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 */
886 struct ATS_ressource_entry
888 /* index in ressources array */
890 /* depending ATSi parameter to calculcate limits */
899 /* index in ressources array */
901 /* depending ATSi parameter to calculcate limits */
903 /* cfg option to load limits */
910 /* cofficients for the specific plugins */
920 static struct ATS_ressource ressources[] =
922 /* FIXME: the coefficients for the specific plugins */
923 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
924 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
925 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
927 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
928 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
929 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
930 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
933 static int available_ressources = 3;
941 * Time of last execution
943 struct GNUNET_TIME_Absolute last;
945 * Minimum intervall between two executions
947 struct GNUNET_TIME_Relative min_delta;
949 * Regular intervall when execution is triggered
951 struct GNUNET_TIME_Relative exec_intervall;
953 * Maximum execution time per calculation
955 struct GNUNET_TIME_Relative max_exec_duration;
957 * Maximum number of LP iterations per calculation
965 * Ressource costs or quality metrics changed, update matrix
967 int modified_resources;
970 * Ressource costs or quality metrics changed, update matrix
972 int modified_quality;
975 * Peers have connected or disconnected, problem has to be recreated
985 GNUNET_SCHEDULER_TaskIdentifier ats_task;
987 struct ATS_result res;
996 static struct GNUNET_HELLO_Message *our_hello;
1001 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1006 static struct GNUNET_PeerIdentity my_identity;
1011 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1014 * Our configuration.
1016 const struct GNUNET_CONFIGURATION_Handle *cfg;
1019 * Linked list of all clients to this service.
1021 static struct TransportClient *clients;
1024 * All loaded plugins.
1026 static struct TransportPlugin *plugins;
1029 * Handle to peerinfo service.
1031 static struct GNUNET_PEERINFO_Handle *peerinfo;
1034 * All known neighbours and their HELLOs.
1036 static struct NeighbourList *neighbours;
1039 * Number of neighbours we'd like to have.
1041 static uint32_t max_connect_per_transport;
1044 * Head of linked list.
1046 static struct CheckHelloValidatedContext *chvc_head;
1049 * Tail of linked list.
1051 static struct CheckHelloValidatedContext *chvc_tail;
1054 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1055 * of the given peer that we are currently validating).
1057 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1060 * Handle for reporting statistics.
1062 static struct GNUNET_STATISTICS_Handle *stats;
1065 * Handle for ats information
1067 static struct ATS_info *ats;
1069 struct ATS_quality_entry
1077 static struct ATS_quality_metric qm[] =
1079 {1, 1028, "QUALITY_NET_DISTANCE"},
1080 {2, 1034, "QUALITY_NET_DELAY"},
1082 static int available_quality_metrics = 2;
1086 * The peer specified by the given neighbour has timed-out or a plugin
1087 * has disconnected. We may either need to do nothing (other plugins
1088 * still up), or trigger a full disconnect and clean up. This
1089 * function updates our state and do the necessary notifications.
1090 * Also notifies our clients that the neighbour is now officially
1093 * @param n the neighbour list entry for the peer
1094 * @param check should we just check if all plugins
1095 * disconnected or must we ask all plugins to
1098 static void disconnect_neighbour (struct NeighbourList *n, int check);
1101 * Check the ready list for the given neighbour and if a plugin is
1102 * ready for transmission (and if we have a message), do so!
1104 * @param nexi target peer for which to transmit
1106 static void try_transmission_to_peer (struct NeighbourList *n);
1111 void ats_shutdown ( );
1113 void ats_notify_peer_connect (
1114 const struct GNUNET_PeerIdentity *peer,
1115 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1117 void ats_notify_peer_disconnect (
1118 const struct GNUNET_PeerIdentity *peer);
1120 void ats_notify_ats_data (
1121 const struct GNUNET_PeerIdentity *peer,
1122 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1124 struct ForeignAddressList * ats_get_preferred_address (
1125 struct NeighbourList *n);
1128 * Find an entry in the neighbour list for a particular peer.
1130 * @return NULL if not found.
1132 static struct NeighbourList *
1133 find_neighbour (const struct GNUNET_PeerIdentity *key)
1135 struct NeighbourList *head = neighbours;
1137 while ((head != NULL) &&
1138 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1143 static void update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1146 for (c1=0; c1<ats_count; c1++)
1148 for (c2=0; c2<available_quality_metrics; c2++)
1150 if (ntohl(ats_data[c1].type) == qm[c2].atis_index)
1152 fal->quality[c2].values[0] = fal->quality[c2].values[1];
1153 fal->quality[c2].values[1] = fal->quality[c2].values[2];
1154 fal->quality[c2].values[2] = ntohl(ats_data[c1].value);
1160 static void update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1163 for (c=0; c<available_quality_metrics; c++)
1165 if (ats_index == qm[c].atis_index)
1167 fal->quality[c].values[0] = fal->quality[c].values[1];
1168 fal->quality[c].values[1] = fal->quality[c].values[2];
1169 fal->quality[c].values[2] = value;
1175 * Find an entry in the transport list for a particular transport.
1177 * @return NULL if not found.
1179 static struct TransportPlugin *
1180 find_transport (const char *short_name)
1182 struct TransportPlugin *head = plugins;
1183 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1189 * Is a particular peer blacklisted for a particular transport?
1191 * @param peer the peer to check for
1192 * @param plugin the plugin used to connect to the peer
1194 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1197 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1200 if (plugin->blacklist != NULL)
1202 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1206 "Peer `%s:%s' is blacklisted!\n",
1207 plugin->short_name, GNUNET_i2s (peer));
1210 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1220 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1222 struct TransportPlugin *plugin;
1224 plugin = find_transport(transport_name);
1225 if (plugin == NULL) /* Nothing to do */
1227 if (plugin->blacklist == NULL)
1228 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1229 GNUNET_assert(plugin->blacklist != NULL);
1230 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1232 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1237 * Read the blacklist file, containing transport:peer entries.
1238 * Provided the transport is loaded, set up hashmap with these
1239 * entries to blacklist peers by transport.
1243 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1250 struct GNUNET_PeerIdentity pid;
1252 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1253 unsigned int entries_found;
1254 char *transport_name;
1257 GNUNET_CONFIGURATION_get_value_filename (cfg,
1263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1264 "Option `%s' in section `%s' not specified!\n",
1270 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1271 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1272 | GNUNET_DISK_PERM_USER_WRITE);
1273 if (0 != STAT (fn, &frstat))
1275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1276 _("Could not read blacklist file `%s'\n"), fn);
1280 if (frstat.st_size == 0)
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284 _("Blacklist file `%s' is empty.\n"),
1290 /* FIXME: use mmap */
1291 data = GNUNET_malloc_large (frstat.st_size);
1292 GNUNET_assert(data != NULL);
1293 if (frstat.st_size !=
1294 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1297 _("Failed to read blacklist from `%s'\n"), fn);
1304 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1306 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1307 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1310 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1313 if (colon_pos >= frstat.st_size)
1315 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1316 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1317 (unsigned long long) colon_pos);
1323 if (isspace( (unsigned char) data[colon_pos]))
1325 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1326 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1327 (unsigned long long) colon_pos);
1329 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1333 tsize = colon_pos - pos;
1334 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1336 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1337 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1338 (unsigned long long) colon_pos);
1347 transport_name = GNUNET_malloc(tsize + 1);
1348 memcpy(transport_name, &data[pos], tsize);
1349 pos = colon_pos + 1;
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1352 "Read transport name %s in blacklist file.\n",
1355 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1356 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1358 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1359 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1360 (unsigned long long) pos);
1362 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1364 GNUNET_free_non_null(transport_name);
1367 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1368 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1371 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1372 (unsigned long long) pos,
1377 if (0 != memcmp (&pid,
1379 sizeof (struct GNUNET_PeerIdentity)))
1382 add_peer_to_blacklist (&pid,
1387 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1388 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1392 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1393 GNUNET_free_non_null(transport_name);
1394 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1397 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1404 * Function called to notify a client about the socket being ready to
1405 * queue more data. "buf" will be NULL and "size" zero if the socket
1406 * was closed for writing in the meantime.
1408 * @param cls closure
1409 * @param size number of bytes available in buf
1410 * @param buf where the callee should write the message
1411 * @return number of bytes written to buf
1414 transmit_to_client_callback (void *cls, size_t size, void *buf)
1416 struct TransportClient *client = cls;
1417 struct ClientMessageQueueEntry *q;
1420 const struct GNUNET_MessageHeader *msg;
1427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1428 "Transmission to client failed, closing connection.\n");
1430 /* fatal error with client, free message queue! */
1431 while (NULL != (q = client->message_queue_head))
1433 GNUNET_STATISTICS_update (stats,
1434 gettext_noop ("# bytes discarded (could not transmit to client)"),
1435 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1437 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1438 client->message_queue_tail,
1442 client->message_count = 0;
1447 while (NULL != (q = client->message_queue_head))
1449 msg = (const struct GNUNET_MessageHeader *) &q[1];
1450 msize = ntohs (msg->size);
1451 if (msize + tsize > size)
1454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1455 "Transmitting message of type %u to client.\n",
1458 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1459 client->message_queue_tail,
1461 memcpy (&cbuf[tsize], msg, msize);
1464 client->message_count--;
1468 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1469 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1471 GNUNET_TIME_UNIT_FOREVER_REL,
1472 &transmit_to_client_callback,
1474 GNUNET_assert (client->th != NULL);
1481 * Convert an address to a string.
1483 * @param plugin name of the plugin responsible for the address
1484 * @param addr binary address
1485 * @param addr_len number of bytes in addr
1486 * @return NULL on error, otherwise address string
1489 a2s (const char *plugin,
1493 struct TransportPlugin *p;
1497 p = find_transport (plugin);
1500 return p->api->address_to_string (p->api->cls,
1507 * Mark the given FAL entry as 'connected' (and hence preferred for
1508 * sending); also mark all others for the same peer as 'not connected'
1509 * (since only one can be preferred).
1511 * @param fal address to set to 'connected'
1514 mark_address_connected (struct ForeignAddressList *fal)
1516 struct ForeignAddressList *pos;
1519 GNUNET_assert (GNUNET_YES == fal->validated);
1520 if (fal->connected == GNUNET_YES)
1521 return; /* nothing to do */
1523 pos = fal->ready_list->addresses;
1526 if (GNUNET_YES == pos->connected)
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1531 a2s (pos->ready_list->plugin->short_name,
1535 GNUNET_break (cnt == GNUNET_YES);
1537 pos->connected = GNUNET_NO;
1538 GNUNET_STATISTICS_update (stats,
1539 gettext_noop ("# connected addresses"),
1545 fal->connected = GNUNET_YES;
1546 if (GNUNET_YES == cnt)
1548 GNUNET_STATISTICS_update (stats,
1549 gettext_noop ("# connected addresses"),
1557 * Send the specified message to the specified client. Since multiple
1558 * messages may be pending for the same client at a time, this code
1559 * makes sure that no message is lost.
1561 * @param client client to transmit the message to
1562 * @param msg the message to send
1563 * @param may_drop can this message be dropped if the
1564 * message queue for this client is getting far too large?
1567 transmit_to_client (struct TransportClient *client,
1568 const struct GNUNET_MessageHeader *msg, int may_drop)
1570 struct ClientMessageQueueEntry *q;
1573 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1575 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1577 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1580 client->message_count,
1582 GNUNET_STATISTICS_update (stats,
1583 gettext_noop ("# messages dropped due to slow client"),
1588 msize = ntohs (msg->size);
1589 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1590 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1591 memcpy (&q[1], msg, msize);
1592 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1593 client->message_queue_tail,
1594 client->message_queue_tail,
1596 client->message_count++;
1597 if (client->th == NULL)
1599 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1601 GNUNET_TIME_UNIT_FOREVER_REL,
1602 &transmit_to_client_callback,
1604 GNUNET_assert (client->th != NULL);
1610 * Transmit a 'SEND_OK' notification to the given client for the
1613 * @param client who to notify
1614 * @param n neighbour to notify about, can be NULL (on failure)
1615 * @param target target of the transmission
1616 * @param result status code for the transmission request
1619 transmit_send_ok (struct TransportClient *client,
1620 struct NeighbourList *n,
1621 const struct GNUNET_PeerIdentity *target,
1624 struct SendOkMessage send_ok_msg;
1626 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1627 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1628 send_ok_msg.success = htonl (result);
1630 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1632 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1633 send_ok_msg.peer = *target;
1634 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1639 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1640 * upon "completion" of a send request. This tells the API
1641 * that it is now legal to send another message to the given
1644 * @param cls closure, identifies the entry on the
1645 * message queue that was transmitted and the
1646 * client responsible for queuing the message
1647 * @param target the peer receiving the message
1648 * @param result GNUNET_OK on success, if the transmission
1649 * failed, we should not tell the client to transmit
1653 transmit_send_continuation (void *cls,
1654 const struct GNUNET_PeerIdentity *target,
1657 struct MessageQueue *mq = cls;
1658 struct NeighbourList *n;
1660 GNUNET_STATISTICS_update (stats,
1661 gettext_noop ("# bytes pending with plugins"),
1662 - (int64_t) mq->message_buf_size,
1664 if (result == GNUNET_OK)
1666 GNUNET_STATISTICS_update (stats,
1667 gettext_noop ("# bytes successfully transmitted by plugins"),
1668 mq->message_buf_size,
1673 GNUNET_STATISTICS_update (stats,
1674 gettext_noop ("# bytes with transmission failure by plugins"),
1675 mq->message_buf_size,
1678 if (mq->specific_address != NULL)
1680 if (result == GNUNET_OK)
1682 mq->specific_address->timeout =
1683 GNUNET_TIME_relative_to_absolute
1684 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1685 if (mq->specific_address->validated == GNUNET_YES)
1686 mark_address_connected (mq->specific_address);
1690 if (mq->specific_address->connected != GNUNET_NO)
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1695 a2s (mq->specific_address->ready_list->plugin->short_name,
1696 mq->specific_address->addr,
1697 mq->specific_address->addrlen));
1699 GNUNET_STATISTICS_update (stats,
1700 gettext_noop ("# connected addresses"),
1703 mq->specific_address->connected = GNUNET_NO;
1706 if (! mq->internal_msg)
1707 mq->specific_address->in_transmit = GNUNET_NO;
1709 n = find_neighbour(&mq->neighbour_id);
1710 if (mq->client != NULL)
1711 transmit_send_ok (mq->client, n, target, result);
1714 try_transmission_to_peer (n);
1719 * Find an address in any of the available transports for
1720 * the given neighbour that would be good for message
1721 * transmission. This is essentially the transport selection
1724 * @param neighbour for whom to select an address
1725 * @return selected address, NULL if we have none
1727 struct ForeignAddressList *
1728 find_ready_address(struct NeighbourList *neighbour)
1730 struct ReadyList *head = neighbour->plugins;
1731 struct ForeignAddressList *addresses;
1732 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1733 struct ForeignAddressList *best_address;
1735 /* Hack to prefer unix domain sockets */
1736 struct ForeignAddressList *unix_address = NULL;
1738 best_address = NULL;
1739 while (head != NULL)
1741 addresses = head->addresses;
1742 while (addresses != NULL)
1744 if ( (addresses->timeout.abs_value < now.abs_value) &&
1745 (addresses->connected == GNUNET_YES) )
1748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1749 "Marking long-time inactive connection to `%4s' as down.\n",
1750 GNUNET_i2s (&neighbour->id));
1752 GNUNET_STATISTICS_update (stats,
1753 gettext_noop ("# connected addresses"),
1756 addresses->connected = GNUNET_NO;
1758 addresses = addresses->next;
1761 addresses = head->addresses;
1762 while (addresses != NULL)
1764 #if DEBUG_TRANSPORT > 1
1765 if (addresses->addr != NULL)
1766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1768 a2s (head->plugin->short_name,
1770 addresses->addrlen),
1771 GNUNET_i2s (&neighbour->id),
1772 addresses->connected,
1773 addresses->in_transmit,
1774 addresses->validated,
1775 addresses->connect_attempts,
1776 (unsigned long long) addresses->timeout.abs_value,
1777 (unsigned int) addresses->distance);
1779 if (0==strcmp(head->plugin->short_name,"unix"))
1781 if ((unix_address == NULL) || ((unix_address != NULL) &&
1782 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1783 unix_address = addresses;
1785 if ( ( (best_address == NULL) ||
1786 (addresses->connected == GNUNET_YES) ||
1787 (best_address->connected == GNUNET_NO) ) &&
1788 (addresses->in_transmit == GNUNET_NO) &&
1789 ( (best_address == NULL) ||
1790 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1791 best_address = addresses;
1792 /* FIXME: also give lower-latency addresses that are not
1793 connected a chance some times... */
1794 addresses = addresses->next;
1796 if (unix_address != NULL)
1800 if (unix_address != NULL)
1802 best_address = unix_address;
1804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1807 if (best_address != NULL)
1811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1812 "Best address found (`%s') has latency of %llu ms.\n",
1813 (best_address->addrlen > 0)
1814 ? a2s (best_address->ready_list->plugin->short_name,
1816 best_address->addrlen)
1818 best_address->latency.rel_value);
1823 GNUNET_STATISTICS_update (stats,
1824 gettext_noop ("# transmission attempts failed (no address)"),
1829 return best_address;
1835 * We should re-try transmitting to the given peer,
1836 * hopefully we've learned something in the meantime.
1839 retry_transmission_task (void *cls,
1840 const struct GNUNET_SCHEDULER_TaskContext *tc)
1842 struct NeighbourList *n = cls;
1844 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1845 try_transmission_to_peer (n);
1850 * Check the ready list for the given neighbour and if a plugin is
1851 * ready for transmission (and if we have a message), do so!
1853 * @param neighbour target peer for which to transmit
1856 try_transmission_to_peer (struct NeighbourList *n)
1858 struct ReadyList *rl;
1859 struct MessageQueue *mq;
1860 struct GNUNET_TIME_Relative timeout;
1864 if (n->messages_head == NULL)
1867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1868 "Transmission queue for `%4s' is empty\n",
1869 GNUNET_i2s (&n->id));
1871 return; /* nothing to do */
1874 mq = n->messages_head;
1875 force_address = GNUNET_YES;
1876 if (mq->specific_address == NULL)
1879 mq->specific_address = ats_get_preferred_address(n);
1880 GNUNET_STATISTICS_update (stats,
1881 gettext_noop ("# transport selected peer address freely"),
1884 force_address = GNUNET_NO;
1886 if (mq->specific_address == NULL)
1888 GNUNET_STATISTICS_update (stats,
1889 gettext_noop ("# transport failed to selected peer address"),
1892 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1893 if (timeout.rel_value == 0)
1896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1897 "No destination address available to transmit message of size %u to peer `%4s'\n",
1898 mq->message_buf_size,
1899 GNUNET_i2s (&mq->neighbour_id));
1901 GNUNET_STATISTICS_update (stats,
1902 gettext_noop ("# bytes in message queue for other peers"),
1903 - (int64_t) mq->message_buf_size,
1905 GNUNET_STATISTICS_update (stats,
1906 gettext_noop ("# bytes discarded (no destination address available)"),
1907 mq->message_buf_size,
1909 if (mq->client != NULL)
1910 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1911 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1915 return; /* nobody ready */
1917 GNUNET_STATISTICS_update (stats,
1918 gettext_noop ("# message delivery deferred (no address)"),
1921 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1922 GNUNET_SCHEDULER_cancel (n->retry_task);
1923 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1924 &retry_transmission_task,
1927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1928 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1929 mq->message_buf_size,
1930 GNUNET_i2s (&mq->neighbour_id),
1933 /* FIXME: might want to trigger peerinfo lookup here
1934 (unless that's already pending...) */
1937 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1940 if (mq->specific_address->connected == GNUNET_NO)
1941 mq->specific_address->connect_attempts++;
1942 rl = mq->specific_address->ready_list;
1943 mq->plugin = rl->plugin;
1944 if (!mq->internal_msg)
1945 mq->specific_address->in_transmit = GNUNET_YES;
1947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1948 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1949 mq->message_buf_size,
1950 GNUNET_i2s (&n->id),
1951 (mq->specific_address->addr != NULL)
1952 ? a2s (mq->plugin->short_name,
1953 mq->specific_address->addr,
1954 mq->specific_address->addrlen)
1956 rl->plugin->short_name);
1958 GNUNET_STATISTICS_update (stats,
1959 gettext_noop ("# bytes in message queue for other peers"),
1960 - (int64_t) mq->message_buf_size,
1962 GNUNET_STATISTICS_update (stats,
1963 gettext_noop ("# bytes pending with plugins"),
1964 mq->message_buf_size,
1966 ret = rl->plugin->api->send (rl->plugin->api->cls,
1969 mq->message_buf_size,
1971 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1972 mq->specific_address->session,
1973 mq->specific_address->addr,
1974 mq->specific_address->addrlen,
1976 &transmit_send_continuation, mq);
1979 /* failure, but 'send' would not call continuation in this case,
1980 so we need to do it here! */
1981 transmit_send_continuation (mq,
1989 * Send the specified message to the specified peer.
1991 * @param client source of the transmission request (can be NULL)
1992 * @param peer_address ForeignAddressList where we should send this message
1993 * @param priority how important is the message
1994 * @param timeout how long do we have to transmit?
1995 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1996 * @param message_buf_size total size of all messages in message_buf
1997 * @param is_internal is this an internal message; these are pre-pended and
1998 * also do not count for plugins being "ready" to transmit
1999 * @param neighbour handle to the neighbour for transmission
2002 transmit_to_peer (struct TransportClient *client,
2003 struct ForeignAddressList *peer_address,
2004 unsigned int priority,
2005 struct GNUNET_TIME_Relative timeout,
2006 const char *message_buf,
2007 size_t message_buf_size,
2008 int is_internal, struct NeighbourList *neighbour)
2010 struct MessageQueue *mq;
2015 /* check for duplicate submission */
2016 mq = neighbour->messages_head;
2019 if (mq->client == client)
2021 /* client transmitted to same peer twice
2022 before getting SEND_OK! */
2030 GNUNET_STATISTICS_update (stats,
2031 gettext_noop ("# bytes in message queue for other peers"),
2034 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2035 mq->specific_address = peer_address;
2036 mq->client = client;
2037 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2038 memcpy (&mq[1], message_buf, message_buf_size);
2039 mq->message_buf = (const char*) &mq[1];
2040 mq->message_buf_size = message_buf_size;
2041 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2042 mq->internal_msg = is_internal;
2043 mq->priority = priority;
2044 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2046 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2047 neighbour->messages_tail,
2050 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2051 neighbour->messages_tail,
2052 neighbour->messages_tail,
2054 try_transmission_to_peer (neighbour);
2061 struct GeneratorContext
2063 struct TransportPlugin *plug_pos;
2064 struct OwnAddressList *addr_pos;
2065 struct GNUNET_TIME_Absolute expiration;
2073 address_generator (void *cls, size_t max, void *buf)
2075 struct GeneratorContext *gc = cls;
2078 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2080 gc->plug_pos = gc->plug_pos->next;
2081 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2083 if (NULL == gc->plug_pos)
2088 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2091 gc->addr_pos->addrlen, buf, max);
2092 gc->addr_pos = gc->addr_pos->next;
2098 * Construct our HELLO message from all of the addresses of
2099 * all of the transports.
2104 struct GNUNET_HELLO_Message *hello;
2105 struct TransportClient *cpos;
2106 struct NeighbourList *npos;
2107 struct GeneratorContext gc;
2109 gc.plug_pos = plugins;
2110 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2111 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2112 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2115 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2117 GNUNET_STATISTICS_update (stats,
2118 gettext_noop ("# refreshed my HELLO"),
2122 while (cpos != NULL)
2124 transmit_to_client (cpos,
2125 (const struct GNUNET_MessageHeader *) hello,
2130 GNUNET_free_non_null (our_hello);
2132 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2134 while (npos != NULL)
2137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2138 "Transmitting updated `%s' to neighbour `%4s'\n",
2139 "HELLO", GNUNET_i2s (&npos->id));
2141 GNUNET_STATISTICS_update (stats,
2142 gettext_noop ("# transmitted my HELLO to other peers"),
2145 transmit_to_peer (NULL, NULL, 0,
2146 HELLO_ADDRESS_EXPIRATION,
2147 (const char *) our_hello,
2148 GNUNET_HELLO_size(our_hello),
2156 * Task used to clean up expired addresses for a plugin.
2158 * @param cls closure
2162 expire_address_task (void *cls,
2163 const struct GNUNET_SCHEDULER_TaskContext *tc);
2167 * Update the list of addresses for this plugin,
2168 * expiring those that are past their expiration date.
2170 * @param plugin addresses of which plugin should be recomputed?
2171 * @param fresh set to GNUNET_YES if a new address was added
2172 * and we need to regenerate the HELLO even if nobody
2176 update_addresses (struct TransportPlugin *plugin,
2179 static struct GNUNET_TIME_Absolute last_update;
2180 struct GNUNET_TIME_Relative min_remaining;
2181 struct GNUNET_TIME_Relative remaining;
2182 struct GNUNET_TIME_Absolute now;
2183 struct OwnAddressList *pos;
2184 struct OwnAddressList *prev;
2185 struct OwnAddressList *next;
2188 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2189 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2190 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2191 now = GNUNET_TIME_absolute_get ();
2192 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2193 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2195 pos = plugin->addresses;
2199 if (pos->expires.abs_value < now.abs_value)
2201 expired = GNUNET_YES;
2203 plugin->addresses = pos->next;
2205 prev->next = pos->next;
2210 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2211 if (remaining.rel_value < min_remaining.rel_value)
2212 min_remaining = remaining;
2218 if (expired || fresh)
2223 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2224 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2226 plugin->address_update_task
2227 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2228 &expire_address_task, plugin);
2233 * Task used to clean up expired addresses for a plugin.
2235 * @param cls closure
2239 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2241 struct TransportPlugin *plugin = cls;
2243 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2244 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2245 update_addresses (plugin, GNUNET_NO);
2250 * Iterator over hash map entries that NULLs the session of validation
2251 * entries that match the given session.
2253 * @param cls closure (the 'struct Session*' to match against)
2254 * @param key current key code (peer ID, not used)
2255 * @param value value in the hash map ('struct ValidationEntry*')
2256 * @return GNUNET_YES (we should continue to iterate)
2259 remove_session_validations (void *cls,
2260 const GNUNET_HashCode * key,
2263 struct Session *session = cls;
2264 struct ValidationEntry *ve = value;
2266 if (session == ve->session)
2273 * We've been disconnected from the other peer (for some
2274 * connection-oriented transport). Either quickly
2275 * re-establish the connection or signal the disconnect
2278 * Only signal CORE level disconnect if ALL addresses
2279 * for the peer are exhausted.
2281 * @param p overall plugin context
2282 * @param nl neighbour that was disconnected
2285 try_fast_reconnect (struct TransportPlugin *p,
2286 struct NeighbourList *nl)
2288 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2289 /* Note: the idea here is to hide problems with transports (or
2290 switching between plugins) from the core to eliminate the need to
2291 re-negotiate session keys and the like; OTOH, we should tell core
2292 quickly (much faster than timeout) `if a connection was lost and
2293 could not be re-established (i.e. other peer went down or is
2294 unable / refuses to communicate);
2296 So we should consider:
2297 1) ideally: our own willingness / need to connect
2298 2) prior failures to connect to this peer (by plugin)
2299 3) ideally: reasons why other peer terminated (as far as knowable)
2301 Most importantly, it must be POSSIBLE for another peer to terminate
2302 a connection for a while (without us instantly re-establishing it).
2303 Similarly, if another peer is gone we should quickly notify CORE.
2304 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2305 on the other end), we should reconnect in such a way that BOTH CORE
2306 services never even notice.
2307 Furthermore, the same mechanism (or small variation) could be used
2308 to switch to a better-performing plugin (ATS).
2310 Finally, this needs to be tested throughly... */
2313 * GNUNET_NO in the call below makes transport disconnect the peer,
2314 * even if only a single address (out of say, six) went away. This
2315 * function must be careful to ONLY disconnect if the peer is gone,
2316 * not just a specifi address.
2318 * More specifically, half the places it was used had it WRONG.
2321 /* No reconnect, signal disconnect instead! */
2322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2323 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2324 "try_fast_reconnect");
2325 disconnect_neighbour (nl, GNUNET_YES);
2330 * Function that will be called whenever the plugin internally
2331 * cleans up a session pointer and hence the service needs to
2332 * discard all of those sessions as well. Plugins that do not
2333 * use sessions can simply omit calling this function and always
2334 * use NULL wherever a session pointer is needed.
2336 * @param cls closure
2337 * @param peer which peer was the session for
2338 * @param session which session is being destoyed
2341 plugin_env_session_end (void *cls,
2342 const struct GNUNET_PeerIdentity *peer,
2343 struct Session *session)
2345 struct TransportPlugin *p = cls;
2346 struct NeighbourList *nl;
2347 struct ReadyList *rl;
2348 struct ForeignAddressList *pos;
2349 struct ForeignAddressList *prev;
2351 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2352 &remove_session_validations,
2354 nl = find_neighbour (peer);
2356 return; /* was never marked as connected */
2360 if (rl->plugin == p)
2365 return; /* was never marked as connected */
2367 pos = rl->addresses;
2368 while ( (pos != NULL) &&
2369 (pos->session != session) )
2375 return; /* was never marked as connected */
2376 pos->session = NULL;
2377 if (pos->addrlen != 0)
2379 if (nl->received_pong != GNUNET_NO)
2380 try_fast_reconnect (p, nl);
2383 /* was inbound connection, free 'pos' */
2385 rl->addresses = pos->next;
2387 prev->next = pos->next;
2388 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2390 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2391 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2394 if (nl->received_pong == GNUNET_NO)
2395 return; /* nothing to do, never connected... */
2396 /* check if we have any validated addresses left */
2397 pos = rl->addresses;
2402 try_fast_reconnect (p, nl);
2407 /* no valid addresses left, signal disconnect! */
2409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2410 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2411 "plugin_env_session_end");
2412 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2413 * it means there aren't any left for this PLUGIN/PEER combination! So
2414 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2415 * when it isn't necessary. Using GNUNET_YES at least checks to see
2416 * if there are any addresses that work first, so as not to overdo it.
2419 disconnect_neighbour (nl, GNUNET_YES);
2424 * Function that must be called by each plugin to notify the
2425 * transport service about the addresses under which the transport
2426 * provided by the plugin can be reached.
2428 * @param cls closure
2429 * @param name name of the transport that generated the address
2430 * @param addr one of the addresses of the host, NULL for the last address
2431 * the specific address format depends on the transport
2432 * @param addrlen length of the address
2433 * @param expires when should this address automatically expire?
2436 plugin_env_notify_address (void *cls,
2440 struct GNUNET_TIME_Relative expires)
2442 struct TransportPlugin *p = cls;
2443 struct OwnAddressList *al;
2444 struct GNUNET_TIME_Absolute abex;
2446 GNUNET_assert (addr != NULL);
2447 abex = GNUNET_TIME_relative_to_absolute (expires);
2448 GNUNET_assert (p == find_transport (name));
2452 if ( (addrlen == al->addrlen) &&
2453 (0 == memcmp (addr, &al[1], addrlen)) )
2456 update_addresses (p, GNUNET_NO);
2461 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2462 al->next = p->addresses;
2465 al->addrlen = addrlen;
2466 memcpy (&al[1], addr, addrlen);
2467 update_addresses (p, GNUNET_YES);
2472 * Notify all of our clients about a peer connecting.
2475 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2476 struct GNUNET_TIME_Relative latency,
2479 struct ConnectInfoMessage * cim;
2480 struct TransportClient *cpos;
2485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2486 "Notifying clients about connection from `%s'\n",
2489 GNUNET_STATISTICS_update (stats,
2490 gettext_noop ("# peers connected"),
2495 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2496 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2500 cim = GNUNET_malloc (size);
2502 cim->header.size = htons (size);
2503 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2504 cim->ats_count = htonl(2);
2505 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2506 (&(cim->ats))[0].value = htonl (distance);
2507 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2508 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2509 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2510 (&(cim->ats))[2].value = htonl (0);
2511 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2513 /* notify ats about connecting peer */
2514 ats_notify_peer_connect (peer, &(cim->ats));
2517 while (cpos != NULL)
2519 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2528 * Notify all of our clients about a peer disconnecting.
2531 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2533 struct DisconnectInfoMessage dim;
2534 struct TransportClient *cpos;
2537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2538 "Notifying clients about lost connection to `%s'\n",
2541 GNUNET_STATISTICS_update (stats,
2542 gettext_noop ("# peers connected"),
2545 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2546 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2547 dim.reserved = htonl (0);
2548 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2550 /* notify ats about connecting peer */
2551 ats_notify_peer_disconnect (peer);
2554 while (cpos != NULL)
2556 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2563 * Find a ForeignAddressList entry for the given neighbour
2564 * that matches the given address and transport.
2566 * @param neighbour which peer we care about
2567 * @param tname name of the transport plugin
2568 * @param session session to look for, NULL for 'any'; otherwise
2569 * can be used for the service to "learn" this session ID
2571 * @param addr binary address
2572 * @param addrlen length of addr
2573 * @return NULL if no such entry exists
2575 static struct ForeignAddressList *
2576 find_peer_address(struct NeighbourList *neighbour,
2578 struct Session *session,
2582 struct ReadyList *head;
2583 struct ForeignAddressList *pos;
2585 head = neighbour->plugins;
2586 while (head != NULL)
2588 if (0 == strcmp (tname, head->plugin->short_name))
2594 pos = head->addresses;
2595 while ( (pos != NULL) &&
2596 ( (pos->addrlen != addrlen) ||
2597 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2599 if ( (session != NULL) &&
2600 (pos->session == session) )
2604 if ( (session != NULL) && (pos != NULL) )
2605 pos->session = session; /* learn it! */
2611 * Get the peer address struct for the given neighbour and
2612 * address. If it doesn't yet exist, create it.
2614 * @param neighbour which peer we care about
2615 * @param tname name of the transport plugin
2616 * @param session session of the plugin, or NULL for none
2617 * @param addr binary address
2618 * @param addrlen length of addr
2619 * @return NULL if we do not have a transport plugin for 'tname'
2621 static struct ForeignAddressList *
2622 add_peer_address (struct NeighbourList *neighbour,
2624 struct Session *session,
2628 struct ReadyList *head;
2629 struct ForeignAddressList *ret;
2632 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2635 head = neighbour->plugins;
2637 while (head != NULL)
2639 if (0 == strcmp (tname, head->plugin->short_name))
2645 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2646 ret->session = session;
2647 if ((addrlen > 0) && (addr != NULL))
2649 ret->addr = (const char*) &ret[1];
2650 memcpy (&ret[1], addr, addrlen);
2657 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2659 for (c=0; c<available_ressources; c++)
2661 struct ATS_ressource_entry *r = ret->ressources;
2663 r[c].atis_index = ressources[c].atis_index;
2664 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2666 r[c].c = ressources[c].c_unix;
2669 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2671 r[c].c = ressources[c].c_udp;
2674 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2676 r[c].c = ressources[c].c_tcp;
2679 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2681 r[c].c = ressources[c].c_http;
2684 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2686 r[c].c = ressources[c].c_https;
2689 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2691 r[c].c = ressources[c].c_wlan;
2697 r[c].c = ressources[c].c_default;
2698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2699 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2703 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2704 ret->addrlen = addrlen;
2705 ret->expires = GNUNET_TIME_relative_to_absolute
2706 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2707 ret->latency = GNUNET_TIME_relative_get_forever();
2709 ret->timeout = GNUNET_TIME_relative_to_absolute
2710 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2711 ret->ready_list = head;
2712 ret->next = head->addresses;
2713 head->addresses = ret;
2719 * Closure for 'add_validated_address'.
2721 struct AddValidatedAddressContext
2724 * Entry that has been validated.
2726 const struct ValidationEntry *ve;
2729 * Flag set after we have added the address so
2730 * that we terminate the iteration next time.
2737 * Callback function used to fill a buffer of max bytes with a list of
2738 * addresses in the format used by HELLOs. Should use
2739 * "GNUNET_HELLO_add_address" as a helper function.
2741 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2742 * @param max maximum number of bytes that can be written to buf
2743 * @param buf where to write the address information
2744 * @return number of bytes written, 0 to signal the
2745 * end of the iteration.
2748 add_validated_address (void *cls,
2749 size_t max, void *buf)
2751 struct AddValidatedAddressContext *avac = cls;
2752 const struct ValidationEntry *ve = avac->ve;
2754 if (GNUNET_YES == avac->done)
2756 avac->done = GNUNET_YES;
2757 return GNUNET_HELLO_add_address (ve->transport_name,
2758 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2768 * Closure for 'check_address_exists'.
2770 struct CheckAddressExistsClosure
2773 * Address to check for.
2778 * Name of the transport.
2785 struct Session *session;
2788 * Set to GNUNET_YES if the address exists.
2801 * Iterator over hash map entries. Checks if the given
2802 * validation entry is for the same address as what is given
2805 * @param cls the 'struct CheckAddressExistsClosure*'
2806 * @param key current key code (ignored)
2807 * @param value value in the hash map ('struct ValidationEntry')
2808 * @return GNUNET_YES if we should continue to
2809 * iterate (mismatch), GNUNET_NO if not (entry matched)
2812 check_address_exists (void *cls,
2813 const GNUNET_HashCode * key,
2816 struct CheckAddressExistsClosure *caec = cls;
2817 struct ValidationEntry *ve = value;
2819 if ( (0 == strcmp (caec->tname,
2820 ve->transport_name)) &&
2821 (caec->addrlen == ve->addrlen) &&
2822 (0 == memcmp (caec->addr,
2826 caec->exists = GNUNET_YES;
2829 if ( (ve->session != NULL) &&
2830 (caec->session == ve->session) )
2832 caec->exists = GNUNET_YES;
2841 * Iterator to free entries in the validation_map.
2843 * @param cls closure (unused)
2844 * @param key current key code
2845 * @param value value in the hash map (validation to abort)
2846 * @return GNUNET_YES (always)
2849 abort_validation (void *cls,
2850 const GNUNET_HashCode * key,
2853 struct ValidationEntry *va = value;
2855 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2856 GNUNET_SCHEDULER_cancel (va->timeout_task);
2857 GNUNET_free (va->transport_name);
2858 if (va->chvc != NULL)
2860 va->chvc->ve_count--;
2861 if (va->chvc->ve_count == 0)
2863 GNUNET_CONTAINER_DLL_remove (chvc_head,
2866 GNUNET_free (va->chvc);
2876 * HELLO validation cleanup task (validation failed).
2878 * @param cls the 'struct ValidationEntry' that failed
2879 * @param tc scheduler context (unused)
2882 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2884 struct ValidationEntry *va = cls;
2885 struct GNUNET_PeerIdentity pid;
2887 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2888 GNUNET_STATISTICS_update (stats,
2889 gettext_noop ("# address validation timeouts"),
2892 GNUNET_CRYPTO_hash (&va->publicKey,
2894 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2896 GNUNET_break (GNUNET_OK ==
2897 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2900 abort_validation (NULL, NULL, va);
2905 neighbour_timeout_task (void *cls,
2906 const struct GNUNET_SCHEDULER_TaskContext *tc)
2908 struct NeighbourList *n = cls;
2911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2912 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2914 GNUNET_STATISTICS_update (stats,
2915 gettext_noop ("# disconnects due to timeout"),
2918 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2919 disconnect_neighbour (n, GNUNET_NO);
2924 * Schedule the job that will cause us to send a PING to the
2925 * foreign address to evaluate its validity and latency.
2927 * @param fal address to PING
2930 schedule_next_ping (struct ForeignAddressList *fal);
2934 * Add the given address to the list of foreign addresses
2935 * available for the given peer (check for duplicates).
2937 * @param cls the respective 'struct NeighbourList' to update
2938 * @param tname name of the transport
2939 * @param expiration expiration time
2940 * @param addr the address
2941 * @param addrlen length of the address
2942 * @return GNUNET_OK (always)
2945 add_to_foreign_address_list (void *cls,
2947 struct GNUNET_TIME_Absolute expiration,
2951 struct NeighbourList *n = cls;
2952 struct ForeignAddressList *fal;
2955 GNUNET_STATISTICS_update (stats,
2956 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2960 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2963 #if DEBUG_TRANSPORT_HELLO
2964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2965 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2966 a2s (tname, addr, addrlen),
2968 GNUNET_i2s (&n->id),
2969 expiration.abs_value);
2971 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2974 GNUNET_STATISTICS_update (stats,
2975 gettext_noop ("# previously validated addresses lacking transport"),
2981 fal->expires = GNUNET_TIME_absolute_max (expiration,
2983 schedule_next_ping (fal);
2989 fal->expires = GNUNET_TIME_absolute_max (expiration,
2994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2995 "Failed to add new address for `%4s'\n",
2996 GNUNET_i2s (&n->id));
2999 if (fal->validated == GNUNET_NO)
3001 fal->validated = GNUNET_YES;
3002 GNUNET_STATISTICS_update (stats,
3003 gettext_noop ("# peer addresses considered valid"),
3007 if (try == GNUNET_YES)
3009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3010 "Have new addresses, will try to trigger transmissions.\n");
3011 try_transmission_to_peer (n);
3018 * Add addresses in validated HELLO "h" to the set of addresses
3019 * we have for this peer.
3021 * @param cls closure ('struct NeighbourList*')
3022 * @param peer id of the peer, NULL for last call
3023 * @param h hello message for the peer (can be NULL)
3024 * @param err_msg NULL if successful, otherwise contains error message
3027 add_hello_for_peer (void *cls,
3028 const struct GNUNET_PeerIdentity *peer,
3029 const struct GNUNET_HELLO_Message *h,
3030 const char *err_msg)
3032 struct NeighbourList *n = cls;
3034 if (err_msg != NULL)
3036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3037 _("Error in communication with PEERINFO service\n"));
3042 GNUNET_STATISTICS_update (stats,
3043 gettext_noop ("# outstanding peerinfo iterate requests"),
3050 return; /* no HELLO available */
3052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3053 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3057 if (GNUNET_YES != n->public_key_valid)
3059 GNUNET_HELLO_get_key (h, &n->publicKey);
3060 n->public_key_valid = GNUNET_YES;
3062 GNUNET_HELLO_iterate_addresses (h,
3064 &add_to_foreign_address_list,
3070 * Create a fresh entry in our neighbour list for the given peer.
3071 * Will try to transmit our current HELLO to the new neighbour.
3072 * Do not call this function directly, use 'setup_peer_check_blacklist.
3074 * @param peer the peer for which we create the entry
3075 * @param do_hello should we schedule transmitting a HELLO
3076 * @return the new neighbour list entry
3078 static struct NeighbourList *
3079 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3082 struct NeighbourList *n;
3083 struct TransportPlugin *tp;
3084 struct ReadyList *rl;
3087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3088 "Setting up state for neighbour `%4s'\n",
3091 GNUNET_assert (our_hello != NULL);
3092 GNUNET_STATISTICS_update (stats,
3093 gettext_noop ("# active neighbours"),
3096 n = GNUNET_malloc (sizeof (struct NeighbourList));
3097 n->next = neighbours;
3101 GNUNET_TIME_relative_to_absolute
3102 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3103 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3104 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3105 MAX_BANDWIDTH_CARRY_S);
3109 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3111 rl = GNUNET_malloc (sizeof (struct ReadyList));
3113 rl->next = n->plugins;
3116 rl->addresses = NULL;
3120 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3122 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3123 &neighbour_timeout_task, n);
3126 GNUNET_STATISTICS_update (stats,
3127 gettext_noop ("# peerinfo new neighbor iterate requests"),
3130 GNUNET_STATISTICS_update (stats,
3131 gettext_noop ("# outstanding peerinfo iterate requests"),
3134 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3135 GNUNET_TIME_UNIT_FOREVER_REL,
3136 &add_hello_for_peer, n);
3138 GNUNET_STATISTICS_update (stats,
3139 gettext_noop ("# HELLO's sent to new neighbors"),
3142 transmit_to_peer (NULL, NULL, 0,
3143 HELLO_ADDRESS_EXPIRATION,
3144 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3152 * Function called after we have checked if communicating
3153 * with a given peer is acceptable.
3155 * @param cls closure
3156 * @param n NULL if communication is not acceptable
3158 typedef void (*SetupContinuation)(void *cls,
3159 struct NeighbourList *n);
3163 * Information kept for each client registered to perform
3169 * This is a linked list.
3171 struct Blacklisters *next;
3174 * This is a linked list.
3176 struct Blacklisters *prev;
3179 * Client responsible for this entry.
3181 struct GNUNET_SERVER_Client *client;
3184 * Blacklist check that we're currently performing.
3186 struct BlacklistCheck *bc;
3192 * Head of DLL of blacklisting clients.
3194 static struct Blacklisters *bl_head;
3197 * Tail of DLL of blacklisting clients.
3199 static struct Blacklisters *bl_tail;
3203 * Context we use when performing a blacklist check.
3205 struct BlacklistCheck
3209 * This is a linked list.
3211 struct BlacklistCheck *next;
3214 * This is a linked list.
3216 struct BlacklistCheck *prev;
3219 * Peer being checked.
3221 struct GNUNET_PeerIdentity peer;
3224 * Option for setup neighbour afterwards.
3229 * Continuation to call with the result.
3231 SetupContinuation cont;
3239 * Current transmission request handle for this client, or NULL if no
3240 * request is pending.
3242 struct GNUNET_CONNECTION_TransmitHandle *th;
3245 * Our current position in the blacklisters list.
3247 struct Blacklisters *bl_pos;
3250 * Current task performing the check.
3252 GNUNET_SCHEDULER_TaskIdentifier task;
3257 * Head of DLL of active blacklisting queries.
3259 static struct BlacklistCheck *bc_head;
3262 * Tail of DLL of active blacklisting queries.
3264 static struct BlacklistCheck *bc_tail;
3268 * Perform next action in the blacklist check.
3270 * @param cls the 'struct BlacklistCheck*'
3274 do_blacklist_check (void *cls,
3275 const struct GNUNET_SCHEDULER_TaskContext *tc);
3278 * Transmit blacklist query to the client.
3280 * @param cls the 'struct BlacklistCheck'
3281 * @param size number of bytes allowed
3282 * @param buf where to copy the message
3283 * @return number of bytes copied to buf
3286 transmit_blacklist_message (void *cls,
3290 struct BlacklistCheck *bc = cls;
3291 struct Blacklisters *bl;
3292 struct BlacklistMessage bm;
3297 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3298 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3303 bm.header.size = htons (sizeof (struct BlacklistMessage));
3304 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3305 bm.is_allowed = htonl (0);
3307 memcpy (buf, &bm, sizeof (bm));
3308 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3314 * Perform next action in the blacklist check.
3316 * @param cls the 'struct BlacklistCheck*'
3320 do_blacklist_check (void *cls,
3321 const struct GNUNET_SCHEDULER_TaskContext *tc)
3323 struct BlacklistCheck *bc = cls;
3324 struct Blacklisters *bl;
3326 bc->task = GNUNET_SCHEDULER_NO_TASK;
3330 bc->cont (bc->cont_cls,
3331 setup_new_neighbour (&bc->peer, bc->do_hello));
3338 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3339 sizeof (struct BlacklistMessage),
3340 GNUNET_TIME_UNIT_FOREVER_REL,
3341 &transmit_blacklist_message,
3348 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3349 * does not yet exist, check the blacklist. If the blacklist says creating
3350 * one is acceptable, create one and call the continuation; otherwise
3351 * call the continuation with NULL.
3353 * @param peer peer to setup or look up a struct NeighbourList for
3354 * @param do_hello should we also schedule sending our HELLO to the peer
3355 * if this is a new record
3356 * @param cont function to call with the 'struct NeigbhbourList*'
3357 * @param cont_cls closure for cont
3360 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3362 SetupContinuation cont,
3365 struct NeighbourList *n;
3366 struct BlacklistCheck *bc;
3368 n = find_neighbour(peer);
3375 if (bl_head == NULL)
3378 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3380 setup_new_neighbour(peer, do_hello);
3383 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3384 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3386 bc->do_hello = do_hello;
3388 bc->cont_cls = cont_cls;
3389 bc->bl_pos = bl_head;
3390 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3396 * Function called with the result of querying a new blacklister about
3397 * it being allowed (or not) to continue to talk to an existing neighbour.
3399 * @param cls the original 'struct NeighbourList'
3400 * @param n NULL if we need to disconnect
3403 confirm_or_drop_neighbour (void *cls,
3404 struct NeighbourList *n)
3406 struct NeighbourList * orig = cls;
3410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3411 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3412 "confirm_or_drop_neighboUr");
3413 disconnect_neighbour (orig, GNUNET_NO);
3419 * Handle a request to start a blacklist.
3421 * @param cls closure (always NULL)
3422 * @param client identification of the client
3423 * @param message the actual message
3426 handle_blacklist_init (void *cls,
3427 struct GNUNET_SERVER_Client *client,
3428 const struct GNUNET_MessageHeader *message)
3430 struct Blacklisters *bl;
3431 struct BlacklistCheck *bc;
3432 struct NeighbourList *n;
3437 if (bl->client == client)
3440 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3445 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3446 bl->client = client;
3447 GNUNET_SERVER_client_keep (client);
3448 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3449 /* confirm that all existing connections are OK! */
3453 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3454 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3456 bc->do_hello = GNUNET_NO;
3457 bc->cont = &confirm_or_drop_neighbour;
3460 if (n == neighbours) /* all would wait for the same client, no need to
3461 create more than just the first task right now */
3462 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3470 * Handle a request to blacklist a peer.
3472 * @param cls closure (always NULL)
3473 * @param client identification of the client
3474 * @param message the actual message
3477 handle_blacklist_reply (void *cls,
3478 struct GNUNET_SERVER_Client *client,
3479 const struct GNUNET_MessageHeader *message)
3481 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3482 struct Blacklisters *bl;
3483 struct BlacklistCheck *bc;
3486 while ( (bl != NULL) &&
3487 (bl->client != client) )
3491 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3496 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3498 bc->cont (bc->cont_cls, NULL);
3499 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3504 bc->bl_pos = bc->bl_pos->next;
3505 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3508 /* check if any other bc's are waiting for this blacklister */
3512 if ( (bc->bl_pos == bl) &&
3513 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3514 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3522 * Send periodic PING messages to a given foreign address.
3524 * @param cls our 'struct PeriodicValidationContext*'
3525 * @param tc task context
3528 send_periodic_ping (void *cls,
3529 const struct GNUNET_SCHEDULER_TaskContext *tc)
3531 struct ForeignAddressList *peer_address = cls;
3532 struct TransportPlugin *tp;
3533 struct ValidationEntry *va;
3534 struct NeighbourList *neighbour;
3535 struct TransportPingMessage ping;
3536 struct CheckAddressExistsClosure caec;
3538 uint16_t hello_size;
3542 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3543 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3545 tp = peer_address->ready_list->plugin;
3546 neighbour = peer_address->ready_list->neighbour;
3547 if (GNUNET_YES != neighbour->public_key_valid)
3549 /* no public key yet, try again later */
3550 schedule_next_ping (peer_address);
3553 caec.addr = peer_address->addr;
3554 caec.addrlen = peer_address->addrlen;
3555 caec.tname = tp->short_name;
3556 caec.session = peer_address->session;
3557 caec.exists = GNUNET_NO;
3558 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3559 &check_address_exists,
3561 if (caec.exists == GNUNET_YES)
3563 /* During validation attempts we will likely trigger the other
3564 peer trying to validate our address which in turn will cause
3565 it to send us its HELLO, so we expect to hit this case rather
3566 frequently. Only print something if we are very verbose. */
3567 #if DEBUG_TRANSPORT > 1
3568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3569 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3570 (peer_address->addr != NULL)
3571 ? a2s (tp->short_name,
3573 peer_address->addrlen)
3576 GNUNET_i2s (&neighbour->id));
3578 schedule_next_ping (peer_address);
3581 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3582 va->transport_name = GNUNET_strdup (tp->short_name);
3583 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3585 va->send_time = GNUNET_TIME_absolute_get();
3586 va->session = peer_address->session;
3587 if (peer_address->addr != NULL)
3589 va->addr = (const void*) &va[1];
3590 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3591 va->addrlen = peer_address->addrlen;
3593 memcpy(&va->publicKey,
3594 &neighbour->publicKey,
3595 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3597 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3598 &timeout_hello_validation,
3600 GNUNET_CONTAINER_multihashmap_put (validation_map,
3601 &neighbour->id.hashPubKey,
3603 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3605 if (peer_address->validated != GNUNET_YES)
3606 hello_size = GNUNET_HELLO_size(our_hello);
3610 tsize = sizeof(struct TransportPingMessage) + hello_size;
3612 if (peer_address->addr != NULL)
3614 slen = strlen (tp->short_name) + 1;
3615 tsize += slen + peer_address->addrlen;
3619 slen = 0; /* make gcc happy */
3621 message_buf = GNUNET_malloc(tsize);
3622 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3623 ping.challenge = htonl(va->challenge);
3624 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3625 if (peer_address->validated != GNUNET_YES)
3627 memcpy(message_buf, our_hello, hello_size);
3630 if (peer_address->addr != NULL)
3632 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3633 peer_address->addrlen +
3635 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3638 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3640 peer_address->addrlen);
3644 ping.header.size = htons(sizeof(struct TransportPingMessage));
3647 memcpy(&message_buf[hello_size],
3649 sizeof(struct TransportPingMessage));
3651 #if DEBUG_TRANSPORT_REVALIDATION
3652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3653 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3654 (peer_address->addr != NULL)
3655 ? a2s (peer_address->plugin->short_name,
3657 peer_address->addrlen)
3660 GNUNET_i2s (&neighbour->id),
3661 "HELLO", hello_size,
3664 if (peer_address->validated != GNUNET_YES)
3665 GNUNET_STATISTICS_update (stats,
3666 gettext_noop ("# PING with HELLO messages sent"),
3670 GNUNET_STATISTICS_update (stats,
3671 gettext_noop ("# PING without HELLO messages sent"),
3674 GNUNET_STATISTICS_update (stats,
3675 gettext_noop ("# PING messages sent for re-validation"),
3678 transmit_to_peer (NULL, peer_address,
3679 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3680 HELLO_VERIFICATION_TIMEOUT,
3682 GNUNET_YES, neighbour);
3683 GNUNET_free(message_buf);
3684 schedule_next_ping (peer_address);
3689 * Schedule the job that will cause us to send a PING to the
3690 * foreign address to evaluate its validity and latency.
3692 * @param fal address to PING
3695 schedule_next_ping (struct ForeignAddressList *fal)
3697 struct GNUNET_TIME_Relative delay;
3699 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3701 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3702 delay.rel_value /= 2; /* do before expiration */
3703 delay = GNUNET_TIME_relative_min (delay,
3704 LATENCY_EVALUATION_MAX_DELAY);
3705 if (GNUNET_YES != fal->estimated)
3707 delay = GNUNET_TIME_UNIT_ZERO;
3708 fal->estimated = GNUNET_YES;
3710 if (GNUNET_YES == fal->connected)
3712 delay = GNUNET_TIME_relative_min (delay,
3713 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3715 /* FIXME: also adjust delay based on how close the last
3716 observed latency is to the latency of the best alternative */
3717 /* bound how fast we can go */
3718 delay = GNUNET_TIME_relative_max (delay,
3719 GNUNET_TIME_UNIT_SECONDS);
3720 /* randomize a bit (to avoid doing all at the same time) */
3721 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3722 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3723 &send_periodic_ping,
3731 * Function that will be called if we receive some payload
3732 * from another peer.
3734 * @param message the payload
3735 * @param n peer who claimed to be the sender
3738 handle_payload_message (const struct GNUNET_MessageHeader *message,
3739 struct NeighbourList *n)
3741 struct InboundMessage *im;
3742 struct TransportClient *cpos;
3745 msize = ntohs (message->size);
3746 if (n->received_pong == GNUNET_NO)
3748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3749 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3750 ntohs (message->type),
3751 ntohs (message->size),
3752 GNUNET_i2s (&n->id));
3753 GNUNET_free_non_null (n->pre_connect_message_buffer);
3754 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3755 memcpy (n->pre_connect_message_buffer, message, msize);
3760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3761 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3762 ntohs (message->type),
3763 ntohs (message->size),
3764 GNUNET_i2s (&n->id));
3766 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3769 n->quota_violation_count++;
3771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3772 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3773 n->in_tracker.available_bytes_per_s__,
3774 n->quota_violation_count);
3776 /* Discount 32k per violation */
3777 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3782 if (n->quota_violation_count > 0)
3784 /* try to add 32k back */
3785 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3787 n->quota_violation_count--;
3790 GNUNET_STATISTICS_update (stats,
3791 gettext_noop ("# payload received from other peers"),
3794 /* transmit message to all clients */
3795 uint32_t ats_count = 2;
3796 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3797 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3800 im = GNUNET_malloc (size);
3801 im->header.size = htons (size);
3802 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3804 im->ats_count = htonl(ats_count);
3805 /* Setting ATS data */
3806 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3807 (&(im->ats))[0].value = htonl (n->distance);
3808 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3809 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3810 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3811 (&(im->ats))[ats_count].value = htonl (0);
3813 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3815 while (cpos != NULL)
3817 transmit_to_client (cpos, &im->header, GNUNET_YES);
3825 * Iterator over hash map entries. Checks if the given validation
3826 * entry is for the same challenge as what is given in the PONG.
3828 * @param cls the 'struct TransportPongMessage*'
3829 * @param key peer identity
3830 * @param value value in the hash map ('struct ValidationEntry')
3831 * @return GNUNET_YES if we should continue to
3832 * iterate (mismatch), GNUNET_NO if not (entry matched)
3835 check_pending_validation (void *cls,
3836 const GNUNET_HashCode * key,
3839 const struct TransportPongMessage *pong = cls;
3840 struct ValidationEntry *ve = value;
3841 struct AddValidatedAddressContext avac;
3842 unsigned int challenge = ntohl(pong->challenge);
3843 struct GNUNET_HELLO_Message *hello;
3844 struct GNUNET_PeerIdentity target;
3845 struct NeighbourList *n;
3846 struct ForeignAddressList *fal;
3847 struct OwnAddressList *oal;
3848 struct TransportPlugin *tp;
3849 struct GNUNET_MessageHeader *prem;
3855 ps = ntohs (pong->header.size);
3856 if (ps < sizeof (struct TransportPongMessage))
3858 GNUNET_break_op (0);
3861 addr = (const char*) &pong[1];
3862 slen = strlen (ve->transport_name) + 1;
3863 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3864 (ve->challenge != challenge) ||
3865 (addr[slen-1] != '\0') ||
3866 (0 != strcmp (addr, ve->transport_name)) ||
3867 (ntohl (pong->purpose.size)
3868 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3870 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3871 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3876 alen = ps - sizeof (struct TransportPongMessage) - slen;
3877 switch (ntohl (pong->purpose.purpose))
3879 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3880 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3881 (0 != memcmp (&addr[slen],
3885 return GNUNET_YES; /* different entry, keep trying! */
3887 if (0 != memcmp (&pong->pid,
3889 sizeof (struct GNUNET_PeerIdentity)))
3891 GNUNET_break_op (0);
3895 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3900 GNUNET_break_op (0);
3905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3906 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3908 a2s (ve->transport_name,
3909 (const struct sockaddr *) ve->addr,
3911 ve->transport_name);
3914 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3915 if (0 != memcmp (&pong->pid,
3917 sizeof (struct GNUNET_PeerIdentity)))
3919 GNUNET_break_op (0);
3922 if (ve->addrlen != 0)
3924 /* must have been for a different validation entry */
3927 tp = find_transport (ve->transport_name);
3933 oal = tp->addresses;
3936 if ( (oal->addrlen == alen) &&
3937 (0 == memcmp (&oal[1],
3945 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3946 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3947 a2s (ve->transport_name,
3953 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3958 GNUNET_break_op (0);
3963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3964 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3966 a2s (ve->transport_name,
3969 ve->transport_name);
3973 GNUNET_break_op (0);
3976 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3978 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3979 _("Received expired signature. Check system time.\n"));
3982 GNUNET_STATISTICS_update (stats,
3983 gettext_noop ("# address validation successes"),
3986 /* create the updated HELLO */
3987 GNUNET_CRYPTO_hash (&ve->publicKey,
3988 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3989 &target.hashPubKey);
3990 if (ve->addr != NULL)
3992 avac.done = GNUNET_NO;
3994 hello = GNUNET_HELLO_create (&ve->publicKey,
3995 &add_validated_address,
3997 GNUNET_PEERINFO_add_peer (peerinfo,
3999 GNUNET_free (hello);
4001 n = find_neighbour (&target);
4004 n->publicKey = ve->publicKey;
4005 n->public_key_valid = GNUNET_YES;
4006 fal = add_peer_address (n,
4011 GNUNET_assert (fal != NULL);
4012 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4013 fal->validated = GNUNET_YES;
4014 mark_address_connected (fal);
4015 GNUNET_STATISTICS_update (stats,
4016 gettext_noop ("# peer addresses considered valid"),
4019 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4020 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4022 schedule_next_ping (fal);
4023 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4024 n->latency = fal->latency;
4026 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4028 n->distance = fal->distance;
4029 if (GNUNET_NO == n->received_pong)
4031 n->received_pong = GNUNET_YES;
4033 notify_clients_connect (&target, n->latency, n->distance);
4034 if (NULL != (prem = n->pre_connect_message_buffer))
4036 n->pre_connect_message_buffer = NULL;
4037 handle_payload_message (prem, n);
4041 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4043 GNUNET_SCHEDULER_cancel (n->retry_task);
4044 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4045 try_transmission_to_peer (n);
4049 /* clean up validation entry */
4050 GNUNET_assert (GNUNET_YES ==
4051 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4054 abort_validation (NULL, NULL, ve);
4060 * Function that will be called if we receive a validation
4061 * of an address challenge that we transmitted to another
4062 * peer. Note that the validation should only be considered
4063 * acceptable if the challenge matches AND if the sender
4064 * address is at least a plausible address for this peer
4065 * (otherwise we may be seeing a MiM attack).
4067 * @param cls closure
4068 * @param message the pong message
4069 * @param peer who responded to our challenge
4070 * @param sender_address string describing our sender address (as observed
4071 * by the other peer in binary format)
4072 * @param sender_address_len number of bytes in 'sender_address'
4075 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4076 const struct GNUNET_PeerIdentity *peer,
4077 const char *sender_address,
4078 size_t sender_address_len)
4080 #if DEBUG_TRANSPORT > 1
4081 /* we get tons of these that just get discarded, only log
4082 if we are quite verbose */
4083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4084 "Receiving `%s' message from `%4s'.\n", "PONG",
4087 GNUNET_STATISTICS_update (stats,
4088 gettext_noop ("# PONG messages received"),
4091 if (GNUNET_SYSERR !=
4092 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4094 &check_pending_validation,
4097 /* This is *expected* to happen a lot since we send
4098 PONGs to *all* known addresses of the sender of
4099 the PING, so most likely we get multiple PONGs
4100 per PING, and all but the first PONG will end up
4101 here. So really we should not print anything here
4102 unless we want to be very, very verbose... */
4103 #if DEBUG_TRANSPORT > 2
4104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4105 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4117 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4119 * @param cls the 'struct ValidationEntry*'
4120 * @param neighbour neighbour to validate, NULL if validation failed
4123 transmit_hello_and_ping (void *cls,
4124 struct NeighbourList *neighbour)
4126 struct ValidationEntry *va = cls;
4127 struct ForeignAddressList *peer_address;
4128 struct TransportPingMessage ping;
4129 uint16_t hello_size;
4132 struct GNUNET_PeerIdentity id;
4135 GNUNET_CRYPTO_hash (&va->publicKey,
4136 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4138 if (neighbour == NULL)
4140 /* FIXME: stats... */
4141 GNUNET_break (GNUNET_OK ==
4142 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4145 abort_validation (NULL, NULL, va);
4148 neighbour->publicKey = va->publicKey;
4149 neighbour->public_key_valid = GNUNET_YES;
4150 peer_address = add_peer_address (neighbour,
4151 va->transport_name, NULL,
4152 (const void*) &va[1],
4154 if (peer_address == NULL)
4156 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4157 "Failed to add peer `%4s' for plugin `%s'\n",
4158 GNUNET_i2s (&neighbour->id),
4159 va->transport_name);
4160 GNUNET_break (GNUNET_OK ==
4161 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4164 abort_validation (NULL, NULL, va);
4167 hello_size = GNUNET_HELLO_size(our_hello);
4168 slen = strlen(va->transport_name) + 1;
4169 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4170 message_buf = GNUNET_malloc(tsize);
4171 ping.challenge = htonl(va->challenge);
4172 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4173 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4174 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4175 memcpy(message_buf, our_hello, hello_size);
4176 memcpy(&message_buf[hello_size],
4178 sizeof(struct TransportPingMessage));
4179 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4182 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4187 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4190 : a2s (va->transport_name,
4191 (const void*) &va[1], va->addrlen),
4193 GNUNET_i2s (&neighbour->id),
4194 "HELLO", hello_size,
4195 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4198 GNUNET_STATISTICS_update (stats,
4199 gettext_noop ("# PING messages sent for initial validation"),
4202 transmit_to_peer (NULL, peer_address,
4203 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4204 HELLO_VERIFICATION_TIMEOUT,
4206 GNUNET_YES, neighbour);
4207 GNUNET_free(message_buf);
4212 * Check if the given address is already being validated; if not,
4213 * append the given address to the list of entries that are being be
4214 * validated and initiate validation.
4216 * @param cls closure ('struct CheckHelloValidatedContext *')
4217 * @param tname name of the transport
4218 * @param expiration expiration time
4219 * @param addr the address
4220 * @param addrlen length of the address
4221 * @return GNUNET_OK (always)
4224 run_validation (void *cls,
4226 struct GNUNET_TIME_Absolute expiration,
4230 struct CheckHelloValidatedContext *chvc = cls;
4231 struct GNUNET_PeerIdentity id;
4232 struct TransportPlugin *tp;
4233 struct ValidationEntry *va;
4234 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4235 struct CheckAddressExistsClosure caec;
4236 struct OwnAddressList *oal;
4238 GNUNET_assert (addr != NULL);
4240 GNUNET_STATISTICS_update (stats,
4241 gettext_noop ("# peer addresses scheduled for validation"),
4244 tp = find_transport (tname);
4247 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4248 GNUNET_ERROR_TYPE_BULK,
4250 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4252 GNUNET_STATISTICS_update (stats,
4253 gettext_noop ("# peer addresses not validated (plugin not available)"),
4258 /* check if this is one of our own addresses */
4259 oal = tp->addresses;
4262 if ( (oal->addrlen == addrlen) &&
4263 (0 == memcmp (&oal[1],
4267 /* not plausible, this address is equivalent to our own address! */
4268 GNUNET_STATISTICS_update (stats,
4269 gettext_noop ("# peer addresses not validated (loopback)"),
4276 GNUNET_HELLO_get_key (chvc->hello, &pk);
4277 GNUNET_CRYPTO_hash (&pk,
4279 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4282 if (is_blacklisted(&id, tp))
4285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4286 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4294 caec.addrlen = addrlen;
4295 caec.session = NULL;
4297 caec.exists = GNUNET_NO;
4298 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4299 &check_address_exists,
4301 if (caec.exists == GNUNET_YES)
4303 /* During validation attempts we will likely trigger the other
4304 peer trying to validate our address which in turn will cause
4305 it to send us its HELLO, so we expect to hit this case rather
4306 frequently. Only print something if we are very verbose. */
4307 #if DEBUG_TRANSPORT > 1
4308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4309 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4310 a2s (tname, addr, addrlen),
4314 GNUNET_STATISTICS_update (stats,
4315 gettext_noop ("# peer addresses not validated (in progress)"),
4320 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4323 va->transport_name = GNUNET_strdup (tname);
4324 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4326 va->send_time = GNUNET_TIME_absolute_get();
4327 va->addr = (const void*) &va[1];
4328 memcpy (&va[1], addr, addrlen);
4329 va->addrlen = addrlen;
4330 GNUNET_HELLO_get_key (chvc->hello,
4332 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4333 &timeout_hello_validation,
4335 GNUNET_CONTAINER_multihashmap_put (validation_map,
4338 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4339 setup_peer_check_blacklist (&id, GNUNET_NO,
4340 &transmit_hello_and_ping,
4347 * Check if addresses in validated hello "h" overlap with
4348 * those in "chvc->hello" and validate the rest.
4350 * @param cls closure
4351 * @param peer id of the peer, NULL for last call
4352 * @param h hello message for the peer (can be NULL)
4353 * @param err_msg NULL if successful, otherwise contains error message
4356 check_hello_validated (void *cls,
4357 const struct GNUNET_PeerIdentity *peer,
4358 const struct GNUNET_HELLO_Message *h,
4359 const char *err_msg)
4361 struct CheckHelloValidatedContext *chvc = cls;
4362 struct GNUNET_HELLO_Message *plain_hello;
4363 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4364 struct GNUNET_PeerIdentity target;
4365 struct NeighbourList *n;
4367 if (err_msg != NULL)
4369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4370 _("Error in communication with PEERINFO service\n"));
4376 GNUNET_STATISTICS_update (stats,
4377 gettext_noop ("# outstanding peerinfo iterate requests"),
4381 if (GNUNET_NO == chvc->hello_known)
4383 /* notify PEERINFO about the peer now, so that we at least
4384 have the public key if some other component needs it */
4385 GNUNET_HELLO_get_key (chvc->hello, &pk);
4386 GNUNET_CRYPTO_hash (&pk,
4387 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4388 &target.hashPubKey);
4389 plain_hello = GNUNET_HELLO_create (&pk,
4392 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4393 GNUNET_free (plain_hello);
4394 #if DEBUG_TRANSPORT_HELLO
4395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4396 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4398 GNUNET_i2s (&target));
4400 GNUNET_STATISTICS_update (stats,
4401 gettext_noop ("# new HELLOs requiring full validation"),
4404 GNUNET_HELLO_iterate_addresses (chvc->hello,
4411 GNUNET_STATISTICS_update (stats,
4412 gettext_noop ("# duplicate HELLO (peer known)"),
4417 if (chvc->ve_count == 0)
4419 GNUNET_CONTAINER_DLL_remove (chvc_head,
4428 #if DEBUG_TRANSPORT_HELLO
4429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4430 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4434 chvc->hello_known = GNUNET_YES;
4435 n = find_neighbour (peer);
4438 #if DEBUG_TRANSPORT_HELLO
4439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4440 "Calling hello_iterate_addresses for %s!\n",
4443 GNUNET_HELLO_iterate_addresses (h,
4445 &add_to_foreign_address_list,
4447 try_transmission_to_peer (n);
4451 #if DEBUG_TRANSPORT_HELLO
4452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4453 "No existing neighbor record for %s!\n",
4456 GNUNET_STATISTICS_update (stats,
4457 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4461 GNUNET_STATISTICS_update (stats,
4462 gettext_noop ("# HELLO validations (update case)"),
4465 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4467 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4474 * Process HELLO-message.
4476 * @param plugin transport involved, may be NULL
4477 * @param message the actual message
4478 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4481 process_hello (struct TransportPlugin *plugin,
4482 const struct GNUNET_MessageHeader *message)
4485 struct GNUNET_PeerIdentity target;
4486 const struct GNUNET_HELLO_Message *hello;
4487 struct CheckHelloValidatedContext *chvc;
4488 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4489 #if DEBUG_TRANSPORT_HELLO > 2
4492 hsize = ntohs (message->size);
4493 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4494 (hsize < sizeof (struct GNUNET_MessageHeader)))
4497 return GNUNET_SYSERR;
4499 GNUNET_STATISTICS_update (stats,
4500 gettext_noop ("# HELLOs received for validation"),
4504 /* first, check if load is too high */
4505 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4507 GNUNET_STATISTICS_update (stats,
4508 gettext_noop ("# HELLOs ignored due to high load"),
4511 #if DEBUG_TRANSPORT_HELLO
4512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4513 "Ignoring `%s' for `%4s', load too high.\n",
4515 GNUNET_i2s (&target));
4519 hello = (const struct GNUNET_HELLO_Message *) message;
4520 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4522 #if DEBUG_TRANSPORT_HELLO
4523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4524 "Unable to get public key from `%s' for `%4s'!\n",
4526 GNUNET_i2s (&target));
4528 GNUNET_break_op (0);
4529 return GNUNET_SYSERR;
4532 GNUNET_CRYPTO_hash (&publicKey,
4533 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4534 &target.hashPubKey);
4536 #if DEBUG_TRANSPORT_HELLO
4537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4538 "Received `%s' message for `%4s'\n",
4540 GNUNET_i2s (&target));
4543 if (0 == memcmp (&my_identity,
4545 sizeof (struct GNUNET_PeerIdentity)))
4547 GNUNET_STATISTICS_update (stats,
4548 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4554 while (NULL != chvc)
4556 if (GNUNET_HELLO_equals (hello,
4558 GNUNET_TIME_absolute_get ()).abs_value > 0)
4560 #if DEBUG_TRANSPORT_HELLO > 2
4561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4562 "Received duplicate `%s' message for `%4s'; ignored\n",
4564 GNUNET_i2s (&target));
4566 return GNUNET_OK; /* validation already pending */
4568 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4569 GNUNET_break (0 != memcmp (hello, chvc->hello,
4570 GNUNET_HELLO_size(hello)));
4575 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4576 if ((NULL != temp_neighbor))
4578 fprintf(stderr, "Already know peer, ignoring hello\n");
4583 #if DEBUG_TRANSPORT_HELLO > 2
4586 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4588 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4591 GNUNET_i2s (&target),
4593 GNUNET_HELLO_size(hello));
4597 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4599 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4600 memcpy (&chvc[1], hello, hsize);
4601 GNUNET_CONTAINER_DLL_insert (chvc_head,
4604 /* finally, check if HELLO was previously validated
4605 (continuation will then schedule actual validation) */
4606 GNUNET_STATISTICS_update (stats,
4607 gettext_noop ("# peerinfo process hello iterate requests"),
4610 GNUNET_STATISTICS_update (stats,
4611 gettext_noop ("# outstanding peerinfo iterate requests"),
4614 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4616 HELLO_VERIFICATION_TIMEOUT,
4617 &check_hello_validated, chvc);
4623 * The peer specified by the given neighbour has timed-out or a plugin
4624 * has disconnected. We may either need to do nothing (other plugins
4625 * still up), or trigger a full disconnect and clean up. This
4626 * function updates our state and does the necessary notifications.
4627 * Also notifies our clients that the neighbour is now officially
4630 * @param n the neighbour list entry for the peer
4631 * @param check GNUNET_YES to check if ALL addresses for this peer
4632 * are gone, GNUNET_NO to force a disconnect of the peer
4633 * regardless of whether other addresses exist.
4636 disconnect_neighbour (struct NeighbourList *n, int check)
4638 struct ReadyList *rpos;
4639 struct NeighbourList *npos;
4640 struct NeighbourList *nprev;
4641 struct MessageQueue *mq;
4642 struct ForeignAddressList *peer_addresses;
4643 struct ForeignAddressList *peer_pos;
4645 if (GNUNET_YES == check)
4648 while (NULL != rpos)
4650 peer_addresses = rpos->addresses;
4651 while (peer_addresses != NULL)
4653 if (GNUNET_YES == peer_addresses->connected)
4655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4656 "NOT Disconnecting from `%4s', still have live addresses!\n",
4657 GNUNET_i2s (&n->id));
4658 return; /* still connected */
4660 peer_addresses = peer_addresses->next;
4666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4667 "Disconnecting from `%4s'\n",
4668 GNUNET_i2s (&n->id));
4670 /* remove n from neighbours list */
4673 while ((npos != NULL) && (npos != n))
4678 GNUNET_assert (npos != NULL);
4680 neighbours = n->next;
4682 nprev->next = n->next;
4684 /* notify all clients about disconnect */
4685 if (GNUNET_YES == n->received_pong)
4686 notify_clients_disconnect (&n->id);
4688 /* clean up all plugins, cancel connections and pending transmissions */
4689 while (NULL != (rpos = n->plugins))
4691 n->plugins = rpos->next;
4692 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4693 while (rpos->addresses != NULL)
4695 peer_pos = rpos->addresses;
4696 rpos->addresses = peer_pos->next;
4697 if (peer_pos->connected == GNUNET_YES)
4698 GNUNET_STATISTICS_update (stats,
4699 gettext_noop ("# connected addresses"),
4702 if (GNUNET_YES == peer_pos->validated)
4703 GNUNET_STATISTICS_update (stats,
4704 gettext_noop ("# peer addresses considered valid"),
4707 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4709 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4710 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4712 GNUNET_free(peer_pos->ressources);
4713 GNUNET_free(peer_pos->quality);
4714 GNUNET_free(peer_pos);
4719 /* free all messages on the queue */
4720 while (NULL != (mq = n->messages_head))
4722 GNUNET_STATISTICS_update (stats,
4723 gettext_noop ("# bytes in message queue for other peers"),
4724 - (int64_t) mq->message_buf_size,
4726 GNUNET_STATISTICS_update (stats,
4727 gettext_noop ("# bytes discarded due to disconnect"),
4728 mq->message_buf_size,
4730 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4733 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4735 sizeof(struct GNUNET_PeerIdentity)));
4738 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4740 GNUNET_SCHEDULER_cancel (n->timeout_task);
4741 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4743 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4745 GNUNET_SCHEDULER_cancel (n->retry_task);
4746 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4748 if (n->piter != NULL)
4750 GNUNET_PEERINFO_iterate_cancel (n->piter);
4751 GNUNET_STATISTICS_update (stats,
4752 gettext_noop ("# outstanding peerinfo iterate requests"),
4757 /* finally, free n itself */
4758 GNUNET_STATISTICS_update (stats,
4759 gettext_noop ("# active neighbours"),
4762 GNUNET_free_non_null (n->pre_connect_message_buffer);
4768 * We have received a PING message from someone. Need to send a PONG message
4769 * in response to the peer by any means necessary.
4772 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4773 const struct GNUNET_PeerIdentity *peer,
4774 struct Session *session,
4775 const char *sender_address,
4776 uint16_t sender_address_len)
4778 struct TransportPlugin *plugin = cls;
4779 struct SessionHeader *session_header = (struct SessionHeader*) session;
4780 struct TransportPingMessage *ping;
4781 struct TransportPongMessage *pong;
4782 struct NeighbourList *n;
4783 struct ReadyList *rl;
4784 struct ForeignAddressList *fal;
4785 struct OwnAddressList *oal;
4790 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4792 GNUNET_break_op (0);
4793 return GNUNET_SYSERR;
4796 ping = (struct TransportPingMessage *) message;
4797 if (0 != memcmp (&ping->target,
4798 plugin->env.my_identity,
4799 sizeof (struct GNUNET_PeerIdentity)))
4801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4802 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4804 (sender_address != NULL)
4805 ? a2s (plugin->short_name,
4806 (const struct sockaddr *)sender_address,
4809 GNUNET_i2s (&ping->target));
4810 return GNUNET_SYSERR;
4813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4814 "Processing `%s' from `%s'\n",
4816 (sender_address != NULL)
4817 ? a2s (plugin->short_name,
4818 (const struct sockaddr *)sender_address,
4822 GNUNET_STATISTICS_update (stats,
4823 gettext_noop ("# PING messages received"),
4826 addr = (const char*) &ping[1];
4827 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4828 slen = strlen (plugin->short_name) + 1;
4831 /* peer wants to confirm that we have an outbound connection to him */
4832 if (session == NULL)
4834 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4835 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4837 return GNUNET_SYSERR;
4839 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4840 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4841 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4842 pong->purpose.size =
4843 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4845 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4846 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4847 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4848 pong->challenge = ping->challenge;
4849 pong->addrlen = htonl(sender_address_len + slen);
4852 sizeof(struct GNUNET_PeerIdentity));
4856 if ((sender_address!=NULL) && (sender_address_len > 0))
4857 memcpy (&((char*)&pong[1])[slen],
4859 sender_address_len);
4860 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4862 /* create / update cached sig */
4864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4865 "Creating PONG signature to indicate active connection.\n");
4867 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4868 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4869 GNUNET_assert (GNUNET_OK ==
4870 GNUNET_CRYPTO_rsa_sign (my_private_key,
4872 &session_header->pong_signature));
4876 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4878 memcpy (&pong->signature,
4879 &session_header->pong_signature,
4880 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4886 /* peer wants to confirm that this is one of our addresses */
4890 plugin->api->check_address (plugin->api->cls,
4894 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4895 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4896 a2s (plugin->short_name,
4901 oal = plugin->addresses;
4904 if ( (oal->addrlen == alen) &&
4911 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4912 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4913 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4914 pong->purpose.size =
4915 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4917 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4918 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4919 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4920 pong->challenge = ping->challenge;
4921 pong->addrlen = htonl(alen + slen);
4924 sizeof(struct GNUNET_PeerIdentity));
4925 memcpy (&pong[1], plugin->short_name, slen);
4926 memcpy (&((char*)&pong[1])[slen], addr, alen);
4927 if ( (oal != NULL) &&
4928 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4930 /* create / update cached sig */
4932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4933 "Creating PONG signature to indicate ownership.\n");
4935 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4936 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4937 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4938 GNUNET_assert (GNUNET_OK ==
4939 GNUNET_CRYPTO_rsa_sign (my_private_key,
4941 &oal->pong_signature));
4942 memcpy (&pong->signature,
4943 &oal->pong_signature,
4944 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4946 else if (oal == NULL)
4948 /* not using cache (typically DV-only) */
4949 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4950 GNUNET_assert (GNUNET_OK ==
4951 GNUNET_CRYPTO_rsa_sign (my_private_key,
4957 /* can used cached version */
4958 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4959 memcpy (&pong->signature,
4960 &oal->pong_signature,
4961 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4964 n = find_neighbour(peer);
4965 GNUNET_assert (n != NULL);
4966 /* first try reliable response transmission */
4970 fal = rl->addresses;
4973 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4976 ntohs (pong->header.size),
4977 TRANSPORT_PONG_PRIORITY,
4978 HELLO_VERIFICATION_TIMEOUT,
4986 GNUNET_STATISTICS_update (stats,
4987 gettext_noop ("# PONGs unicast via reliable transport"),
4997 /* no reliable method found, do multicast */
4998 GNUNET_STATISTICS_update (stats,
4999 gettext_noop ("# PONGs multicast to all available addresses"),
5005 fal = rl->addresses;
5008 transmit_to_peer(NULL, fal,
5009 TRANSPORT_PONG_PRIORITY,
5010 HELLO_VERIFICATION_TIMEOUT,
5012 ntohs(pong->header.size),
5028 * Function called by the plugin for each received message.
5029 * Update data volumes, possibly notify plugins about
5030 * reducing the rate at which they read from the socket
5031 * and generally forward to our receive callback.
5033 * @param cls the "struct TransportPlugin *" we gave to the plugin
5034 * @param peer (claimed) identity of the other peer
5035 * @param message the message, NULL if we only care about
5036 * learning about the delay until we should receive again
5037 * @param ats_data information for automatic transport selection
5038 * @param ats_count number of elements in ats not including 0-terminator
5039 * @param session identifier used for this session (can be NULL)
5040 * @param sender_address binary address of the sender (if observed)
5041 * @param sender_address_len number of bytes in sender_address
5042 * @return how long in ms the plugin should wait until receiving more data
5043 * (plugins that do not support this, can ignore the return value)
5045 static struct GNUNET_TIME_Relative
5046 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5047 const struct GNUNET_MessageHeader *message,
5048 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5050 struct Session *session,
5051 const char *sender_address,
5052 uint16_t sender_address_len)
5054 struct TransportPlugin *plugin = cls;
5055 struct ReadyList *service_context;
5056 struct ForeignAddressList *peer_address;
5058 struct NeighbourList *n;
5059 struct GNUNET_TIME_Relative ret;
5060 if (is_blacklisted (peer, plugin))
5061 return GNUNET_TIME_UNIT_FOREVER_REL;
5065 n = find_neighbour (peer);
5067 n = setup_new_neighbour (peer, GNUNET_YES);
5068 service_context = n->plugins;
5069 while ((service_context != NULL) && (plugin != service_context->plugin))
5070 service_context = service_context->next;
5071 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5072 peer_address = NULL;
5075 for (c=0; c<ats_count; c++)
5077 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5079 distance = ntohl(ats_data[c].value);
5082 /* notify ATS about incoming data */
5083 //ats_notify_ats_data(peer, ats_data);
5085 if (message != NULL)
5087 if ( (session != NULL) ||
5088 (sender_address != NULL) )
5089 peer_address = add_peer_address (n,
5093 sender_address_len);
5094 if (peer_address != NULL)
5097 update_addr_ats(peer_address, ats_data, ats_count);
5098 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5100 peer_address->distance = distance;
5101 if (GNUNET_YES == peer_address->validated)
5102 mark_address_connected (peer_address);
5103 peer_address->timeout
5105 GNUNET_TIME_relative_to_absolute
5106 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5107 schedule_next_ping (peer_address);
5109 /* update traffic received amount ... */
5110 msize = ntohs (message->size);
5111 GNUNET_STATISTICS_update (stats,
5112 gettext_noop ("# bytes received from other peers"),
5115 n->distance = distance;
5117 GNUNET_TIME_relative_to_absolute
5118 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5119 GNUNET_SCHEDULER_cancel (n->timeout_task);
5121 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5122 &neighbour_timeout_task, n);
5123 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5125 /* dropping message due to frequent inbound volume violations! */
5126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5127 GNUNET_ERROR_TYPE_BULK,
5129 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5130 n->in_tracker.available_bytes_per_s__,
5131 n->quota_violation_count);
5132 GNUNET_STATISTICS_update (stats,
5133 gettext_noop ("# bandwidth quota violations by other peers"),
5136 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5141 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5142 ntohs (message->type),
5143 ntohs (message->size),
5146 switch (ntohs (message->type))
5148 case GNUNET_MESSAGE_TYPE_HELLO:
5149 GNUNET_STATISTICS_update (stats,
5150 gettext_noop ("# HELLO messages received from other peers"),
5153 process_hello (plugin, message);
5155 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5156 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5158 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5159 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5162 handle_payload_message (message, n);
5166 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5167 if (ret.rel_value > 0)
5169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5170 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5171 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5172 (unsigned int) n->in_tracker.available_bytes_per_s__,
5173 (unsigned long long) ret.rel_value);
5174 GNUNET_STATISTICS_update (stats,
5175 gettext_noop ("# ms throttling suggested"),
5176 (int64_t) ret.rel_value,
5183 * Handle START-message. This is the first message sent to us
5184 * by any client which causes us to add it to our list.
5186 * @param cls closure (always NULL)
5187 * @param client identification of the client
5188 * @param message the actual message
5191 handle_start (void *cls,
5192 struct GNUNET_SERVER_Client *client,
5193 const struct GNUNET_MessageHeader *message)
5195 const struct StartMessage *start;
5196 struct TransportClient *c;
5197 struct ConnectInfoMessage * cim;
5198 struct NeighbourList *n;
5202 start = (const struct StartMessage*) message;
5204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5205 "Received `%s' request from client\n", "START");
5210 if (c->client == client)
5212 /* client already on our list! */
5214 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5219 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5220 (0 != memcmp (&start->self,
5222 sizeof (struct GNUNET_PeerIdentity))) )
5224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5225 _("Rejecting control connection from peer `%s', which is not me!\n"),
5226 GNUNET_i2s (&start->self));
5227 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5230 c = GNUNET_malloc (sizeof (struct TransportClient));
5234 if (our_hello != NULL)
5237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5238 "Sending our own `%s' to new client\n", "HELLO");
5240 transmit_to_client (c,
5241 (const struct GNUNET_MessageHeader *) our_hello,
5243 /* tell new client about all existing connections */
5245 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5246 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5250 cim = GNUNET_malloc (size);
5251 cim->header.size = htons (size);
5252 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5253 cim->ats_count = htonl(ats_count);
5254 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5255 (&(cim->ats))[2].value = htonl (0);
5259 if (GNUNET_YES == n->received_pong)
5261 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5262 (&(cim->ats))[0].value = htonl (n->distance);
5263 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5264 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5266 transmit_to_client (c, &cim->header, GNUNET_NO);
5272 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5277 * Handle HELLO-message.
5279 * @param cls closure (always NULL)
5280 * @param client identification of the client
5281 * @param message the actual message
5284 handle_hello (void *cls,
5285 struct GNUNET_SERVER_Client *client,
5286 const struct GNUNET_MessageHeader *message)
5290 GNUNET_STATISTICS_update (stats,
5291 gettext_noop ("# HELLOs received from clients"),
5294 ret = process_hello (NULL, message);
5295 GNUNET_SERVER_receive_done (client, ret);
5300 * Closure for 'transmit_client_message'; followed by
5301 * 'msize' bytes of the actual message.
5303 struct TransmitClientMessageContext
5306 * Client on whom's behalf we are sending.
5308 struct GNUNET_SERVER_Client *client;
5311 * Timeout for the transmission.
5313 struct GNUNET_TIME_Absolute timeout;
5321 * Size of the message in bytes.
5328 * Schedule transmission of a message we got from a client to a peer.
5330 * @param cls the 'struct TransmitClientMessageContext*'
5331 * @param n destination, or NULL on error (in that case, drop the message)
5334 transmit_client_message (void *cls,
5335 struct NeighbourList *n)
5337 struct TransmitClientMessageContext *tcmc = cls;
5338 struct TransportClient *tc;
5341 while ((tc != NULL) && (tc->client != tcmc->client))
5346 transmit_to_peer (tc, NULL, tcmc->priority,
5347 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5349 tcmc->msize, GNUNET_NO, n);
5351 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5352 GNUNET_SERVER_client_drop (tcmc->client);
5358 * Handle SEND-message.
5360 * @param cls closure (always NULL)
5361 * @param client identification of the client
5362 * @param message the actual message
5365 handle_send (void *cls,
5366 struct GNUNET_SERVER_Client *client,
5367 const struct GNUNET_MessageHeader *message)
5369 const struct OutboundMessage *obm;
5370 const struct GNUNET_MessageHeader *obmm;
5371 struct TransmitClientMessageContext *tcmc;
5375 size = ntohs (message->size);
5377 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5380 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5383 GNUNET_STATISTICS_update (stats,
5384 gettext_noop ("# payload received for other peers"),
5387 obm = (const struct OutboundMessage *) message;
5388 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5389 msize = size - sizeof (struct OutboundMessage);
5391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5392 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5393 "SEND", GNUNET_i2s (&obm->peer),
5397 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5398 tcmc->client = client;
5399 tcmc->priority = ntohl (obm->priority);
5400 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5401 tcmc->msize = msize;
5402 /* FIXME: this memcpy can be up to 7% of our total runtime */
5403 memcpy (&tcmc[1], obmm, msize);
5404 GNUNET_SERVER_client_keep (client);
5405 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5406 &transmit_client_message,
5412 * Handle request connect message
5414 * @param cls closure (always NULL)
5415 * @param client identification of the client
5416 * @param message the actual message
5419 handle_request_connect (void *cls,
5420 struct GNUNET_SERVER_Client *client,
5421 const struct GNUNET_MessageHeader *message)
5423 const struct TransportRequestConnectMessage *trcm =
5424 (const struct TransportRequestConnectMessage *) message;
5426 GNUNET_STATISTICS_update (stats,
5427 gettext_noop ("# REQUEST CONNECT messages received"),
5430 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5431 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5433 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5437 * Handle SET_QUOTA-message.
5439 * @param cls closure (always NULL)
5440 * @param client identification of the client
5441 * @param message the actual message
5444 handle_set_quota (void *cls,
5445 struct GNUNET_SERVER_Client *client,
5446 const struct GNUNET_MessageHeader *message)
5448 const struct QuotaSetMessage *qsm =
5449 (const struct QuotaSetMessage *) message;
5450 struct NeighbourList *n;
5452 GNUNET_STATISTICS_update (stats,
5453 gettext_noop ("# SET QUOTA messages received"),
5456 n = find_neighbour (&qsm->peer);
5459 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5460 GNUNET_STATISTICS_update (stats,
5461 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5468 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5470 (unsigned int) ntohl (qsm->quota.value__),
5471 (unsigned int) n->in_tracker.available_bytes_per_s__,
5472 GNUNET_i2s (&qsm->peer));
5474 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5476 if (0 == ntohl (qsm->quota.value__))
5478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5479 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5481 disconnect_neighbour (n, GNUNET_NO);
5483 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5488 * Take the given address and append it to the set of results sent back to
5491 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5492 * @param address the resolved name, NULL to indicate the last response
5495 transmit_address_to_client (void *cls, const char *address)
5497 struct GNUNET_SERVER_TransmitContext *tc = cls;
5500 if (NULL == address)
5503 slen = strlen (address) + 1;
5505 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5506 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5507 if (NULL == address)
5508 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5513 * Handle AddressLookup-message.
5515 * @param cls closure (always NULL)
5516 * @param client identification of the client
5517 * @param message the actual message
5520 handle_address_lookup (void *cls,
5521 struct GNUNET_SERVER_Client *client,
5522 const struct GNUNET_MessageHeader *message)
5524 const struct AddressLookupMessage *alum;
5525 struct TransportPlugin *lsPlugin;
5526 const char *nameTransport;
5527 const char *address;
5529 struct GNUNET_SERVER_TransmitContext *tc;
5530 struct GNUNET_TIME_Absolute timeout;
5531 struct GNUNET_TIME_Relative rtimeout;
5534 size = ntohs (message->size);
5535 if (size < sizeof (struct AddressLookupMessage))
5537 GNUNET_break_op (0);
5538 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5541 alum = (const struct AddressLookupMessage *) message;
5542 uint32_t addressLen = ntohl (alum->addrlen);
5543 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5545 GNUNET_break_op (0);
5546 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5549 address = (const char *) &alum[1];
5550 nameTransport = (const char *) &address[addressLen];
5552 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5554 GNUNET_break_op (0);
5555 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5558 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5559 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5560 numeric = ntohl (alum->numeric_only);
5561 lsPlugin = find_transport (nameTransport);
5562 if (NULL == lsPlugin)
5564 tc = GNUNET_SERVER_transmit_context_create (client);
5565 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5566 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5567 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5570 tc = GNUNET_SERVER_transmit_context_create (client);
5571 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5573 address, addressLen,
5576 &transmit_address_to_client, tc);
5581 * Setup the environment for this plugin.
5584 create_environment (struct TransportPlugin *plug)
5586 plug->env.cfg = cfg;
5587 plug->env.my_identity = &my_identity;
5588 plug->env.our_hello = &our_hello;
5589 plug->env.cls = plug;
5590 plug->env.receive = &plugin_env_receive;
5591 plug->env.notify_address = &plugin_env_notify_address;
5592 plug->env.session_end = &plugin_env_session_end;
5593 plug->env.max_connections = max_connect_per_transport;
5594 plug->env.stats = stats;
5599 * Start the specified transport (load the plugin).
5602 start_transport (struct GNUNET_SERVER_Handle *server,
5605 struct TransportPlugin *plug;
5608 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5609 _("Loading `%s' transport plugin\n"), name);
5610 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5611 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5612 create_environment (plug);
5613 plug->short_name = GNUNET_strdup (name);
5614 plug->lib_name = libname;
5615 plug->next = plugins;
5617 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5618 if (plug->api == NULL)
5620 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5621 _("Failed to load transport plugin for `%s'\n"), name);
5622 GNUNET_free (plug->short_name);
5623 plugins = plug->next;
5624 GNUNET_free (libname);
5631 * Called whenever a client is disconnected. Frees our
5632 * resources associated with that client.
5634 * @param cls closure
5635 * @param client identification of the client
5638 client_disconnect_notification (void *cls,
5639 struct GNUNET_SERVER_Client *client)
5641 struct TransportClient *pos;
5642 struct TransportClient *prev;
5643 struct ClientMessageQueueEntry *mqe;
5644 struct Blacklisters *bl;
5645 struct BlacklistCheck *bc;
5650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5651 "Client disconnected, cleaning up.\n");
5653 /* clean up blacklister */
5657 if (bl->client == client)
5662 if (bc->bl_pos == bl)
5664 bc->bl_pos = bl->next;
5667 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5670 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5671 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5677 GNUNET_CONTAINER_DLL_remove (bl_head,
5680 GNUNET_SERVER_client_drop (bl->client);
5686 /* clean up 'normal' clients */
5689 while ((pos != NULL) && (pos->client != client))
5696 while (NULL != (mqe = pos->message_queue_head))
5698 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5699 pos->message_queue_tail,
5701 pos->message_count--;
5705 clients = pos->next;
5707 prev->next = pos->next;
5708 if (GNUNET_YES == pos->tcs_pending)
5713 if (pos->th != NULL)
5715 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5718 GNUNET_break (0 == pos->message_count);
5724 * Function called when the service shuts down. Unloads our plugins
5725 * and cancels pending validations.
5727 * @param cls closure, unused
5728 * @param tc task context (unused)
5731 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5733 struct TransportPlugin *plug;
5734 struct OwnAddressList *al;
5735 struct CheckHelloValidatedContext *chvc;
5737 while (neighbours != NULL)
5739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5740 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5742 disconnect_neighbour (neighbours, GNUNET_NO);
5745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5746 "Transport service is unloading plugins...\n");
5748 while (NULL != (plug = plugins))
5750 plugins = plug->next;
5751 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5753 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5754 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5756 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5757 GNUNET_free (plug->lib_name);
5758 GNUNET_free (plug->short_name);
5759 while (NULL != (al = plug->addresses))
5761 plug->addresses = al->next;
5766 if (my_private_key != NULL)
5767 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5768 GNUNET_free_non_null (our_hello);
5770 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5773 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5774 validation_map = NULL;
5778 /* free 'chvc' data structure */
5779 while (NULL != (chvc = chvc_head))
5781 chvc_head = chvc->next;
5782 if (chvc->piter != NULL)
5784 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5785 GNUNET_STATISTICS_update (stats,
5786 gettext_noop ("# outstanding peerinfo iterate requests"),
5792 GNUNET_assert (chvc->ve_count == 0);
5799 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5802 if (peerinfo != NULL)
5804 GNUNET_PEERINFO_disconnect (peerinfo);
5807 /* Can we assume those are gone by now, or do we need to clean up
5809 GNUNET_break (bl_head == NULL);
5810 GNUNET_break (bc_head == NULL);
5814 static int ats_evaluate_results (int result, int solution, char * problem)
5816 int cont = GNUNET_NO;
5817 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5819 error_kind = GNUNET_ERROR_TYPE_ERROR;
5823 case GLP_ESTOP : /* search terminated by application */
5824 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5826 case GLP_EITLIM : /* iteration limit exceeded */
5827 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5830 case GLP_ETMLIM : /* time limit exceeded */
5831 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5833 case GLP_ENOPFS : /* no primal feasible solution */
5834 case GLP_ENODFS : /* no dual feasible solution */
5835 GNUNET_log (error_kind, "%s No feasible solution", problem);
5838 case GLP_EBADB : /* invalid basis */
5839 case GLP_ESING : /* singular matrix */
5840 case GLP_ECOND : /* ill-conditioned matrix */
5841 case GLP_EBOUND : /* invalid bounds */
5842 case GLP_EFAIL : /* solver failed */
5843 case GLP_EOBJLL : /* objective lower limit reached */
5844 case GLP_EOBJUL : /* objective upper limit reached */
5845 case GLP_EROOT : /* root LP optimum not provided */
5846 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5850 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5856 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
5859 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
5863 GNUNET_log (error_kind, "%s solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n", problem);
5867 GNUNET_log (error_kind, "%s problem has no integer feasible solution\n", problem);
5877 static void ats_solve_problem (unsigned int max_it, unsigned int max_dur, unsigned int c_peers, unsigned int c_mechs, struct ATS_result *res)
5883 glp_prob *prob = ats->prob;
5886 glp_init_smcp(&opt_lp);
5888 opt_lp.msg_lev = GLP_MSG_ALL;
5890 opt_lp.msg_lev = GLP_MSG_OFF;
5892 opt_lp.presolve = GLP_ON;
5893 result = glp_simplex(prob, &opt_lp);
5894 solution = glp_get_status (prob);
5896 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
5900 glp_init_iocp(&opt_mlp);
5901 /* maximum duration */
5902 opt_mlp.presolve = GLP_ON;
5903 opt_mlp.tm_lim = max_dur;
5906 opt_mlp.msg_lev = GLP_MSG_ALL;
5908 opt_mlp.msg_lev = GLP_MSG_OFF;
5910 result = glp_intopt (prob, &opt_mlp);
5911 solution = glp_mip_status (prob);
5912 res->solution = solution;
5913 res->valid = GNUNET_NO;
5914 if (ats_evaluate_results(result, solution, "MLP") == GNUNET_YES)
5915 res->valid = GNUNET_YES;
5919 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
5922 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5923 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5924 glp_write_mip (prob, filename);
5925 GNUNET_free (filename);
5927 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
5930 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5931 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5932 glp_print_sol (prob, filename);
5933 GNUNET_free (filename);
5938 int error = GNUNET_NO;
5940 struct ATS_mechanism *t = NULL;
5941 for (c=1; c<= (c_peers); c++ )
5944 t = peers[c].m_head;
5947 bw = glp_get_col_prim(prob, t->col_index);
5951 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);
5953 if (check ==GNUNET_YES)
5955 glp_write_sol(prob, "invalid_solution.mlp");
5956 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
5957 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
5960 if (check ==GNUNET_NO)
5968 for (c=1; c<= available_quality_metrics; c++ )
5970 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));
5972 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));
5973 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));
5974 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));
5979 /** solve the bandwidth distribution problem
5980 * @param max_it maximum iterations
5981 * @param max_dur maximum duration in ms
5982 * @param D weight for diversity
5983 * @param U weight for utility
5984 * @param R weight for relativity
5985 * @param v_b_min minimal bandwidth per peer
5986 * @param v_n_min minimum number of connections
5987 * @param res result struct
5988 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5990 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
5993 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5994 return GNUNET_SYSERR;
5997 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
6000 if (ats->prob != NULL)
6001 glp_delete_prob(ats->prob);
6003 ats->prob = glp_create_prob();
6009 int c_c_ressources = available_ressources;
6010 int c_q_metrics = available_quality_metrics;
6012 double M = VERY_BIG_DOUBLE_VALUE;
6013 double Q[c_q_metrics+1];
6014 for (c=1; c<=c_q_metrics; c++)
6019 struct NeighbourList *next = neighbours;
6022 struct ReadyList *r_next = next->plugins;
6023 while (r_next != NULL)
6025 struct ForeignAddressList * a_next = r_next->addresses;
6026 while (a_next != NULL)
6029 a_next = a_next->next;
6031 r_next = r_next->next;
6040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6042 res->valid = GNUNET_NO;
6043 return GNUNET_SYSERR;
6046 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6047 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6054 peers[c_peers].peer = next->id;
6055 peers[c_peers].m_head = NULL;
6056 peers[c_peers].m_tail = NULL;
6058 peers[c_peers].f = 1.0 / c_mechs;
6060 struct ReadyList *r_next = next->plugins;
6061 while (r_next != NULL)
6063 struct ForeignAddressList * a_next = r_next->addresses;
6064 while (a_next != NULL)
6066 mechanisms[c_mechs].addr = a_next;
6067 mechanisms[c_mechs].col_index = c_mechs;
6068 mechanisms[c_mechs].peer = &peers[c_peers];
6069 mechanisms[c_mechs].next = NULL;
6070 mechanisms[c_mechs].plugin = r_next->plugin;
6072 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6074 a_next = a_next->next;
6076 r_next = r_next->next;
6084 if (v_n_min > c_peers)
6088 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);
6091 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6094 int * ia = GNUNET_malloc (size * sizeof (int));
6095 int * ja = GNUNET_malloc (size * sizeof (int));
6096 double * ar = GNUNET_malloc(size* sizeof (double));
6098 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6099 glp_set_obj_dir(ats->prob, GLP_MAX);
6101 /* adding columns */
6103 glp_add_cols(ats->prob, 2 * c_mechs);
6104 /* adding b_t cols */
6105 for (c=1; c <= c_mechs; c++)
6108 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6109 glp_set_col_name(ats->prob, c, name);
6111 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6112 glp_set_obj_coef(ats->prob, c, 1);
6115 /* adding n_t cols */
6116 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6118 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6119 glp_set_col_name(ats->prob, c, name);
6121 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6122 glp_set_col_kind(ats->prob, c, GLP_IV);
6123 glp_set_obj_coef(ats->prob, c, 0);
6126 /* feasibility constraints */
6127 /* Constraint 1: one address per peer*/
6129 glp_add_rows(ats->prob, c_peers);
6130 for (c=1; c<=c_peers; c++)
6132 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6134 struct ATS_mechanism *m = peers[c].m_head;
6137 ia[array_index] = row_index;
6138 ja[array_index] = (c_mechs + m->col_index);
6139 ar[array_index] = 1;
6141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6149 /* Constraint 2: only active mechanism gets bandwidth assigned */
6150 glp_add_rows(ats->prob, c_mechs);
6151 for (c=1; c<=c_mechs; c++)
6153 /* b_t - n_t * M <= 0 */
6155 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6157 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6159 ia[array_index] = row_index;
6160 ja[array_index] = mechanisms[c].col_index;
6161 ar[array_index] = 1;
6163 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6166 ia[array_index] = row_index;
6167 ja[array_index] = c_mechs + mechanisms[c].col_index;
6168 ar[array_index] = -M;
6170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6176 /* Constraint 3: minimum bandwidth*/
6177 glp_add_rows(ats->prob, c_mechs);
6178 for (c=1; c<=c_mechs; c++)
6180 /* b_t - n_t * b_min <= 0 */
6182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6184 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6186 ia[array_index] = row_index;
6187 ja[array_index] = mechanisms[c].col_index;
6188 ar[array_index] = 1;
6190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6193 ia[array_index] = row_index;
6194 ja[array_index] = c_mechs + mechanisms[c].col_index;
6195 ar[array_index] = -v_b_min;
6197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6203 /* Constraint 4: max ressource capacity */
6204 /* V cr: bt * ct_r <= cr_maxsolution
6206 glp_add_rows(ats->prob, available_ressources);
6207 double ct_max = VERY_BIG_DOUBLE_VALUE;
6208 double ct_min = 0.0;
6210 for (c=0; c<available_ressources; c++)
6212 ct_max = ressources[c].c_max;
6213 ct_min = ressources[c].c_min;
6215 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6217 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6219 for (c2=1; c2<=c_mechs; c2++)
6222 ia[array_index] = row_index;
6223 ja[array_index] = c2;
6224 value = mechanisms[c2].addr->ressources[c].c;
6225 ar[array_index] = value;
6227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6234 /* Constraint 5: min number of connections*/
6235 glp_add_rows(ats->prob, 1);
6236 for (c=1; c<=c_mechs; c++)
6238 // b_t - n_t * b_min >= 0
6240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6242 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6244 ia[array_index] = row_index;
6245 ja[array_index] = c_mechs + mechanisms[c].col_index;
6246 ar[array_index] = 1;
6248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6254 /* optimisation constraints*/
6256 /* adding columns */
6257 glp_add_cols(ats->prob, 3 + c_q_metrics);
6259 glp_set_col_name(ats->prob, (2*c_mechs) + 1, "d");
6260 glp_set_obj_coef(ats->prob, (2*c_mechs) + 1, D);
6261 glp_set_col_bnds(ats->prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6262 glp_set_col_name(ats->prob, (2*c_mechs) + 2, "u");
6263 glp_set_obj_coef(ats->prob, (2*c_mechs) + 2, U);
6264 glp_set_col_bnds(ats->prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6265 glp_set_col_name(ats->prob, (2*c_mechs) + 3, "r");
6266 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3, R);
6267 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6269 for (c=1; c<= c_q_metrics; c++)
6271 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6272 glp_set_col_name(ats->prob, (2*c_mechs) + 3 + c, name);
6273 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6275 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3 + c, Q[c]);
6278 // Constraint 6: optimize for diversity
6279 glp_add_rows(ats->prob, 1);
6281 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6283 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6284 for (c=1; c<=c_mechs; c++)
6286 // b_t - n_t * b_min >= 0
6287 ia[array_index] = row_index;
6288 ja[array_index] = c_mechs + mechanisms[c].col_index;
6289 ar[array_index] = 1;
6291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6295 ia[array_index] = row_index;
6296 ja[array_index] = (2*c_mechs) + 1;
6297 ar[array_index] = -1;
6299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6305 // Constraint 7: optimize for quality
6306 glp_add_rows(ats->prob, available_quality_metrics);
6307 for (c=1; c <= c_q_metrics; c++)
6310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6312 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6314 for (c2=1; c2<=c_mechs; c2++)
6317 ia[array_index] = row_index;
6318 ja[array_index] = c2;
6319 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6322 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6323 if (v1 < 1) v0 = 0.1;
6324 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6325 if (v1 < 1) v0 = 0.1;
6326 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6327 if (v1 < 1) v0 = 0.1;
6328 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6330 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6333 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6335 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6337 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6339 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6341 value = (double) 10 / value;
6345 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6347 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]);
6352 ia[array_index] = row_index;
6353 ja[array_index] = (2*c_mechs) + 3 +c;
6354 ar[array_index] = -1;
6356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6362 // Constraint 8: optimize bandwidth utility
6363 glp_add_rows(ats->prob, 1);
6365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6367 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6368 for (c=1; c<=c_mechs; c++)
6370 ia[array_index] = row_index;
6371 ja[array_index] = c;
6372 ar[array_index] = mechanisms[c].peer->f;
6374 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6378 ia[array_index] = row_index;
6379 ja[array_index] = (2*c_mechs) + 2;
6380 ar[array_index] = -1;
6382 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6388 // Constraint 9: optimize relativity
6389 glp_add_rows(ats->prob, c_peers);
6390 for (c=1; c<=c_peers; c++)
6392 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6394 struct ATS_mechanism *m = peers[c].m_head;
6397 ia[array_index] = row_index;
6398 ja[array_index] = m->col_index;
6399 ar[array_index] = 1;
6401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6406 ia[array_index] = row_index;
6407 ja[array_index] = (2*c_mechs) + 3;
6408 ar[array_index] = -1;
6410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6416 /* Loading the matrix */
6417 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6419 res->c_mechs = c_mechs;
6420 res->c_peers = c_peers;
6422 res->valid = GNUNET_YES;
6430 for (c=0; c<c_mechs; c++)
6431 GNUNET_free_non_null (mechanisms[c].rc);
6433 GNUNET_free(mechanisms);
6439 void ats_calculate_bandwidth_distribution ()
6441 struct GNUNET_TIME_Absolute start;
6442 struct GNUNET_TIME_Relative duration;
6444 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6445 if (delta.rel_value < ats->min_delta.rel_value)
6448 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6454 if (INT_MAX < ats->max_exec_duration.rel_value)
6457 dur = (int) ats->max_exec_duration.rel_value;
6459 start = GNUNET_TIME_absolute_get();
6460 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... have to recreate problem\n");
6465 ats->modified_addr = GNUNET_NO;
6466 ats->res.c_mechs = 0;
6467 ats->res.c_peers = 0;
6468 ats->res.solution = 0;
6469 ats->res.valid = GNUNET_NO;
6470 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->res);
6472 else if (ats->modified_resources)
6474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "RESSOURCE...modified problem\n");
6477 else if (ats->modified_quality)
6479 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "RESSOURCE...quality problem\n");
6483 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6486 if (ats->res.valid == GNUNET_YES)
6488 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->res.c_peers, ats->res.c_mechs, &ats->res);
6491 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6493 if ((ats->res.valid == GNUNET_YES))
6496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu %llu \n", res, duration.rel_value, ats->res.solution);
6498 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6499 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->res.c_mechs, GNUNET_NO);
6500 GNUNET_STATISTICS_set (stats, "ATS peers", ats->res.c_peers, GNUNET_NO);
6501 GNUNET_STATISTICS_set (stats, "ATS solution", ats->res.solution, GNUNET_NO);
6502 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6507 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6510 ats->last = GNUNET_TIME_absolute_get();
6512 ats->modified_addr = GNUNET_NO;
6513 ats->modified_resources = GNUNET_NO;
6514 ats->modified_quality = GNUNET_NO;
6520 ats_schedule_calculation (void *cls,
6521 const struct GNUNET_SCHEDULER_TaskContext *tc)
6523 struct ATS_info *ats = (struct ATS_info *) cls;
6527 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6528 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6535 ats_calculate_bandwidth_distribution (ats);
6537 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6538 &ats_schedule_calculation, ats);
6543 ats = GNUNET_malloc(sizeof (struct ATS_info));
6545 ats->min_delta = ATS_MIN_INTERVAL;
6546 ats->exec_intervall = ATS_EXEC_INTERVAL;
6547 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6548 ats->max_iterations = ATS_MAX_ITERATIONS;
6549 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6552 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active");
6559 ats->v_b_min = 64000;
6564 unsigned long long value;
6566 /* loading cost ressources */
6567 for (c=0; c<available_ressources; c++)
6569 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6570 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6572 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6577 ressources[c].c_max = value;
6580 GNUNET_free (section);
6581 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6582 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6584 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6589 ressources[c].c_min = value;
6592 GNUNET_free (section);
6595 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6596 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6598 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6599 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6601 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6605 void ats_shutdown ()
6608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6610 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6611 GNUNET_SCHEDULER_cancel(ats->ats_task);
6612 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6614 if (ats->prob != NULL)
6616 glp_delete_prob(ats->prob);
6624 void ats_notify_peer_connect (
6625 const struct GNUNET_PeerIdentity *peer,
6626 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6632 while (ntohl(ats_data[c].type)!=0)
6635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6640 ats->modified_addr = GNUNET_YES;
6642 ats_calculate_bandwidth_distribution(ats);
6645 void ats_notify_peer_disconnect (
6646 const struct GNUNET_PeerIdentity *peer)
6649 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6652 ats->modified_addr = GNUNET_YES;
6654 ats_calculate_bandwidth_distribution (ats);
6658 void ats_notify_ats_data (
6659 const struct GNUNET_PeerIdentity *peer,
6660 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6663 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6665 ats_calculate_bandwidth_distribution(ats);
6668 struct ForeignAddressList * ats_get_preferred_address (
6669 struct NeighbourList *n)
6672 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6674 struct ReadyList *next = n->plugins;
6675 while (next != NULL)
6678 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6682 return find_ready_address(n);
6686 * Initiate transport service.
6688 * @param cls closure
6689 * @param server the initialized server
6690 * @param c configuration to use
6694 struct GNUNET_SERVER_Handle *server,
6695 const struct GNUNET_CONFIGURATION_Handle *c)
6697 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6698 {&handle_start, NULL,
6699 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6700 {&handle_hello, NULL,
6701 GNUNET_MESSAGE_TYPE_HELLO, 0},
6702 {&handle_send, NULL,
6703 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6704 {&handle_request_connect, NULL,
6705 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6706 {&handle_set_quota, NULL,
6707 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6708 {&handle_address_lookup, NULL,
6709 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6711 {&handle_blacklist_init, NULL,
6712 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6713 {&handle_blacklist_reply, NULL,
6714 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6720 unsigned long long tneigh;
6724 stats = GNUNET_STATISTICS_create ("transport", cfg);
6725 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6726 /* parse configuration */
6728 GNUNET_CONFIGURATION_get_value_number (c,
6733 GNUNET_CONFIGURATION_get_value_filename (c,
6735 "HOSTKEY", &keyfile)))
6737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6739 ("Transport service is lacking key configuration settings. Exiting.\n"));
6740 GNUNET_SCHEDULER_shutdown ();
6743 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6746 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6747 validation_map = NULL;
6751 max_connect_per_transport = (uint32_t) tneigh;
6752 peerinfo = GNUNET_PEERINFO_connect (cfg);
6753 if (peerinfo == NULL)
6755 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6756 _("Could not access PEERINFO service. Exiting.\n"));
6757 GNUNET_SCHEDULER_shutdown ();
6760 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6763 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6764 validation_map = NULL;
6765 GNUNET_free (keyfile);
6768 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6769 GNUNET_free (keyfile);
6770 if (my_private_key == NULL)
6772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6774 ("Transport service could not access hostkey. Exiting.\n"));
6775 GNUNET_SCHEDULER_shutdown ();
6778 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6781 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6782 validation_map = NULL;
6785 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6786 GNUNET_CRYPTO_hash (&my_public_key,
6787 sizeof (my_public_key), &my_identity.hashPubKey);
6788 /* setup notification */
6789 GNUNET_SERVER_disconnect_notify (server,
6790 &client_disconnect_notification, NULL);
6791 /* load plugins... */
6794 GNUNET_CONFIGURATION_get_value_string (c,
6795 "TRANSPORT", "PLUGINS", &plugs))
6797 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6798 _("Starting transport plugins `%s'\n"), plugs);
6799 pos = strtok (plugs, " ");
6802 start_transport (server, pos);
6804 pos = strtok (NULL, " ");
6806 GNUNET_free (plugs);
6808 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6809 &shutdown_task, NULL);
6816 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6818 /* If we have a blacklist file, read from it */
6819 read_blacklist_file(cfg);
6820 /* process client requests */
6821 GNUNET_SERVER_add_handlers (server, handlers);
6826 * The main function for the transport service.
6828 * @param argc number of arguments from the command line
6829 * @param argv command line arguments
6830 * @return 0 ok, 1 on error
6833 main (int argc, char *const *argv)
6835 a2s (NULL, NULL, 0); /* make compiler happy */
6836 return (GNUNET_OK ==
6837 GNUNET_SERVICE_run (argc,
6840 GNUNET_SERVICE_OPTION_NONE,
6841 &run, NULL)) ? 0 : 1;
6844 /* end of gnunet-service-transport.c */