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 */
893 struct ATS_ressource_entry
895 /* index in ressources array */
897 /* depending ATSi parameter to calculcate limits */
906 /* index in ressources array */
908 /* depending ATSi parameter to calculcate limits */
910 /* cfg option to load limits */
917 /* cofficients for the specific plugins */
927 static struct ATS_ressource ressources[] =
929 /* FIXME: the coefficients for the specific plugins */
930 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
931 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
932 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
934 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
935 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
936 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
937 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
940 static int available_ressources = 3;
948 * Time of last execution
950 struct GNUNET_TIME_Absolute last;
952 * Minimum intervall between two executions
954 struct GNUNET_TIME_Relative min_delta;
956 * Regular intervall when execution is triggered
958 struct GNUNET_TIME_Relative exec_intervall;
960 * Maximum execution time per calculation
962 struct GNUNET_TIME_Relative max_exec_duration;
964 * Maximum number of LP iterations per calculation
972 * Ressource costs or quality metrics changed, update matrix
974 int modified_resources;
977 * Ressource costs or quality metrics changed, update matrix
979 int modified_quality;
982 * Peers have connected or disconnected, problem has to be recreated
992 GNUNET_SCHEDULER_TaskIdentifier ats_task;
994 struct ATS_result res;
999 struct ATS_mechanism * mechanisms;
1000 struct ATS_peer * peers;
1005 * Our HELLO message.
1007 static struct GNUNET_HELLO_Message *our_hello;
1012 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1017 static struct GNUNET_PeerIdentity my_identity;
1022 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1025 * Our configuration.
1027 const struct GNUNET_CONFIGURATION_Handle *cfg;
1030 * Linked list of all clients to this service.
1032 static struct TransportClient *clients;
1035 * All loaded plugins.
1037 static struct TransportPlugin *plugins;
1040 * Handle to peerinfo service.
1042 static struct GNUNET_PEERINFO_Handle *peerinfo;
1045 * All known neighbours and their HELLOs.
1047 static struct NeighbourList *neighbours;
1050 * Number of neighbours we'd like to have.
1052 static uint32_t max_connect_per_transport;
1055 * Head of linked list.
1057 static struct CheckHelloValidatedContext *chvc_head;
1060 * Tail of linked list.
1062 static struct CheckHelloValidatedContext *chvc_tail;
1065 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1066 * of the given peer that we are currently validating).
1068 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1071 * Handle for reporting statistics.
1073 static struct GNUNET_STATISTICS_Handle *stats;
1076 * Handle for ats information
1078 static struct ATS_info *ats;
1080 struct ATS_quality_entry
1088 static struct ATS_quality_metric qm[] =
1090 {1, 1028, "QUALITY_NET_DISTANCE"},
1091 {2, 1034, "QUALITY_NET_DELAY"},
1093 static int available_quality_metrics = 2;
1097 * The peer specified by the given neighbour has timed-out or a plugin
1098 * has disconnected. We may either need to do nothing (other plugins
1099 * still up), or trigger a full disconnect and clean up. This
1100 * function updates our state and do the necessary notifications.
1101 * Also notifies our clients that the neighbour is now officially
1104 * @param n the neighbour list entry for the peer
1105 * @param check should we just check if all plugins
1106 * disconnected or must we ask all plugins to
1109 static void disconnect_neighbour (struct NeighbourList *n, int check);
1112 * Check the ready list for the given neighbour and if a plugin is
1113 * ready for transmission (and if we have a message), do so!
1115 * @param nexi target peer for which to transmit
1117 static void try_transmission_to_peer (struct NeighbourList *n);
1119 static void ats_shutdown ( );
1121 static void ats_notify_peer_connect (
1122 const struct GNUNET_PeerIdentity *peer,
1123 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
1125 static void ats_notify_peer_disconnect (
1126 const struct GNUNET_PeerIdentity *peer);
1129 static void ats_notify_ats_data (
1130 const struct GNUNET_PeerIdentity *peer,
1131 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1134 struct ForeignAddressList * ats_get_preferred_address (
1135 struct NeighbourList *n);
1138 ats_calculate_bandwidth_distribution ();
1141 * Find an entry in the neighbour list for a particular peer.
1143 * @return NULL if not found.
1145 static struct NeighbourList *
1146 find_neighbour (const struct GNUNET_PeerIdentity *key)
1148 struct NeighbourList *head = neighbours;
1150 while ((head != NULL) &&
1151 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1156 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1159 int set = GNUNET_NO;
1160 for (c=0; c<available_quality_metrics; c++)
1162 if (ats_index == qm[c].atis_index)
1164 fal->quality[c].values[0] = fal->quality[c].values[1];
1165 fal->quality[c].values[1] = fal->quality[c].values[2];
1166 fal->quality[c].values[2] = value;
1168 ats->modified_quality = GNUNET_YES;
1171 if (set == GNUNET_NO)
1173 for (c=0; c<available_ressources; c++)
1175 if (ats_index == ressources[c].atis_index)
1177 fal->ressources[c].c = value;
1179 ats->modified_resources = GNUNET_YES;
1187 static int update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1191 for (c1=0; c1<ats_count; c1++)
1193 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1199 * Find an entry in the transport list for a particular transport.
1201 * @return NULL if not found.
1203 static struct TransportPlugin *
1204 find_transport (const char *short_name)
1206 struct TransportPlugin *head = plugins;
1207 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1213 * Is a particular peer blacklisted for a particular transport?
1215 * @param peer the peer to check for
1216 * @param plugin the plugin used to connect to the peer
1218 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1221 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1224 if (plugin->blacklist != NULL)
1226 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1230 "Peer `%s:%s' is blacklisted!\n",
1231 plugin->short_name, GNUNET_i2s (peer));
1234 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1244 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1246 struct TransportPlugin *plugin;
1248 plugin = find_transport(transport_name);
1249 if (plugin == NULL) /* Nothing to do */
1251 if (plugin->blacklist == NULL)
1252 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1253 GNUNET_assert(plugin->blacklist != NULL);
1254 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1256 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1261 * Read the blacklist file, containing transport:peer entries.
1262 * Provided the transport is loaded, set up hashmap with these
1263 * entries to blacklist peers by transport.
1267 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1274 struct GNUNET_PeerIdentity pid;
1276 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1277 unsigned int entries_found;
1278 char *transport_name;
1281 GNUNET_CONFIGURATION_get_value_filename (cfg,
1287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288 "Option `%s' in section `%s' not specified!\n",
1294 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1295 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1296 | GNUNET_DISK_PERM_USER_WRITE);
1297 if (0 != STAT (fn, &frstat))
1299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1300 _("Could not read blacklist file `%s'\n"), fn);
1304 if (frstat.st_size == 0)
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 _("Blacklist file `%s' is empty.\n"),
1314 /* FIXME: use mmap */
1315 data = GNUNET_malloc_large (frstat.st_size);
1316 GNUNET_assert(data != NULL);
1317 if (frstat.st_size !=
1318 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1321 _("Failed to read blacklist from `%s'\n"), fn);
1328 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1330 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1331 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1334 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1337 if (colon_pos >= frstat.st_size)
1339 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1340 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1341 (unsigned long long) colon_pos);
1347 if (isspace( (unsigned char) data[colon_pos]))
1349 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1350 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1351 (unsigned long long) colon_pos);
1353 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1357 tsize = colon_pos - pos;
1358 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1360 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1361 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1362 (unsigned long long) colon_pos);
1371 transport_name = GNUNET_malloc(tsize + 1);
1372 memcpy(transport_name, &data[pos], tsize);
1373 pos = colon_pos + 1;
1375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1376 "Read transport name %s in blacklist file.\n",
1379 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1380 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1382 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1383 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1384 (unsigned long long) pos);
1386 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1388 GNUNET_free_non_null(transport_name);
1391 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1392 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1394 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1395 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1396 (unsigned long long) pos,
1401 if (0 != memcmp (&pid,
1403 sizeof (struct GNUNET_PeerIdentity)))
1406 add_peer_to_blacklist (&pid,
1411 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1412 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1416 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1417 GNUNET_free_non_null(transport_name);
1418 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1421 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1428 * Function called to notify a client about the socket being ready to
1429 * queue more data. "buf" will be NULL and "size" zero if the socket
1430 * was closed for writing in the meantime.
1432 * @param cls closure
1433 * @param size number of bytes available in buf
1434 * @param buf where the callee should write the message
1435 * @return number of bytes written to buf
1438 transmit_to_client_callback (void *cls, size_t size, void *buf)
1440 struct TransportClient *client = cls;
1441 struct ClientMessageQueueEntry *q;
1444 const struct GNUNET_MessageHeader *msg;
1451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1452 "Transmission to client failed, closing connection.\n");
1454 /* fatal error with client, free message queue! */
1455 while (NULL != (q = client->message_queue_head))
1457 GNUNET_STATISTICS_update (stats,
1458 gettext_noop ("# bytes discarded (could not transmit to client)"),
1459 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1461 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1462 client->message_queue_tail,
1466 client->message_count = 0;
1471 while (NULL != (q = client->message_queue_head))
1473 msg = (const struct GNUNET_MessageHeader *) &q[1];
1474 msize = ntohs (msg->size);
1475 if (msize + tsize > size)
1478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1479 "Transmitting message of type %u to client.\n",
1482 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1483 client->message_queue_tail,
1485 memcpy (&cbuf[tsize], msg, msize);
1488 client->message_count--;
1492 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1493 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1495 GNUNET_TIME_UNIT_FOREVER_REL,
1496 &transmit_to_client_callback,
1498 GNUNET_assert (client->th != NULL);
1505 * Convert an address to a string.
1507 * @param plugin name of the plugin responsible for the address
1508 * @param addr binary address
1509 * @param addr_len number of bytes in addr
1510 * @return NULL on error, otherwise address string
1513 a2s (const char *plugin,
1517 struct TransportPlugin *p;
1521 p = find_transport (plugin);
1524 return p->api->address_to_string (p->api->cls,
1531 * Mark the given FAL entry as 'connected' (and hence preferred for
1532 * sending); also mark all others for the same peer as 'not connected'
1533 * (since only one can be preferred).
1535 * @param fal address to set to 'connected'
1538 mark_address_connected (struct ForeignAddressList *fal)
1540 struct ForeignAddressList *pos;
1543 GNUNET_assert (GNUNET_YES == fal->validated);
1544 if (fal->connected == GNUNET_YES)
1545 return; /* nothing to do */
1547 pos = fal->ready_list->addresses;
1550 if (GNUNET_YES == pos->connected)
1553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1554 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1555 a2s (pos->ready_list->plugin->short_name,
1559 GNUNET_break (cnt == GNUNET_YES);
1561 pos->connected = GNUNET_NO;
1562 GNUNET_STATISTICS_update (stats,
1563 gettext_noop ("# connected addresses"),
1569 fal->connected = GNUNET_YES;
1570 if (GNUNET_YES == cnt)
1572 GNUNET_STATISTICS_update (stats,
1573 gettext_noop ("# connected addresses"),
1581 * Send the specified message to the specified client. Since multiple
1582 * messages may be pending for the same client at a time, this code
1583 * makes sure that no message is lost.
1585 * @param client client to transmit the message to
1586 * @param msg the message to send
1587 * @param may_drop can this message be dropped if the
1588 * message queue for this client is getting far too large?
1591 transmit_to_client (struct TransportClient *client,
1592 const struct GNUNET_MessageHeader *msg, int may_drop)
1594 struct ClientMessageQueueEntry *q;
1597 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1599 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1601 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1604 client->message_count,
1606 GNUNET_STATISTICS_update (stats,
1607 gettext_noop ("# messages dropped due to slow client"),
1612 msize = ntohs (msg->size);
1613 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1614 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1615 memcpy (&q[1], msg, msize);
1616 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1617 client->message_queue_tail,
1618 client->message_queue_tail,
1620 client->message_count++;
1621 if (client->th == NULL)
1623 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1625 GNUNET_TIME_UNIT_FOREVER_REL,
1626 &transmit_to_client_callback,
1628 GNUNET_assert (client->th != NULL);
1634 * Transmit a 'SEND_OK' notification to the given client for the
1637 * @param client who to notify
1638 * @param n neighbour to notify about, can be NULL (on failure)
1639 * @param target target of the transmission
1640 * @param result status code for the transmission request
1643 transmit_send_ok (struct TransportClient *client,
1644 struct NeighbourList *n,
1645 const struct GNUNET_PeerIdentity *target,
1648 struct SendOkMessage send_ok_msg;
1650 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1651 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1652 send_ok_msg.success = htonl (result);
1654 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1656 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1657 send_ok_msg.peer = *target;
1658 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1663 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1664 * upon "completion" of a send request. This tells the API
1665 * that it is now legal to send another message to the given
1668 * @param cls closure, identifies the entry on the
1669 * message queue that was transmitted and the
1670 * client responsible for queuing the message
1671 * @param target the peer receiving the message
1672 * @param result GNUNET_OK on success, if the transmission
1673 * failed, we should not tell the client to transmit
1677 transmit_send_continuation (void *cls,
1678 const struct GNUNET_PeerIdentity *target,
1681 struct MessageQueue *mq = cls;
1682 struct NeighbourList *n;
1684 GNUNET_STATISTICS_update (stats,
1685 gettext_noop ("# bytes pending with plugins"),
1686 - (int64_t) mq->message_buf_size,
1688 if (result == GNUNET_OK)
1690 GNUNET_STATISTICS_update (stats,
1691 gettext_noop ("# bytes successfully transmitted by plugins"),
1692 mq->message_buf_size,
1697 GNUNET_STATISTICS_update (stats,
1698 gettext_noop ("# bytes with transmission failure by plugins"),
1699 mq->message_buf_size,
1702 if (mq->specific_address != NULL)
1704 if (result == GNUNET_OK)
1706 mq->specific_address->timeout =
1707 GNUNET_TIME_relative_to_absolute
1708 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1709 if (mq->specific_address->validated == GNUNET_YES)
1710 mark_address_connected (mq->specific_address);
1714 if (mq->specific_address->connected != GNUNET_NO)
1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1719 a2s (mq->specific_address->ready_list->plugin->short_name,
1720 mq->specific_address->addr,
1721 mq->specific_address->addrlen));
1723 GNUNET_STATISTICS_update (stats,
1724 gettext_noop ("# connected addresses"),
1727 mq->specific_address->connected = GNUNET_NO;
1730 if (! mq->internal_msg)
1731 mq->specific_address->in_transmit = GNUNET_NO;
1733 n = find_neighbour(&mq->neighbour_id);
1734 if (mq->client != NULL)
1735 transmit_send_ok (mq->client, n, target, result);
1738 try_transmission_to_peer (n);
1743 * Find an address in any of the available transports for
1744 * the given neighbour that would be good for message
1745 * transmission. This is essentially the transport selection
1748 * @param neighbour for whom to select an address
1749 * @return selected address, NULL if we have none
1751 struct ForeignAddressList *
1752 find_ready_address(struct NeighbourList *neighbour)
1754 struct ReadyList *head = neighbour->plugins;
1755 struct ForeignAddressList *addresses;
1756 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1757 struct ForeignAddressList *best_address;
1759 /* Hack to prefer unix domain sockets */
1760 struct ForeignAddressList *unix_address = NULL;
1762 best_address = NULL;
1763 while (head != NULL)
1765 addresses = head->addresses;
1766 while (addresses != NULL)
1768 if ( (addresses->timeout.abs_value < now.abs_value) &&
1769 (addresses->connected == GNUNET_YES) )
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773 "Marking long-time inactive connection to `%4s' as down.\n",
1774 GNUNET_i2s (&neighbour->id));
1776 GNUNET_STATISTICS_update (stats,
1777 gettext_noop ("# connected addresses"),
1780 addresses->connected = GNUNET_NO;
1782 addresses = addresses->next;
1785 addresses = head->addresses;
1786 while (addresses != NULL)
1788 #if DEBUG_TRANSPORT > 1
1789 if (addresses->addr != NULL)
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1792 a2s (head->plugin->short_name,
1794 addresses->addrlen),
1795 GNUNET_i2s (&neighbour->id),
1796 addresses->connected,
1797 addresses->in_transmit,
1798 addresses->validated,
1799 addresses->connect_attempts,
1800 (unsigned long long) addresses->timeout.abs_value,
1801 (unsigned int) addresses->distance);
1803 if (0==strcmp(head->plugin->short_name,"unix"))
1805 if ((unix_address == NULL) || ((unix_address != NULL) &&
1806 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1807 unix_address = addresses;
1809 if ( ( (best_address == NULL) ||
1810 (addresses->connected == GNUNET_YES) ||
1811 (best_address->connected == GNUNET_NO) ) &&
1812 (addresses->in_transmit == GNUNET_NO) &&
1813 ( (best_address == NULL) ||
1814 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1815 best_address = addresses;
1816 /* FIXME: also give lower-latency addresses that are not
1817 connected a chance some times... */
1818 addresses = addresses->next;
1820 if (unix_address != NULL)
1824 if (unix_address != NULL)
1826 best_address = unix_address;
1828 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1831 if (best_address != NULL)
1835 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1836 "Best address found (`%s') has latency of %llu ms.\n",
1837 (best_address->addrlen > 0)
1838 ? a2s (best_address->ready_list->plugin->short_name,
1840 best_address->addrlen)
1842 best_address->latency.rel_value);
1847 GNUNET_STATISTICS_update (stats,
1848 gettext_noop ("# transmission attempts failed (no address)"),
1853 return best_address;
1859 * We should re-try transmitting to the given peer,
1860 * hopefully we've learned something in the meantime.
1863 retry_transmission_task (void *cls,
1864 const struct GNUNET_SCHEDULER_TaskContext *tc)
1866 struct NeighbourList *n = cls;
1868 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1869 try_transmission_to_peer (n);
1874 * Check the ready list for the given neighbour and if a plugin is
1875 * ready for transmission (and if we have a message), do so!
1877 * @param neighbour target peer for which to transmit
1880 try_transmission_to_peer (struct NeighbourList *n)
1882 struct ReadyList *rl;
1883 struct MessageQueue *mq;
1884 struct GNUNET_TIME_Relative timeout;
1888 if (n->messages_head == NULL)
1891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1892 "Transmission queue for `%4s' is empty\n",
1893 GNUNET_i2s (&n->id));
1895 return; /* nothing to do */
1898 mq = n->messages_head;
1899 force_address = GNUNET_YES;
1900 if (mq->specific_address == NULL)
1903 mq->specific_address = ats_get_preferred_address(n);
1904 GNUNET_STATISTICS_update (stats,
1905 gettext_noop ("# transport selected peer address freely"),
1908 force_address = GNUNET_NO;
1910 if (mq->specific_address == NULL)
1912 GNUNET_STATISTICS_update (stats,
1913 gettext_noop ("# transport failed to selected peer address"),
1916 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1917 if (timeout.rel_value == 0)
1920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1921 "No destination address available to transmit message of size %u to peer `%4s'\n",
1922 mq->message_buf_size,
1923 GNUNET_i2s (&mq->neighbour_id));
1925 GNUNET_STATISTICS_update (stats,
1926 gettext_noop ("# bytes in message queue for other peers"),
1927 - (int64_t) mq->message_buf_size,
1929 GNUNET_STATISTICS_update (stats,
1930 gettext_noop ("# bytes discarded (no destination address available)"),
1931 mq->message_buf_size,
1933 if (mq->client != NULL)
1934 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1935 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1939 return; /* nobody ready */
1941 GNUNET_STATISTICS_update (stats,
1942 gettext_noop ("# message delivery deferred (no address)"),
1945 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1946 GNUNET_SCHEDULER_cancel (n->retry_task);
1947 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1948 &retry_transmission_task,
1951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1952 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1953 mq->message_buf_size,
1954 GNUNET_i2s (&mq->neighbour_id),
1957 /* FIXME: might want to trigger peerinfo lookup here
1958 (unless that's already pending...) */
1961 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1964 if (mq->specific_address->connected == GNUNET_NO)
1965 mq->specific_address->connect_attempts++;
1966 rl = mq->specific_address->ready_list;
1967 mq->plugin = rl->plugin;
1968 if (!mq->internal_msg)
1969 mq->specific_address->in_transmit = GNUNET_YES;
1971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1972 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1973 mq->message_buf_size,
1974 GNUNET_i2s (&n->id),
1975 (mq->specific_address->addr != NULL)
1976 ? a2s (mq->plugin->short_name,
1977 mq->specific_address->addr,
1978 mq->specific_address->addrlen)
1980 rl->plugin->short_name);
1982 GNUNET_STATISTICS_update (stats,
1983 gettext_noop ("# bytes in message queue for other peers"),
1984 - (int64_t) mq->message_buf_size,
1986 GNUNET_STATISTICS_update (stats,
1987 gettext_noop ("# bytes pending with plugins"),
1988 mq->message_buf_size,
1990 ret = rl->plugin->api->send (rl->plugin->api->cls,
1993 mq->message_buf_size,
1995 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1996 mq->specific_address->session,
1997 mq->specific_address->addr,
1998 mq->specific_address->addrlen,
2000 &transmit_send_continuation, mq);
2003 /* failure, but 'send' would not call continuation in this case,
2004 so we need to do it here! */
2005 transmit_send_continuation (mq,
2013 * Send the specified message to the specified peer.
2015 * @param client source of the transmission request (can be NULL)
2016 * @param peer_address ForeignAddressList where we should send this message
2017 * @param priority how important is the message
2018 * @param timeout how long do we have to transmit?
2019 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
2020 * @param message_buf_size total size of all messages in message_buf
2021 * @param is_internal is this an internal message; these are pre-pended and
2022 * also do not count for plugins being "ready" to transmit
2023 * @param neighbour handle to the neighbour for transmission
2026 transmit_to_peer (struct TransportClient *client,
2027 struct ForeignAddressList *peer_address,
2028 unsigned int priority,
2029 struct GNUNET_TIME_Relative timeout,
2030 const char *message_buf,
2031 size_t message_buf_size,
2032 int is_internal, struct NeighbourList *neighbour)
2034 struct MessageQueue *mq;
2039 /* check for duplicate submission */
2040 mq = neighbour->messages_head;
2043 if (mq->client == client)
2045 /* client transmitted to same peer twice
2046 before getting SEND_OK! */
2054 GNUNET_STATISTICS_update (stats,
2055 gettext_noop ("# bytes in message queue for other peers"),
2058 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2059 mq->specific_address = peer_address;
2060 mq->client = client;
2061 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2062 memcpy (&mq[1], message_buf, message_buf_size);
2063 mq->message_buf = (const char*) &mq[1];
2064 mq->message_buf_size = message_buf_size;
2065 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2066 mq->internal_msg = is_internal;
2067 mq->priority = priority;
2068 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2070 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2071 neighbour->messages_tail,
2074 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2075 neighbour->messages_tail,
2076 neighbour->messages_tail,
2078 try_transmission_to_peer (neighbour);
2085 struct GeneratorContext
2087 struct TransportPlugin *plug_pos;
2088 struct OwnAddressList *addr_pos;
2089 struct GNUNET_TIME_Absolute expiration;
2097 address_generator (void *cls, size_t max, void *buf)
2099 struct GeneratorContext *gc = cls;
2102 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2104 gc->plug_pos = gc->plug_pos->next;
2105 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2107 if (NULL == gc->plug_pos)
2112 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2115 gc->addr_pos->addrlen, buf, max);
2116 gc->addr_pos = gc->addr_pos->next;
2122 * Construct our HELLO message from all of the addresses of
2123 * all of the transports.
2128 struct GNUNET_HELLO_Message *hello;
2129 struct TransportClient *cpos;
2130 struct NeighbourList *npos;
2131 struct GeneratorContext gc;
2133 gc.plug_pos = plugins;
2134 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2135 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2136 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2139 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2141 GNUNET_STATISTICS_update (stats,
2142 gettext_noop ("# refreshed my HELLO"),
2146 while (cpos != NULL)
2148 transmit_to_client (cpos,
2149 (const struct GNUNET_MessageHeader *) hello,
2154 GNUNET_free_non_null (our_hello);
2156 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2158 while (npos != NULL)
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2162 "Transmitting updated `%s' to neighbour `%4s'\n",
2163 "HELLO", GNUNET_i2s (&npos->id));
2165 GNUNET_STATISTICS_update (stats,
2166 gettext_noop ("# transmitted my HELLO to other peers"),
2169 transmit_to_peer (NULL, NULL, 0,
2170 HELLO_ADDRESS_EXPIRATION,
2171 (const char *) our_hello,
2172 GNUNET_HELLO_size(our_hello),
2180 * Task used to clean up expired addresses for a plugin.
2182 * @param cls closure
2186 expire_address_task (void *cls,
2187 const struct GNUNET_SCHEDULER_TaskContext *tc);
2191 * Update the list of addresses for this plugin,
2192 * expiring those that are past their expiration date.
2194 * @param plugin addresses of which plugin should be recomputed?
2195 * @param fresh set to GNUNET_YES if a new address was added
2196 * and we need to regenerate the HELLO even if nobody
2200 update_addresses (struct TransportPlugin *plugin,
2203 static struct GNUNET_TIME_Absolute last_update;
2204 struct GNUNET_TIME_Relative min_remaining;
2205 struct GNUNET_TIME_Relative remaining;
2206 struct GNUNET_TIME_Absolute now;
2207 struct OwnAddressList *pos;
2208 struct OwnAddressList *prev;
2209 struct OwnAddressList *next;
2212 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2213 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2214 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2215 now = GNUNET_TIME_absolute_get ();
2216 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2217 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2219 pos = plugin->addresses;
2223 if (pos->expires.abs_value < now.abs_value)
2225 expired = GNUNET_YES;
2227 plugin->addresses = pos->next;
2229 prev->next = pos->next;
2234 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2235 if (remaining.rel_value < min_remaining.rel_value)
2236 min_remaining = remaining;
2242 if (expired || fresh)
2247 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2248 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2250 plugin->address_update_task
2251 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2252 &expire_address_task, plugin);
2257 * Task used to clean up expired addresses for a plugin.
2259 * @param cls closure
2263 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2265 struct TransportPlugin *plugin = cls;
2267 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2268 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2269 update_addresses (plugin, GNUNET_NO);
2274 * Iterator over hash map entries that NULLs the session of validation
2275 * entries that match the given session.
2277 * @param cls closure (the 'struct Session*' to match against)
2278 * @param key current key code (peer ID, not used)
2279 * @param value value in the hash map ('struct ValidationEntry*')
2280 * @return GNUNET_YES (we should continue to iterate)
2283 remove_session_validations (void *cls,
2284 const GNUNET_HashCode * key,
2287 struct Session *session = cls;
2288 struct ValidationEntry *ve = value;
2290 if (session == ve->session)
2297 * We've been disconnected from the other peer (for some
2298 * connection-oriented transport). Either quickly
2299 * re-establish the connection or signal the disconnect
2302 * Only signal CORE level disconnect if ALL addresses
2303 * for the peer are exhausted.
2305 * @param p overall plugin context
2306 * @param nl neighbour that was disconnected
2309 try_fast_reconnect (struct TransportPlugin *p,
2310 struct NeighbourList *nl)
2312 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2313 /* Note: the idea here is to hide problems with transports (or
2314 switching between plugins) from the core to eliminate the need to
2315 re-negotiate session keys and the like; OTOH, we should tell core
2316 quickly (much faster than timeout) `if a connection was lost and
2317 could not be re-established (i.e. other peer went down or is
2318 unable / refuses to communicate);
2320 So we should consider:
2321 1) ideally: our own willingness / need to connect
2322 2) prior failures to connect to this peer (by plugin)
2323 3) ideally: reasons why other peer terminated (as far as knowable)
2325 Most importantly, it must be POSSIBLE for another peer to terminate
2326 a connection for a while (without us instantly re-establishing it).
2327 Similarly, if another peer is gone we should quickly notify CORE.
2328 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2329 on the other end), we should reconnect in such a way that BOTH CORE
2330 services never even notice.
2331 Furthermore, the same mechanism (or small variation) could be used
2332 to switch to a better-performing plugin (ATS).
2334 Finally, this needs to be tested throughly... */
2337 * GNUNET_NO in the call below makes transport disconnect the peer,
2338 * even if only a single address (out of say, six) went away. This
2339 * function must be careful to ONLY disconnect if the peer is gone,
2340 * not just a specifi address.
2342 * More specifically, half the places it was used had it WRONG.
2345 /* No reconnect, signal disconnect instead! */
2346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2347 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2348 "try_fast_reconnect");
2349 disconnect_neighbour (nl, GNUNET_YES);
2354 * Function that will be called whenever the plugin internally
2355 * cleans up a session pointer and hence the service needs to
2356 * discard all of those sessions as well. Plugins that do not
2357 * use sessions can simply omit calling this function and always
2358 * use NULL wherever a session pointer is needed.
2360 * @param cls closure
2361 * @param peer which peer was the session for
2362 * @param session which session is being destoyed
2365 plugin_env_session_end (void *cls,
2366 const struct GNUNET_PeerIdentity *peer,
2367 struct Session *session)
2369 struct TransportPlugin *p = cls;
2370 struct NeighbourList *nl;
2371 struct ReadyList *rl;
2372 struct ForeignAddressList *pos;
2373 struct ForeignAddressList *prev;
2375 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2376 &remove_session_validations,
2378 nl = find_neighbour (peer);
2380 return; /* was never marked as connected */
2384 if (rl->plugin == p)
2389 return; /* was never marked as connected */
2391 pos = rl->addresses;
2392 while ( (pos != NULL) &&
2393 (pos->session != session) )
2399 return; /* was never marked as connected */
2400 pos->session = NULL;
2401 if (pos->addrlen != 0)
2403 if (nl->received_pong != GNUNET_NO)
2404 try_fast_reconnect (p, nl);
2407 /* was inbound connection, free 'pos' */
2409 rl->addresses = pos->next;
2411 prev->next = pos->next;
2412 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2414 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2415 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2418 if (nl->received_pong == GNUNET_NO)
2419 return; /* nothing to do, never connected... */
2420 /* check if we have any validated addresses left */
2421 pos = rl->addresses;
2426 try_fast_reconnect (p, nl);
2431 /* no valid addresses left, signal disconnect! */
2433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2434 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2435 "plugin_env_session_end");
2436 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2437 * it means there aren't any left for this PLUGIN/PEER combination! So
2438 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2439 * when it isn't necessary. Using GNUNET_YES at least checks to see
2440 * if there are any addresses that work first, so as not to overdo it.
2443 disconnect_neighbour (nl, GNUNET_YES);
2448 * Function that must be called by each plugin to notify the
2449 * transport service about the addresses under which the transport
2450 * provided by the plugin can be reached.
2452 * @param cls closure
2453 * @param name name of the transport that generated the address
2454 * @param addr one of the addresses of the host, NULL for the last address
2455 * the specific address format depends on the transport
2456 * @param addrlen length of the address
2457 * @param expires when should this address automatically expire?
2460 plugin_env_notify_address (void *cls,
2464 struct GNUNET_TIME_Relative expires)
2466 struct TransportPlugin *p = cls;
2467 struct OwnAddressList *al;
2468 struct GNUNET_TIME_Absolute abex;
2470 GNUNET_assert (addr != NULL);
2471 abex = GNUNET_TIME_relative_to_absolute (expires);
2472 GNUNET_assert (p == find_transport (name));
2476 if ( (addrlen == al->addrlen) &&
2477 (0 == memcmp (addr, &al[1], addrlen)) )
2480 update_addresses (p, GNUNET_NO);
2485 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2486 al->next = p->addresses;
2489 al->addrlen = addrlen;
2490 memcpy (&al[1], addr, addrlen);
2491 update_addresses (p, GNUNET_YES);
2496 * Notify all of our clients about a peer connecting.
2499 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2500 struct GNUNET_TIME_Relative latency,
2503 struct ConnectInfoMessage * cim;
2504 struct TransportClient *cpos;
2509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2510 "Notifying clients about connection from `%s'\n",
2513 GNUNET_STATISTICS_update (stats,
2514 gettext_noop ("# peers connected"),
2519 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2520 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2524 cim = GNUNET_malloc (size);
2526 cim->header.size = htons (size);
2527 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2528 cim->ats_count = htonl(2);
2529 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2530 (&(cim->ats))[0].value = htonl (distance);
2531 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2532 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2533 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2534 (&(cim->ats))[2].value = htonl (0);
2535 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2537 /* notify ats about connecting peer */
2538 ats_notify_peer_connect (peer, &(cim->ats), 2);
2541 while (cpos != NULL)
2543 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2552 * Notify all of our clients about a peer disconnecting.
2555 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2557 struct DisconnectInfoMessage dim;
2558 struct TransportClient *cpos;
2561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2562 "Notifying clients about lost connection to `%s'\n",
2565 GNUNET_STATISTICS_update (stats,
2566 gettext_noop ("# peers connected"),
2569 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2570 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2571 dim.reserved = htonl (0);
2572 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2574 /* notify ats about connecting peer */
2575 ats_notify_peer_disconnect (peer);
2578 while (cpos != NULL)
2580 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2587 * Find a ForeignAddressList entry for the given neighbour
2588 * that matches the given address and transport.
2590 * @param neighbour which peer we care about
2591 * @param tname name of the transport plugin
2592 * @param session session to look for, NULL for 'any'; otherwise
2593 * can be used for the service to "learn" this session ID
2595 * @param addr binary address
2596 * @param addrlen length of addr
2597 * @return NULL if no such entry exists
2599 static struct ForeignAddressList *
2600 find_peer_address(struct NeighbourList *neighbour,
2602 struct Session *session,
2606 struct ReadyList *head;
2607 struct ForeignAddressList *pos;
2609 head = neighbour->plugins;
2610 while (head != NULL)
2612 if (0 == strcmp (tname, head->plugin->short_name))
2618 pos = head->addresses;
2619 while ( (pos != NULL) &&
2620 ( (pos->addrlen != addrlen) ||
2621 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2623 if ( (session != NULL) &&
2624 (pos->session == session) )
2628 if ( (session != NULL) && (pos != NULL) )
2629 pos->session = session; /* learn it! */
2635 * Get the peer address struct for the given neighbour and
2636 * address. If it doesn't yet exist, create it.
2638 * @param neighbour which peer we care about
2639 * @param tname name of the transport plugin
2640 * @param session session of the plugin, or NULL for none
2641 * @param addr binary address
2642 * @param addrlen length of addr
2643 * @return NULL if we do not have a transport plugin for 'tname'
2645 static struct ForeignAddressList *
2646 add_peer_address (struct NeighbourList *neighbour,
2648 struct Session *session,
2652 struct ReadyList *head;
2653 struct ForeignAddressList *ret;
2656 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2659 head = neighbour->plugins;
2661 while (head != NULL)
2663 if (0 == strcmp (tname, head->plugin->short_name))
2669 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2670 ret->session = session;
2671 if ((addrlen > 0) && (addr != NULL))
2673 ret->addr = (const char*) &ret[1];
2674 memcpy (&ret[1], addr, addrlen);
2681 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2683 for (c=0; c<available_ressources; c++)
2685 struct ATS_ressource_entry *r = ret->ressources;
2687 r[c].atis_index = ressources[c].atis_index;
2688 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2690 r[c].c = ressources[c].c_unix;
2693 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2695 r[c].c = ressources[c].c_udp;
2698 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2700 r[c].c = ressources[c].c_tcp;
2703 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2705 r[c].c = ressources[c].c_http;
2708 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2710 r[c].c = ressources[c].c_https;
2713 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2715 r[c].c = ressources[c].c_wlan;
2721 r[c].c = ressources[c].c_default;
2722 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2723 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2727 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2728 ret->addrlen = addrlen;
2729 ret->expires = GNUNET_TIME_relative_to_absolute
2730 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2731 ret->latency = GNUNET_TIME_relative_get_forever();
2733 ret->timeout = GNUNET_TIME_relative_to_absolute
2734 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2735 ret->ready_list = head;
2736 ret->next = head->addresses;
2737 head->addresses = ret;
2743 * Closure for 'add_validated_address'.
2745 struct AddValidatedAddressContext
2748 * Entry that has been validated.
2750 const struct ValidationEntry *ve;
2753 * Flag set after we have added the address so
2754 * that we terminate the iteration next time.
2761 * Callback function used to fill a buffer of max bytes with a list of
2762 * addresses in the format used by HELLOs. Should use
2763 * "GNUNET_HELLO_add_address" as a helper function.
2765 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2766 * @param max maximum number of bytes that can be written to buf
2767 * @param buf where to write the address information
2768 * @return number of bytes written, 0 to signal the
2769 * end of the iteration.
2772 add_validated_address (void *cls,
2773 size_t max, void *buf)
2775 struct AddValidatedAddressContext *avac = cls;
2776 const struct ValidationEntry *ve = avac->ve;
2778 if (GNUNET_YES == avac->done)
2780 avac->done = GNUNET_YES;
2781 return GNUNET_HELLO_add_address (ve->transport_name,
2782 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2792 * Closure for 'check_address_exists'.
2794 struct CheckAddressExistsClosure
2797 * Address to check for.
2802 * Name of the transport.
2809 struct Session *session;
2812 * Set to GNUNET_YES if the address exists.
2825 * Iterator over hash map entries. Checks if the given
2826 * validation entry is for the same address as what is given
2829 * @param cls the 'struct CheckAddressExistsClosure*'
2830 * @param key current key code (ignored)
2831 * @param value value in the hash map ('struct ValidationEntry')
2832 * @return GNUNET_YES if we should continue to
2833 * iterate (mismatch), GNUNET_NO if not (entry matched)
2836 check_address_exists (void *cls,
2837 const GNUNET_HashCode * key,
2840 struct CheckAddressExistsClosure *caec = cls;
2841 struct ValidationEntry *ve = value;
2843 if ( (0 == strcmp (caec->tname,
2844 ve->transport_name)) &&
2845 (caec->addrlen == ve->addrlen) &&
2846 (0 == memcmp (caec->addr,
2850 caec->exists = GNUNET_YES;
2853 if ( (ve->session != NULL) &&
2854 (caec->session == ve->session) )
2856 caec->exists = GNUNET_YES;
2865 * Iterator to free entries in the validation_map.
2867 * @param cls closure (unused)
2868 * @param key current key code
2869 * @param value value in the hash map (validation to abort)
2870 * @return GNUNET_YES (always)
2873 abort_validation (void *cls,
2874 const GNUNET_HashCode * key,
2877 struct ValidationEntry *va = value;
2879 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2880 GNUNET_SCHEDULER_cancel (va->timeout_task);
2881 GNUNET_free (va->transport_name);
2882 if (va->chvc != NULL)
2884 va->chvc->ve_count--;
2885 if (va->chvc->ve_count == 0)
2887 GNUNET_CONTAINER_DLL_remove (chvc_head,
2890 GNUNET_free (va->chvc);
2900 * HELLO validation cleanup task (validation failed).
2902 * @param cls the 'struct ValidationEntry' that failed
2903 * @param tc scheduler context (unused)
2906 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2908 struct ValidationEntry *va = cls;
2909 struct GNUNET_PeerIdentity pid;
2911 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2912 GNUNET_STATISTICS_update (stats,
2913 gettext_noop ("# address validation timeouts"),
2916 GNUNET_CRYPTO_hash (&va->publicKey,
2918 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2920 GNUNET_break (GNUNET_OK ==
2921 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2924 abort_validation (NULL, NULL, va);
2929 neighbour_timeout_task (void *cls,
2930 const struct GNUNET_SCHEDULER_TaskContext *tc)
2932 struct NeighbourList *n = cls;
2935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2936 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2938 GNUNET_STATISTICS_update (stats,
2939 gettext_noop ("# disconnects due to timeout"),
2942 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2943 disconnect_neighbour (n, GNUNET_NO);
2948 * Schedule the job that will cause us to send a PING to the
2949 * foreign address to evaluate its validity and latency.
2951 * @param fal address to PING
2954 schedule_next_ping (struct ForeignAddressList *fal);
2958 * Add the given address to the list of foreign addresses
2959 * available for the given peer (check for duplicates).
2961 * @param cls the respective 'struct NeighbourList' to update
2962 * @param tname name of the transport
2963 * @param expiration expiration time
2964 * @param addr the address
2965 * @param addrlen length of the address
2966 * @return GNUNET_OK (always)
2969 add_to_foreign_address_list (void *cls,
2971 struct GNUNET_TIME_Absolute expiration,
2975 struct NeighbourList *n = cls;
2976 struct ForeignAddressList *fal;
2979 GNUNET_STATISTICS_update (stats,
2980 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2984 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2987 #if DEBUG_TRANSPORT_HELLO
2988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2989 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2990 a2s (tname, addr, addrlen),
2992 GNUNET_i2s (&n->id),
2993 expiration.abs_value);
2995 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2998 GNUNET_STATISTICS_update (stats,
2999 gettext_noop ("# previously validated addresses lacking transport"),
3005 fal->expires = GNUNET_TIME_absolute_max (expiration,
3007 schedule_next_ping (fal);
3013 fal->expires = GNUNET_TIME_absolute_max (expiration,
3018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3019 "Failed to add new address for `%4s'\n",
3020 GNUNET_i2s (&n->id));
3023 if (fal->validated == GNUNET_NO)
3025 fal->validated = GNUNET_YES;
3026 GNUNET_STATISTICS_update (stats,
3027 gettext_noop ("# peer addresses considered valid"),
3031 if (try == GNUNET_YES)
3033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3034 "Have new addresses, will try to trigger transmissions.\n");
3035 try_transmission_to_peer (n);
3042 * Add addresses in validated HELLO "h" to the set of addresses
3043 * we have for this peer.
3045 * @param cls closure ('struct NeighbourList*')
3046 * @param peer id of the peer, NULL for last call
3047 * @param h hello message for the peer (can be NULL)
3048 * @param err_msg NULL if successful, otherwise contains error message
3051 add_hello_for_peer (void *cls,
3052 const struct GNUNET_PeerIdentity *peer,
3053 const struct GNUNET_HELLO_Message *h,
3054 const char *err_msg)
3056 struct NeighbourList *n = cls;
3058 if (err_msg != NULL)
3060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3061 _("Error in communication with PEERINFO service\n"));
3066 GNUNET_STATISTICS_update (stats,
3067 gettext_noop ("# outstanding peerinfo iterate requests"),
3074 return; /* no HELLO available */
3076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3077 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3081 if (GNUNET_YES != n->public_key_valid)
3083 GNUNET_HELLO_get_key (h, &n->publicKey);
3084 n->public_key_valid = GNUNET_YES;
3086 GNUNET_HELLO_iterate_addresses (h,
3088 &add_to_foreign_address_list,
3094 * Create a fresh entry in our neighbour list for the given peer.
3095 * Will try to transmit our current HELLO to the new neighbour.
3096 * Do not call this function directly, use 'setup_peer_check_blacklist.
3098 * @param peer the peer for which we create the entry
3099 * @param do_hello should we schedule transmitting a HELLO
3100 * @return the new neighbour list entry
3102 static struct NeighbourList *
3103 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3106 struct NeighbourList *n;
3107 struct TransportPlugin *tp;
3108 struct ReadyList *rl;
3111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3112 "Setting up state for neighbour `%4s'\n",
3115 GNUNET_assert (our_hello != NULL);
3116 GNUNET_STATISTICS_update (stats,
3117 gettext_noop ("# active neighbours"),
3120 n = GNUNET_malloc (sizeof (struct NeighbourList));
3121 n->next = neighbours;
3125 GNUNET_TIME_relative_to_absolute
3126 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3127 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3128 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3129 MAX_BANDWIDTH_CARRY_S);
3133 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3135 rl = GNUNET_malloc (sizeof (struct ReadyList));
3137 rl->next = n->plugins;
3140 rl->addresses = NULL;
3144 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3146 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3147 &neighbour_timeout_task, n);
3150 GNUNET_STATISTICS_update (stats,
3151 gettext_noop ("# peerinfo new neighbor iterate requests"),
3154 GNUNET_STATISTICS_update (stats,
3155 gettext_noop ("# outstanding peerinfo iterate requests"),
3158 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3159 GNUNET_TIME_UNIT_FOREVER_REL,
3160 &add_hello_for_peer, n);
3162 GNUNET_STATISTICS_update (stats,
3163 gettext_noop ("# HELLO's sent to new neighbors"),
3166 transmit_to_peer (NULL, NULL, 0,
3167 HELLO_ADDRESS_EXPIRATION,
3168 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3176 * Function called after we have checked if communicating
3177 * with a given peer is acceptable.
3179 * @param cls closure
3180 * @param n NULL if communication is not acceptable
3182 typedef void (*SetupContinuation)(void *cls,
3183 struct NeighbourList *n);
3187 * Information kept for each client registered to perform
3193 * This is a linked list.
3195 struct Blacklisters *next;
3198 * This is a linked list.
3200 struct Blacklisters *prev;
3203 * Client responsible for this entry.
3205 struct GNUNET_SERVER_Client *client;
3208 * Blacklist check that we're currently performing.
3210 struct BlacklistCheck *bc;
3216 * Head of DLL of blacklisting clients.
3218 static struct Blacklisters *bl_head;
3221 * Tail of DLL of blacklisting clients.
3223 static struct Blacklisters *bl_tail;
3227 * Context we use when performing a blacklist check.
3229 struct BlacklistCheck
3233 * This is a linked list.
3235 struct BlacklistCheck *next;
3238 * This is a linked list.
3240 struct BlacklistCheck *prev;
3243 * Peer being checked.
3245 struct GNUNET_PeerIdentity peer;
3248 * Option for setup neighbour afterwards.
3253 * Continuation to call with the result.
3255 SetupContinuation cont;
3263 * Current transmission request handle for this client, or NULL if no
3264 * request is pending.
3266 struct GNUNET_CONNECTION_TransmitHandle *th;
3269 * Our current position in the blacklisters list.
3271 struct Blacklisters *bl_pos;
3274 * Current task performing the check.
3276 GNUNET_SCHEDULER_TaskIdentifier task;
3281 * Head of DLL of active blacklisting queries.
3283 static struct BlacklistCheck *bc_head;
3286 * Tail of DLL of active blacklisting queries.
3288 static struct BlacklistCheck *bc_tail;
3292 * Perform next action in the blacklist check.
3294 * @param cls the 'struct BlacklistCheck*'
3298 do_blacklist_check (void *cls,
3299 const struct GNUNET_SCHEDULER_TaskContext *tc);
3302 * Transmit blacklist query to the client.
3304 * @param cls the 'struct BlacklistCheck'
3305 * @param size number of bytes allowed
3306 * @param buf where to copy the message
3307 * @return number of bytes copied to buf
3310 transmit_blacklist_message (void *cls,
3314 struct BlacklistCheck *bc = cls;
3315 struct Blacklisters *bl;
3316 struct BlacklistMessage bm;
3321 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3322 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3327 bm.header.size = htons (sizeof (struct BlacklistMessage));
3328 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3329 bm.is_allowed = htonl (0);
3331 memcpy (buf, &bm, sizeof (bm));
3332 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3338 * Perform next action in the blacklist check.
3340 * @param cls the 'struct BlacklistCheck*'
3344 do_blacklist_check (void *cls,
3345 const struct GNUNET_SCHEDULER_TaskContext *tc)
3347 struct BlacklistCheck *bc = cls;
3348 struct Blacklisters *bl;
3350 bc->task = GNUNET_SCHEDULER_NO_TASK;
3354 bc->cont (bc->cont_cls,
3355 setup_new_neighbour (&bc->peer, bc->do_hello));
3362 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3363 sizeof (struct BlacklistMessage),
3364 GNUNET_TIME_UNIT_FOREVER_REL,
3365 &transmit_blacklist_message,
3372 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3373 * does not yet exist, check the blacklist. If the blacklist says creating
3374 * one is acceptable, create one and call the continuation; otherwise
3375 * call the continuation with NULL.
3377 * @param peer peer to setup or look up a struct NeighbourList for
3378 * @param do_hello should we also schedule sending our HELLO to the peer
3379 * if this is a new record
3380 * @param cont function to call with the 'struct NeigbhbourList*'
3381 * @param cont_cls closure for cont
3384 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3386 SetupContinuation cont,
3389 struct NeighbourList *n;
3390 struct BlacklistCheck *bc;
3392 n = find_neighbour(peer);
3399 if (bl_head == NULL)
3402 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3404 setup_new_neighbour(peer, do_hello);
3407 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3408 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3410 bc->do_hello = do_hello;
3412 bc->cont_cls = cont_cls;
3413 bc->bl_pos = bl_head;
3414 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3420 * Function called with the result of querying a new blacklister about
3421 * it being allowed (or not) to continue to talk to an existing neighbour.
3423 * @param cls the original 'struct NeighbourList'
3424 * @param n NULL if we need to disconnect
3427 confirm_or_drop_neighbour (void *cls,
3428 struct NeighbourList *n)
3430 struct NeighbourList * orig = cls;
3434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3435 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3436 "confirm_or_drop_neighboUr");
3437 disconnect_neighbour (orig, GNUNET_NO);
3443 * Handle a request to start a blacklist.
3445 * @param cls closure (always NULL)
3446 * @param client identification of the client
3447 * @param message the actual message
3450 handle_blacklist_init (void *cls,
3451 struct GNUNET_SERVER_Client *client,
3452 const struct GNUNET_MessageHeader *message)
3454 struct Blacklisters *bl;
3455 struct BlacklistCheck *bc;
3456 struct NeighbourList *n;
3461 if (bl->client == client)
3464 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3469 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3470 bl->client = client;
3471 GNUNET_SERVER_client_keep (client);
3472 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3473 /* confirm that all existing connections are OK! */
3477 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3478 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3480 bc->do_hello = GNUNET_NO;
3481 bc->cont = &confirm_or_drop_neighbour;
3484 if (n == neighbours) /* all would wait for the same client, no need to
3485 create more than just the first task right now */
3486 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3494 * Handle a request to blacklist a peer.
3496 * @param cls closure (always NULL)
3497 * @param client identification of the client
3498 * @param message the actual message
3501 handle_blacklist_reply (void *cls,
3502 struct GNUNET_SERVER_Client *client,
3503 const struct GNUNET_MessageHeader *message)
3505 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3506 struct Blacklisters *bl;
3507 struct BlacklistCheck *bc;
3510 while ( (bl != NULL) &&
3511 (bl->client != client) )
3515 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3520 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3522 bc->cont (bc->cont_cls, NULL);
3523 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3528 bc->bl_pos = bc->bl_pos->next;
3529 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3532 /* check if any other bc's are waiting for this blacklister */
3536 if ( (bc->bl_pos == bl) &&
3537 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3538 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3546 * Send periodic PING messages to a given foreign address.
3548 * @param cls our 'struct PeriodicValidationContext*'
3549 * @param tc task context
3552 send_periodic_ping (void *cls,
3553 const struct GNUNET_SCHEDULER_TaskContext *tc)
3555 struct ForeignAddressList *peer_address = cls;
3556 struct TransportPlugin *tp;
3557 struct ValidationEntry *va;
3558 struct NeighbourList *neighbour;
3559 struct TransportPingMessage ping;
3560 struct CheckAddressExistsClosure caec;
3562 uint16_t hello_size;
3566 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3567 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3569 tp = peer_address->ready_list->plugin;
3570 neighbour = peer_address->ready_list->neighbour;
3571 if (GNUNET_YES != neighbour->public_key_valid)
3573 /* no public key yet, try again later */
3574 schedule_next_ping (peer_address);
3577 caec.addr = peer_address->addr;
3578 caec.addrlen = peer_address->addrlen;
3579 caec.tname = tp->short_name;
3580 caec.session = peer_address->session;
3581 caec.exists = GNUNET_NO;
3582 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3583 &check_address_exists,
3585 if (caec.exists == GNUNET_YES)
3587 /* During validation attempts we will likely trigger the other
3588 peer trying to validate our address which in turn will cause
3589 it to send us its HELLO, so we expect to hit this case rather
3590 frequently. Only print something if we are very verbose. */
3591 #if DEBUG_TRANSPORT > 1
3592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3593 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3594 (peer_address->addr != NULL)
3595 ? a2s (tp->short_name,
3597 peer_address->addrlen)
3600 GNUNET_i2s (&neighbour->id));
3602 schedule_next_ping (peer_address);
3605 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3606 va->transport_name = GNUNET_strdup (tp->short_name);
3607 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3609 va->send_time = GNUNET_TIME_absolute_get();
3610 va->session = peer_address->session;
3611 if (peer_address->addr != NULL)
3613 va->addr = (const void*) &va[1];
3614 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3615 va->addrlen = peer_address->addrlen;
3617 memcpy(&va->publicKey,
3618 &neighbour->publicKey,
3619 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3621 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3622 &timeout_hello_validation,
3624 GNUNET_CONTAINER_multihashmap_put (validation_map,
3625 &neighbour->id.hashPubKey,
3627 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3629 if (peer_address->validated != GNUNET_YES)
3630 hello_size = GNUNET_HELLO_size(our_hello);
3634 tsize = sizeof(struct TransportPingMessage) + hello_size;
3636 if (peer_address->addr != NULL)
3638 slen = strlen (tp->short_name) + 1;
3639 tsize += slen + peer_address->addrlen;
3643 slen = 0; /* make gcc happy */
3645 message_buf = GNUNET_malloc(tsize);
3646 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3647 ping.challenge = htonl(va->challenge);
3648 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3649 if (peer_address->validated != GNUNET_YES)
3651 memcpy(message_buf, our_hello, hello_size);
3654 if (peer_address->addr != NULL)
3656 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3657 peer_address->addrlen +
3659 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3662 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3664 peer_address->addrlen);
3668 ping.header.size = htons(sizeof(struct TransportPingMessage));
3671 memcpy(&message_buf[hello_size],
3673 sizeof(struct TransportPingMessage));
3675 #if DEBUG_TRANSPORT_REVALIDATION
3676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3677 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3678 (peer_address->addr != NULL)
3679 ? a2s (peer_address->plugin->short_name,
3681 peer_address->addrlen)
3684 GNUNET_i2s (&neighbour->id),
3685 "HELLO", hello_size,
3688 if (peer_address->validated != GNUNET_YES)
3689 GNUNET_STATISTICS_update (stats,
3690 gettext_noop ("# PING with HELLO messages sent"),
3694 GNUNET_STATISTICS_update (stats,
3695 gettext_noop ("# PING without HELLO messages sent"),
3698 GNUNET_STATISTICS_update (stats,
3699 gettext_noop ("# PING messages sent for re-validation"),
3702 transmit_to_peer (NULL, peer_address,
3703 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3704 HELLO_VERIFICATION_TIMEOUT,
3706 GNUNET_YES, neighbour);
3707 GNUNET_free(message_buf);
3708 schedule_next_ping (peer_address);
3713 * Schedule the job that will cause us to send a PING to the
3714 * foreign address to evaluate its validity and latency.
3716 * @param fal address to PING
3719 schedule_next_ping (struct ForeignAddressList *fal)
3721 struct GNUNET_TIME_Relative delay;
3723 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3725 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3726 delay.rel_value /= 2; /* do before expiration */
3727 delay = GNUNET_TIME_relative_min (delay,
3728 LATENCY_EVALUATION_MAX_DELAY);
3729 if (GNUNET_YES != fal->estimated)
3731 delay = GNUNET_TIME_UNIT_ZERO;
3732 fal->estimated = GNUNET_YES;
3734 if (GNUNET_YES == fal->connected)
3736 delay = GNUNET_TIME_relative_min (delay,
3737 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3739 /* FIXME: also adjust delay based on how close the last
3740 observed latency is to the latency of the best alternative */
3741 /* bound how fast we can go */
3742 delay = GNUNET_TIME_relative_max (delay,
3743 GNUNET_TIME_UNIT_SECONDS);
3744 /* randomize a bit (to avoid doing all at the same time) */
3745 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3746 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3747 &send_periodic_ping,
3755 * Function that will be called if we receive some payload
3756 * from another peer.
3758 * @param message the payload
3759 * @param n peer who claimed to be the sender
3762 handle_payload_message (const struct GNUNET_MessageHeader *message,
3763 struct NeighbourList *n)
3765 struct InboundMessage *im;
3766 struct TransportClient *cpos;
3769 msize = ntohs (message->size);
3770 if (n->received_pong == GNUNET_NO)
3772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3773 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3774 ntohs (message->type),
3775 ntohs (message->size),
3776 GNUNET_i2s (&n->id));
3777 GNUNET_free_non_null (n->pre_connect_message_buffer);
3778 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3779 memcpy (n->pre_connect_message_buffer, message, msize);
3784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3785 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3786 ntohs (message->type),
3787 ntohs (message->size),
3788 GNUNET_i2s (&n->id));
3790 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3793 n->quota_violation_count++;
3795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3796 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3797 n->in_tracker.available_bytes_per_s__,
3798 n->quota_violation_count);
3800 /* Discount 32k per violation */
3801 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3806 if (n->quota_violation_count > 0)
3808 /* try to add 32k back */
3809 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3811 n->quota_violation_count--;
3814 GNUNET_STATISTICS_update (stats,
3815 gettext_noop ("# payload received from other peers"),
3818 /* transmit message to all clients */
3819 uint32_t ats_count = 2;
3820 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3821 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3824 im = GNUNET_malloc (size);
3825 im->header.size = htons (size);
3826 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3828 im->ats_count = htonl(ats_count);
3829 /* Setting ATS data */
3830 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3831 (&(im->ats))[0].value = htonl (n->distance);
3832 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3833 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3834 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3835 (&(im->ats))[ats_count].value = htonl (0);
3837 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3839 while (cpos != NULL)
3841 transmit_to_client (cpos, &im->header, GNUNET_YES);
3849 * Iterator over hash map entries. Checks if the given validation
3850 * entry is for the same challenge as what is given in the PONG.
3852 * @param cls the 'struct TransportPongMessage*'
3853 * @param key peer identity
3854 * @param value value in the hash map ('struct ValidationEntry')
3855 * @return GNUNET_YES if we should continue to
3856 * iterate (mismatch), GNUNET_NO if not (entry matched)
3859 check_pending_validation (void *cls,
3860 const GNUNET_HashCode * key,
3863 const struct TransportPongMessage *pong = cls;
3864 struct ValidationEntry *ve = value;
3865 struct AddValidatedAddressContext avac;
3866 unsigned int challenge = ntohl(pong->challenge);
3867 struct GNUNET_HELLO_Message *hello;
3868 struct GNUNET_PeerIdentity target;
3869 struct NeighbourList *n;
3870 struct ForeignAddressList *fal;
3871 struct OwnAddressList *oal;
3872 struct TransportPlugin *tp;
3873 struct GNUNET_MessageHeader *prem;
3879 ps = ntohs (pong->header.size);
3880 if (ps < sizeof (struct TransportPongMessage))
3882 GNUNET_break_op (0);
3885 addr = (const char*) &pong[1];
3886 slen = strlen (ve->transport_name) + 1;
3887 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3888 (ve->challenge != challenge) ||
3889 (addr[slen-1] != '\0') ||
3890 (0 != strcmp (addr, ve->transport_name)) ||
3891 (ntohl (pong->purpose.size)
3892 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3894 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3895 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3900 alen = ps - sizeof (struct TransportPongMessage) - slen;
3901 switch (ntohl (pong->purpose.purpose))
3903 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3904 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3905 (0 != memcmp (&addr[slen],
3909 return GNUNET_YES; /* different entry, keep trying! */
3911 if (0 != memcmp (&pong->pid,
3913 sizeof (struct GNUNET_PeerIdentity)))
3915 GNUNET_break_op (0);
3919 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3924 GNUNET_break_op (0);
3929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3930 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3932 a2s (ve->transport_name,
3933 (const struct sockaddr *) ve->addr,
3935 ve->transport_name);
3938 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3939 if (0 != memcmp (&pong->pid,
3941 sizeof (struct GNUNET_PeerIdentity)))
3943 GNUNET_break_op (0);
3946 if (ve->addrlen != 0)
3948 /* must have been for a different validation entry */
3951 tp = find_transport (ve->transport_name);
3957 oal = tp->addresses;
3960 if ( (oal->addrlen == alen) &&
3961 (0 == memcmp (&oal[1],
3969 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3970 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3971 a2s (ve->transport_name,
3977 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3982 GNUNET_break_op (0);
3987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3988 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3990 a2s (ve->transport_name,
3993 ve->transport_name);
3997 GNUNET_break_op (0);
4000 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4002 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4003 _("Received expired signature. Check system time.\n"));
4006 GNUNET_STATISTICS_update (stats,
4007 gettext_noop ("# address validation successes"),
4010 /* create the updated HELLO */
4011 GNUNET_CRYPTO_hash (&ve->publicKey,
4012 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4013 &target.hashPubKey);
4014 if (ve->addr != NULL)
4016 avac.done = GNUNET_NO;
4018 hello = GNUNET_HELLO_create (&ve->publicKey,
4019 &add_validated_address,
4021 GNUNET_PEERINFO_add_peer (peerinfo,
4023 GNUNET_free (hello);
4025 n = find_neighbour (&target);
4028 n->publicKey = ve->publicKey;
4029 n->public_key_valid = GNUNET_YES;
4030 fal = add_peer_address (n,
4035 GNUNET_assert (fal != NULL);
4036 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4037 fal->validated = GNUNET_YES;
4038 mark_address_connected (fal);
4039 GNUNET_STATISTICS_update (stats,
4040 gettext_noop ("# peer addresses considered valid"),
4043 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4044 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4046 schedule_next_ping (fal);
4047 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4048 n->latency = fal->latency;
4050 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4052 n->distance = fal->distance;
4053 if (GNUNET_NO == n->received_pong)
4055 n->received_pong = GNUNET_YES;
4057 notify_clients_connect (&target, n->latency, n->distance);
4058 if (NULL != (prem = n->pre_connect_message_buffer))
4060 n->pre_connect_message_buffer = NULL;
4061 handle_payload_message (prem, n);
4065 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4067 GNUNET_SCHEDULER_cancel (n->retry_task);
4068 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4069 try_transmission_to_peer (n);
4073 /* clean up validation entry */
4074 GNUNET_assert (GNUNET_YES ==
4075 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4078 abort_validation (NULL, NULL, ve);
4084 * Function that will be called if we receive a validation
4085 * of an address challenge that we transmitted to another
4086 * peer. Note that the validation should only be considered
4087 * acceptable if the challenge matches AND if the sender
4088 * address is at least a plausible address for this peer
4089 * (otherwise we may be seeing a MiM attack).
4091 * @param cls closure
4092 * @param message the pong message
4093 * @param peer who responded to our challenge
4094 * @param sender_address string describing our sender address (as observed
4095 * by the other peer in binary format)
4096 * @param sender_address_len number of bytes in 'sender_address'
4099 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4100 const struct GNUNET_PeerIdentity *peer,
4101 const char *sender_address,
4102 size_t sender_address_len)
4104 #if DEBUG_TRANSPORT > 1
4105 /* we get tons of these that just get discarded, only log
4106 if we are quite verbose */
4107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4108 "Receiving `%s' message from `%4s'.\n", "PONG",
4111 GNUNET_STATISTICS_update (stats,
4112 gettext_noop ("# PONG messages received"),
4115 if (GNUNET_SYSERR !=
4116 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4118 &check_pending_validation,
4121 /* This is *expected* to happen a lot since we send
4122 PONGs to *all* known addresses of the sender of
4123 the PING, so most likely we get multiple PONGs
4124 per PING, and all but the first PONG will end up
4125 here. So really we should not print anything here
4126 unless we want to be very, very verbose... */
4127 #if DEBUG_TRANSPORT > 2
4128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4129 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4141 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4143 * @param cls the 'struct ValidationEntry*'
4144 * @param neighbour neighbour to validate, NULL if validation failed
4147 transmit_hello_and_ping (void *cls,
4148 struct NeighbourList *neighbour)
4150 struct ValidationEntry *va = cls;
4151 struct ForeignAddressList *peer_address;
4152 struct TransportPingMessage ping;
4153 uint16_t hello_size;
4156 struct GNUNET_PeerIdentity id;
4159 GNUNET_CRYPTO_hash (&va->publicKey,
4160 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4162 if (neighbour == NULL)
4164 /* FIXME: stats... */
4165 GNUNET_break (GNUNET_OK ==
4166 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4169 abort_validation (NULL, NULL, va);
4172 neighbour->publicKey = va->publicKey;
4173 neighbour->public_key_valid = GNUNET_YES;
4174 peer_address = add_peer_address (neighbour,
4175 va->transport_name, NULL,
4176 (const void*) &va[1],
4178 if (peer_address == NULL)
4180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4181 "Failed to add peer `%4s' for plugin `%s'\n",
4182 GNUNET_i2s (&neighbour->id),
4183 va->transport_name);
4184 GNUNET_break (GNUNET_OK ==
4185 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4188 abort_validation (NULL, NULL, va);
4191 hello_size = GNUNET_HELLO_size(our_hello);
4192 slen = strlen(va->transport_name) + 1;
4193 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4194 message_buf = GNUNET_malloc(tsize);
4195 ping.challenge = htonl(va->challenge);
4196 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4197 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4198 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4199 memcpy(message_buf, our_hello, hello_size);
4200 memcpy(&message_buf[hello_size],
4202 sizeof(struct TransportPingMessage));
4203 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4206 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4211 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4214 : a2s (va->transport_name,
4215 (const void*) &va[1], va->addrlen),
4217 GNUNET_i2s (&neighbour->id),
4218 "HELLO", hello_size,
4219 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4222 GNUNET_STATISTICS_update (stats,
4223 gettext_noop ("# PING messages sent for initial validation"),
4226 transmit_to_peer (NULL, peer_address,
4227 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4228 HELLO_VERIFICATION_TIMEOUT,
4230 GNUNET_YES, neighbour);
4231 GNUNET_free(message_buf);
4236 * Check if the given address is already being validated; if not,
4237 * append the given address to the list of entries that are being be
4238 * validated and initiate validation.
4240 * @param cls closure ('struct CheckHelloValidatedContext *')
4241 * @param tname name of the transport
4242 * @param expiration expiration time
4243 * @param addr the address
4244 * @param addrlen length of the address
4245 * @return GNUNET_OK (always)
4248 run_validation (void *cls,
4250 struct GNUNET_TIME_Absolute expiration,
4254 struct CheckHelloValidatedContext *chvc = cls;
4255 struct GNUNET_PeerIdentity id;
4256 struct TransportPlugin *tp;
4257 struct ValidationEntry *va;
4258 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4259 struct CheckAddressExistsClosure caec;
4260 struct OwnAddressList *oal;
4262 GNUNET_assert (addr != NULL);
4264 GNUNET_STATISTICS_update (stats,
4265 gettext_noop ("# peer addresses scheduled for validation"),
4268 tp = find_transport (tname);
4271 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4272 GNUNET_ERROR_TYPE_BULK,
4274 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4276 GNUNET_STATISTICS_update (stats,
4277 gettext_noop ("# peer addresses not validated (plugin not available)"),
4282 /* check if this is one of our own addresses */
4283 oal = tp->addresses;
4286 if ( (oal->addrlen == addrlen) &&
4287 (0 == memcmp (&oal[1],
4291 /* not plausible, this address is equivalent to our own address! */
4292 GNUNET_STATISTICS_update (stats,
4293 gettext_noop ("# peer addresses not validated (loopback)"),
4300 GNUNET_HELLO_get_key (chvc->hello, &pk);
4301 GNUNET_CRYPTO_hash (&pk,
4303 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4306 if (is_blacklisted(&id, tp))
4309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4310 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4318 caec.addrlen = addrlen;
4319 caec.session = NULL;
4321 caec.exists = GNUNET_NO;
4322 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4323 &check_address_exists,
4325 if (caec.exists == GNUNET_YES)
4327 /* During validation attempts we will likely trigger the other
4328 peer trying to validate our address which in turn will cause
4329 it to send us its HELLO, so we expect to hit this case rather
4330 frequently. Only print something if we are very verbose. */
4331 #if DEBUG_TRANSPORT > 1
4332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4333 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4334 a2s (tname, addr, addrlen),
4338 GNUNET_STATISTICS_update (stats,
4339 gettext_noop ("# peer addresses not validated (in progress)"),
4344 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4347 va->transport_name = GNUNET_strdup (tname);
4348 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4350 va->send_time = GNUNET_TIME_absolute_get();
4351 va->addr = (const void*) &va[1];
4352 memcpy (&va[1], addr, addrlen);
4353 va->addrlen = addrlen;
4354 GNUNET_HELLO_get_key (chvc->hello,
4356 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4357 &timeout_hello_validation,
4359 GNUNET_CONTAINER_multihashmap_put (validation_map,
4362 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4363 setup_peer_check_blacklist (&id, GNUNET_NO,
4364 &transmit_hello_and_ping,
4371 * Check if addresses in validated hello "h" overlap with
4372 * those in "chvc->hello" and validate the rest.
4374 * @param cls closure
4375 * @param peer id of the peer, NULL for last call
4376 * @param h hello message for the peer (can be NULL)
4377 * @param err_msg NULL if successful, otherwise contains error message
4380 check_hello_validated (void *cls,
4381 const struct GNUNET_PeerIdentity *peer,
4382 const struct GNUNET_HELLO_Message *h,
4383 const char *err_msg)
4385 struct CheckHelloValidatedContext *chvc = cls;
4386 struct GNUNET_HELLO_Message *plain_hello;
4387 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4388 struct GNUNET_PeerIdentity target;
4389 struct NeighbourList *n;
4391 if (err_msg != NULL)
4393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4394 _("Error in communication with PEERINFO service\n"));
4400 GNUNET_STATISTICS_update (stats,
4401 gettext_noop ("# outstanding peerinfo iterate requests"),
4405 if (GNUNET_NO == chvc->hello_known)
4407 /* notify PEERINFO about the peer now, so that we at least
4408 have the public key if some other component needs it */
4409 GNUNET_HELLO_get_key (chvc->hello, &pk);
4410 GNUNET_CRYPTO_hash (&pk,
4411 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4412 &target.hashPubKey);
4413 plain_hello = GNUNET_HELLO_create (&pk,
4416 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4417 GNUNET_free (plain_hello);
4418 #if DEBUG_TRANSPORT_HELLO
4419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4420 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4422 GNUNET_i2s (&target));
4424 GNUNET_STATISTICS_update (stats,
4425 gettext_noop ("# new HELLOs requiring full validation"),
4428 GNUNET_HELLO_iterate_addresses (chvc->hello,
4435 GNUNET_STATISTICS_update (stats,
4436 gettext_noop ("# duplicate HELLO (peer known)"),
4441 if (chvc->ve_count == 0)
4443 GNUNET_CONTAINER_DLL_remove (chvc_head,
4452 #if DEBUG_TRANSPORT_HELLO
4453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4454 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4458 chvc->hello_known = GNUNET_YES;
4459 n = find_neighbour (peer);
4462 #if DEBUG_TRANSPORT_HELLO
4463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4464 "Calling hello_iterate_addresses for %s!\n",
4467 GNUNET_HELLO_iterate_addresses (h,
4469 &add_to_foreign_address_list,
4471 try_transmission_to_peer (n);
4475 #if DEBUG_TRANSPORT_HELLO
4476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4477 "No existing neighbor record for %s!\n",
4480 GNUNET_STATISTICS_update (stats,
4481 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4485 GNUNET_STATISTICS_update (stats,
4486 gettext_noop ("# HELLO validations (update case)"),
4489 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4491 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4498 * Process HELLO-message.
4500 * @param plugin transport involved, may be NULL
4501 * @param message the actual message
4502 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4505 process_hello (struct TransportPlugin *plugin,
4506 const struct GNUNET_MessageHeader *message)
4509 struct GNUNET_PeerIdentity target;
4510 const struct GNUNET_HELLO_Message *hello;
4511 struct CheckHelloValidatedContext *chvc;
4512 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4513 #if DEBUG_TRANSPORT_HELLO > 2
4516 hsize = ntohs (message->size);
4517 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4518 (hsize < sizeof (struct GNUNET_MessageHeader)))
4521 return GNUNET_SYSERR;
4523 GNUNET_STATISTICS_update (stats,
4524 gettext_noop ("# HELLOs received for validation"),
4528 /* first, check if load is too high */
4529 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4531 GNUNET_STATISTICS_update (stats,
4532 gettext_noop ("# HELLOs ignored due to high load"),
4535 #if DEBUG_TRANSPORT_HELLO
4536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4537 "Ignoring `%s' for `%4s', load too high.\n",
4539 GNUNET_i2s (&target));
4543 hello = (const struct GNUNET_HELLO_Message *) message;
4544 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4546 #if DEBUG_TRANSPORT_HELLO
4547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4548 "Unable to get public key from `%s' for `%4s'!\n",
4550 GNUNET_i2s (&target));
4552 GNUNET_break_op (0);
4553 return GNUNET_SYSERR;
4556 GNUNET_CRYPTO_hash (&publicKey,
4557 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4558 &target.hashPubKey);
4560 #if DEBUG_TRANSPORT_HELLO
4561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4562 "Received `%s' message for `%4s'\n",
4564 GNUNET_i2s (&target));
4567 if (0 == memcmp (&my_identity,
4569 sizeof (struct GNUNET_PeerIdentity)))
4571 GNUNET_STATISTICS_update (stats,
4572 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4578 while (NULL != chvc)
4580 if (GNUNET_HELLO_equals (hello,
4582 GNUNET_TIME_absolute_get ()).abs_value > 0)
4584 #if DEBUG_TRANSPORT_HELLO > 2
4585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4586 "Received duplicate `%s' message for `%4s'; ignored\n",
4588 GNUNET_i2s (&target));
4590 return GNUNET_OK; /* validation already pending */
4592 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4593 GNUNET_break (0 != memcmp (hello, chvc->hello,
4594 GNUNET_HELLO_size(hello)));
4599 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4600 if ((NULL != temp_neighbor))
4602 fprintf(stderr, "Already know peer, ignoring hello\n");
4607 #if DEBUG_TRANSPORT_HELLO > 2
4610 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4612 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4615 GNUNET_i2s (&target),
4617 GNUNET_HELLO_size(hello));
4621 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4623 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4624 memcpy (&chvc[1], hello, hsize);
4625 GNUNET_CONTAINER_DLL_insert (chvc_head,
4628 /* finally, check if HELLO was previously validated
4629 (continuation will then schedule actual validation) */
4630 GNUNET_STATISTICS_update (stats,
4631 gettext_noop ("# peerinfo process hello iterate requests"),
4634 GNUNET_STATISTICS_update (stats,
4635 gettext_noop ("# outstanding peerinfo iterate requests"),
4638 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4640 HELLO_VERIFICATION_TIMEOUT,
4641 &check_hello_validated, chvc);
4647 * The peer specified by the given neighbour has timed-out or a plugin
4648 * has disconnected. We may either need to do nothing (other plugins
4649 * still up), or trigger a full disconnect and clean up. This
4650 * function updates our state and does the necessary notifications.
4651 * Also notifies our clients that the neighbour is now officially
4654 * @param n the neighbour list entry for the peer
4655 * @param check GNUNET_YES to check if ALL addresses for this peer
4656 * are gone, GNUNET_NO to force a disconnect of the peer
4657 * regardless of whether other addresses exist.
4660 disconnect_neighbour (struct NeighbourList *n, int check)
4662 struct ReadyList *rpos;
4663 struct NeighbourList *npos;
4664 struct NeighbourList *nprev;
4665 struct MessageQueue *mq;
4666 struct ForeignAddressList *peer_addresses;
4667 struct ForeignAddressList *peer_pos;
4669 if (GNUNET_YES == check)
4672 while (NULL != rpos)
4674 peer_addresses = rpos->addresses;
4675 while (peer_addresses != NULL)
4677 if (GNUNET_YES == peer_addresses->connected)
4679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4680 "NOT Disconnecting from `%4s', still have live addresses!\n",
4681 GNUNET_i2s (&n->id));
4682 return; /* still connected */
4684 peer_addresses = peer_addresses->next;
4690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4691 "Disconnecting from `%4s'\n",
4692 GNUNET_i2s (&n->id));
4694 /* remove n from neighbours list */
4697 while ((npos != NULL) && (npos != n))
4702 GNUNET_assert (npos != NULL);
4704 neighbours = n->next;
4706 nprev->next = n->next;
4708 /* notify all clients about disconnect */
4709 if (GNUNET_YES == n->received_pong)
4710 notify_clients_disconnect (&n->id);
4712 /* clean up all plugins, cancel connections and pending transmissions */
4713 while (NULL != (rpos = n->plugins))
4715 n->plugins = rpos->next;
4716 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4717 while (rpos->addresses != NULL)
4719 peer_pos = rpos->addresses;
4720 rpos->addresses = peer_pos->next;
4721 if (peer_pos->connected == GNUNET_YES)
4722 GNUNET_STATISTICS_update (stats,
4723 gettext_noop ("# connected addresses"),
4726 if (GNUNET_YES == peer_pos->validated)
4727 GNUNET_STATISTICS_update (stats,
4728 gettext_noop ("# peer addresses considered valid"),
4731 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4733 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4734 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4736 GNUNET_free(peer_pos->ressources);
4737 GNUNET_free(peer_pos->quality);
4738 GNUNET_free(peer_pos);
4743 /* free all messages on the queue */
4744 while (NULL != (mq = n->messages_head))
4746 GNUNET_STATISTICS_update (stats,
4747 gettext_noop ("# bytes in message queue for other peers"),
4748 - (int64_t) mq->message_buf_size,
4750 GNUNET_STATISTICS_update (stats,
4751 gettext_noop ("# bytes discarded due to disconnect"),
4752 mq->message_buf_size,
4754 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4757 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4759 sizeof(struct GNUNET_PeerIdentity)));
4762 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4764 GNUNET_SCHEDULER_cancel (n->timeout_task);
4765 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4767 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4769 GNUNET_SCHEDULER_cancel (n->retry_task);
4770 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4772 if (n->piter != NULL)
4774 GNUNET_PEERINFO_iterate_cancel (n->piter);
4775 GNUNET_STATISTICS_update (stats,
4776 gettext_noop ("# outstanding peerinfo iterate requests"),
4781 /* finally, free n itself */
4782 GNUNET_STATISTICS_update (stats,
4783 gettext_noop ("# active neighbours"),
4786 GNUNET_free_non_null (n->pre_connect_message_buffer);
4792 * We have received a PING message from someone. Need to send a PONG message
4793 * in response to the peer by any means necessary.
4796 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4797 const struct GNUNET_PeerIdentity *peer,
4798 struct Session *session,
4799 const char *sender_address,
4800 uint16_t sender_address_len)
4802 struct TransportPlugin *plugin = cls;
4803 struct SessionHeader *session_header = (struct SessionHeader*) session;
4804 struct TransportPingMessage *ping;
4805 struct TransportPongMessage *pong;
4806 struct NeighbourList *n;
4807 struct ReadyList *rl;
4808 struct ForeignAddressList *fal;
4809 struct OwnAddressList *oal;
4814 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4816 GNUNET_break_op (0);
4817 return GNUNET_SYSERR;
4820 ping = (struct TransportPingMessage *) message;
4821 if (0 != memcmp (&ping->target,
4822 plugin->env.my_identity,
4823 sizeof (struct GNUNET_PeerIdentity)))
4825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4826 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4828 (sender_address != NULL)
4829 ? a2s (plugin->short_name,
4830 (const struct sockaddr *)sender_address,
4833 GNUNET_i2s (&ping->target));
4834 return GNUNET_SYSERR;
4837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4838 "Processing `%s' from `%s'\n",
4840 (sender_address != NULL)
4841 ? a2s (plugin->short_name,
4842 (const struct sockaddr *)sender_address,
4846 GNUNET_STATISTICS_update (stats,
4847 gettext_noop ("# PING messages received"),
4850 addr = (const char*) &ping[1];
4851 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4852 slen = strlen (plugin->short_name) + 1;
4855 /* peer wants to confirm that we have an outbound connection to him */
4856 if (session == NULL)
4858 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4859 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4861 return GNUNET_SYSERR;
4863 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4864 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4865 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4866 pong->purpose.size =
4867 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4869 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4870 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4871 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4872 pong->challenge = ping->challenge;
4873 pong->addrlen = htonl(sender_address_len + slen);
4876 sizeof(struct GNUNET_PeerIdentity));
4880 if ((sender_address!=NULL) && (sender_address_len > 0))
4881 memcpy (&((char*)&pong[1])[slen],
4883 sender_address_len);
4884 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4886 /* create / update cached sig */
4888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4889 "Creating PONG signature to indicate active connection.\n");
4891 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4892 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4893 GNUNET_assert (GNUNET_OK ==
4894 GNUNET_CRYPTO_rsa_sign (my_private_key,
4896 &session_header->pong_signature));
4900 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4902 memcpy (&pong->signature,
4903 &session_header->pong_signature,
4904 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4910 /* peer wants to confirm that this is one of our addresses */
4914 plugin->api->check_address (plugin->api->cls,
4918 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4919 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4920 a2s (plugin->short_name,
4925 oal = plugin->addresses;
4928 if ( (oal->addrlen == alen) &&
4935 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4936 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4937 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4938 pong->purpose.size =
4939 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4941 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4942 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4943 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4944 pong->challenge = ping->challenge;
4945 pong->addrlen = htonl(alen + slen);
4948 sizeof(struct GNUNET_PeerIdentity));
4949 memcpy (&pong[1], plugin->short_name, slen);
4950 memcpy (&((char*)&pong[1])[slen], addr, alen);
4951 if ( (oal != NULL) &&
4952 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4954 /* create / update cached sig */
4956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4957 "Creating PONG signature to indicate ownership.\n");
4959 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4960 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4961 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4962 GNUNET_assert (GNUNET_OK ==
4963 GNUNET_CRYPTO_rsa_sign (my_private_key,
4965 &oal->pong_signature));
4966 memcpy (&pong->signature,
4967 &oal->pong_signature,
4968 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4970 else if (oal == NULL)
4972 /* not using cache (typically DV-only) */
4973 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4974 GNUNET_assert (GNUNET_OK ==
4975 GNUNET_CRYPTO_rsa_sign (my_private_key,
4981 /* can used cached version */
4982 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4983 memcpy (&pong->signature,
4984 &oal->pong_signature,
4985 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4988 n = find_neighbour(peer);
4989 GNUNET_assert (n != NULL);
4990 /* first try reliable response transmission */
4994 fal = rl->addresses;
4997 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5000 ntohs (pong->header.size),
5001 TRANSPORT_PONG_PRIORITY,
5002 HELLO_VERIFICATION_TIMEOUT,
5010 GNUNET_STATISTICS_update (stats,
5011 gettext_noop ("# PONGs unicast via reliable transport"),
5021 /* no reliable method found, do multicast */
5022 GNUNET_STATISTICS_update (stats,
5023 gettext_noop ("# PONGs multicast to all available addresses"),
5029 fal = rl->addresses;
5032 transmit_to_peer(NULL, fal,
5033 TRANSPORT_PONG_PRIORITY,
5034 HELLO_VERIFICATION_TIMEOUT,
5036 ntohs(pong->header.size),
5052 * Function called by the plugin for each received message.
5053 * Update data volumes, possibly notify plugins about
5054 * reducing the rate at which they read from the socket
5055 * and generally forward to our receive callback.
5057 * @param cls the "struct TransportPlugin *" we gave to the plugin
5058 * @param peer (claimed) identity of the other peer
5059 * @param message the message, NULL if we only care about
5060 * learning about the delay until we should receive again
5061 * @param ats_data information for automatic transport selection
5062 * @param ats_count number of elements in ats not including 0-terminator
5063 * @param session identifier used for this session (can be NULL)
5064 * @param sender_address binary address of the sender (if observed)
5065 * @param sender_address_len number of bytes in sender_address
5066 * @return how long in ms the plugin should wait until receiving more data
5067 * (plugins that do not support this, can ignore the return value)
5069 static struct GNUNET_TIME_Relative
5070 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5071 const struct GNUNET_MessageHeader *message,
5072 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5074 struct Session *session,
5075 const char *sender_address,
5076 uint16_t sender_address_len)
5078 struct TransportPlugin *plugin = cls;
5079 struct ReadyList *service_context;
5080 struct ForeignAddressList *peer_address;
5082 struct NeighbourList *n;
5083 struct GNUNET_TIME_Relative ret;
5084 if (is_blacklisted (peer, plugin))
5085 return GNUNET_TIME_UNIT_FOREVER_REL;
5089 n = find_neighbour (peer);
5091 n = setup_new_neighbour (peer, GNUNET_YES);
5092 service_context = n->plugins;
5093 while ((service_context != NULL) && (plugin != service_context->plugin))
5094 service_context = service_context->next;
5095 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5096 peer_address = NULL;
5099 for (c=0; c<ats_count; c++)
5101 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5103 distance = ntohl(ats_data[c].value);
5106 /* notify ATS about incoming data */
5107 //ats_notify_ats_data(peer, ats_data);
5109 if (message != NULL)
5111 if ( (session != NULL) ||
5112 (sender_address != NULL) )
5113 peer_address = add_peer_address (n,
5117 sender_address_len);
5118 if (peer_address != NULL)
5121 update_addr_ats(peer_address, ats_data, ats_count);
5122 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5124 peer_address->distance = distance;
5125 if (GNUNET_YES == peer_address->validated)
5126 mark_address_connected (peer_address);
5127 peer_address->timeout
5129 GNUNET_TIME_relative_to_absolute
5130 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5131 schedule_next_ping (peer_address);
5133 /* update traffic received amount ... */
5134 msize = ntohs (message->size);
5135 GNUNET_STATISTICS_update (stats,
5136 gettext_noop ("# bytes received from other peers"),
5139 n->distance = distance;
5141 GNUNET_TIME_relative_to_absolute
5142 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5143 GNUNET_SCHEDULER_cancel (n->timeout_task);
5145 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5146 &neighbour_timeout_task, n);
5147 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5149 /* dropping message due to frequent inbound volume violations! */
5150 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5151 GNUNET_ERROR_TYPE_BULK,
5153 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5154 n->in_tracker.available_bytes_per_s__,
5155 n->quota_violation_count);
5156 GNUNET_STATISTICS_update (stats,
5157 gettext_noop ("# bandwidth quota violations by other peers"),
5160 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5165 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5166 ntohs (message->type),
5167 ntohs (message->size),
5170 switch (ntohs (message->type))
5172 case GNUNET_MESSAGE_TYPE_HELLO:
5173 GNUNET_STATISTICS_update (stats,
5174 gettext_noop ("# HELLO messages received from other peers"),
5177 process_hello (plugin, message);
5179 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5180 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5182 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5183 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5186 handle_payload_message (message, n);
5190 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5191 if (ret.rel_value > 0)
5193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5194 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5195 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5196 (unsigned int) n->in_tracker.available_bytes_per_s__,
5197 (unsigned long long) ret.rel_value);
5198 GNUNET_STATISTICS_update (stats,
5199 gettext_noop ("# ms throttling suggested"),
5200 (int64_t) ret.rel_value,
5207 * Handle START-message. This is the first message sent to us
5208 * by any client which causes us to add it to our list.
5210 * @param cls closure (always NULL)
5211 * @param client identification of the client
5212 * @param message the actual message
5215 handle_start (void *cls,
5216 struct GNUNET_SERVER_Client *client,
5217 const struct GNUNET_MessageHeader *message)
5219 const struct StartMessage *start;
5220 struct TransportClient *c;
5221 struct ConnectInfoMessage * cim;
5222 struct NeighbourList *n;
5226 start = (const struct StartMessage*) message;
5228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5229 "Received `%s' request from client\n", "START");
5234 if (c->client == client)
5236 /* client already on our list! */
5238 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5243 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5244 (0 != memcmp (&start->self,
5246 sizeof (struct GNUNET_PeerIdentity))) )
5248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5249 _("Rejecting control connection from peer `%s', which is not me!\n"),
5250 GNUNET_i2s (&start->self));
5251 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5254 c = GNUNET_malloc (sizeof (struct TransportClient));
5258 if (our_hello != NULL)
5261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5262 "Sending our own `%s' to new client\n", "HELLO");
5264 transmit_to_client (c,
5265 (const struct GNUNET_MessageHeader *) our_hello,
5267 /* tell new client about all existing connections */
5269 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5270 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5274 cim = GNUNET_malloc (size);
5275 cim->header.size = htons (size);
5276 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5277 cim->ats_count = htonl(ats_count);
5278 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5279 (&(cim->ats))[2].value = htonl (0);
5283 if (GNUNET_YES == n->received_pong)
5285 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5286 (&(cim->ats))[0].value = htonl (n->distance);
5287 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5288 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5290 transmit_to_client (c, &cim->header, GNUNET_NO);
5296 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5301 * Handle HELLO-message.
5303 * @param cls closure (always NULL)
5304 * @param client identification of the client
5305 * @param message the actual message
5308 handle_hello (void *cls,
5309 struct GNUNET_SERVER_Client *client,
5310 const struct GNUNET_MessageHeader *message)
5314 GNUNET_STATISTICS_update (stats,
5315 gettext_noop ("# HELLOs received from clients"),
5318 ret = process_hello (NULL, message);
5319 GNUNET_SERVER_receive_done (client, ret);
5324 * Closure for 'transmit_client_message'; followed by
5325 * 'msize' bytes of the actual message.
5327 struct TransmitClientMessageContext
5330 * Client on whom's behalf we are sending.
5332 struct GNUNET_SERVER_Client *client;
5335 * Timeout for the transmission.
5337 struct GNUNET_TIME_Absolute timeout;
5345 * Size of the message in bytes.
5352 * Schedule transmission of a message we got from a client to a peer.
5354 * @param cls the 'struct TransmitClientMessageContext*'
5355 * @param n destination, or NULL on error (in that case, drop the message)
5358 transmit_client_message (void *cls,
5359 struct NeighbourList *n)
5361 struct TransmitClientMessageContext *tcmc = cls;
5362 struct TransportClient *tc;
5365 while ((tc != NULL) && (tc->client != tcmc->client))
5370 transmit_to_peer (tc, NULL, tcmc->priority,
5371 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5373 tcmc->msize, GNUNET_NO, n);
5375 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5376 GNUNET_SERVER_client_drop (tcmc->client);
5382 * Handle SEND-message.
5384 * @param cls closure (always NULL)
5385 * @param client identification of the client
5386 * @param message the actual message
5389 handle_send (void *cls,
5390 struct GNUNET_SERVER_Client *client,
5391 const struct GNUNET_MessageHeader *message)
5393 const struct OutboundMessage *obm;
5394 const struct GNUNET_MessageHeader *obmm;
5395 struct TransmitClientMessageContext *tcmc;
5399 size = ntohs (message->size);
5401 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5404 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5407 GNUNET_STATISTICS_update (stats,
5408 gettext_noop ("# payload received for other peers"),
5411 obm = (const struct OutboundMessage *) message;
5412 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5413 msize = size - sizeof (struct OutboundMessage);
5415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5416 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5417 "SEND", GNUNET_i2s (&obm->peer),
5421 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5422 tcmc->client = client;
5423 tcmc->priority = ntohl (obm->priority);
5424 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5425 tcmc->msize = msize;
5426 /* FIXME: this memcpy can be up to 7% of our total runtime */
5427 memcpy (&tcmc[1], obmm, msize);
5428 GNUNET_SERVER_client_keep (client);
5429 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5430 &transmit_client_message,
5436 * Handle request connect message
5438 * @param cls closure (always NULL)
5439 * @param client identification of the client
5440 * @param message the actual message
5443 handle_request_connect (void *cls,
5444 struct GNUNET_SERVER_Client *client,
5445 const struct GNUNET_MessageHeader *message)
5447 const struct TransportRequestConnectMessage *trcm =
5448 (const struct TransportRequestConnectMessage *) message;
5450 GNUNET_STATISTICS_update (stats,
5451 gettext_noop ("# REQUEST CONNECT messages received"),
5454 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5455 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5457 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5461 * Handle SET_QUOTA-message.
5463 * @param cls closure (always NULL)
5464 * @param client identification of the client
5465 * @param message the actual message
5468 handle_set_quota (void *cls,
5469 struct GNUNET_SERVER_Client *client,
5470 const struct GNUNET_MessageHeader *message)
5472 const struct QuotaSetMessage *qsm =
5473 (const struct QuotaSetMessage *) message;
5474 struct NeighbourList *n;
5476 GNUNET_STATISTICS_update (stats,
5477 gettext_noop ("# SET QUOTA messages received"),
5480 n = find_neighbour (&qsm->peer);
5483 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5484 GNUNET_STATISTICS_update (stats,
5485 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5492 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5494 (unsigned int) ntohl (qsm->quota.value__),
5495 (unsigned int) n->in_tracker.available_bytes_per_s__,
5496 GNUNET_i2s (&qsm->peer));
5498 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5500 if (0 == ntohl (qsm->quota.value__))
5502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5503 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5505 disconnect_neighbour (n, GNUNET_NO);
5507 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5512 * Take the given address and append it to the set of results sent back to
5515 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5516 * @param address the resolved name, NULL to indicate the last response
5519 transmit_address_to_client (void *cls, const char *address)
5521 struct GNUNET_SERVER_TransmitContext *tc = cls;
5524 if (NULL == address)
5527 slen = strlen (address) + 1;
5529 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5530 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5531 if (NULL == address)
5532 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5537 * Handle AddressLookup-message.
5539 * @param cls closure (always NULL)
5540 * @param client identification of the client
5541 * @param message the actual message
5544 handle_address_lookup (void *cls,
5545 struct GNUNET_SERVER_Client *client,
5546 const struct GNUNET_MessageHeader *message)
5548 const struct AddressLookupMessage *alum;
5549 struct TransportPlugin *lsPlugin;
5550 const char *nameTransport;
5551 const char *address;
5553 struct GNUNET_SERVER_TransmitContext *tc;
5554 struct GNUNET_TIME_Absolute timeout;
5555 struct GNUNET_TIME_Relative rtimeout;
5558 size = ntohs (message->size);
5559 if (size < sizeof (struct AddressLookupMessage))
5561 GNUNET_break_op (0);
5562 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5565 alum = (const struct AddressLookupMessage *) message;
5566 uint32_t addressLen = ntohl (alum->addrlen);
5567 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5569 GNUNET_break_op (0);
5570 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5573 address = (const char *) &alum[1];
5574 nameTransport = (const char *) &address[addressLen];
5576 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5578 GNUNET_break_op (0);
5579 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5582 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5583 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5584 numeric = ntohl (alum->numeric_only);
5585 lsPlugin = find_transport (nameTransport);
5586 if (NULL == lsPlugin)
5588 tc = GNUNET_SERVER_transmit_context_create (client);
5589 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5590 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5591 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5594 tc = GNUNET_SERVER_transmit_context_create (client);
5595 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5597 address, addressLen,
5600 &transmit_address_to_client, tc);
5605 * Setup the environment for this plugin.
5608 create_environment (struct TransportPlugin *plug)
5610 plug->env.cfg = cfg;
5611 plug->env.my_identity = &my_identity;
5612 plug->env.our_hello = &our_hello;
5613 plug->env.cls = plug;
5614 plug->env.receive = &plugin_env_receive;
5615 plug->env.notify_address = &plugin_env_notify_address;
5616 plug->env.session_end = &plugin_env_session_end;
5617 plug->env.max_connections = max_connect_per_transport;
5618 plug->env.stats = stats;
5623 * Start the specified transport (load the plugin).
5626 start_transport (struct GNUNET_SERVER_Handle *server,
5629 struct TransportPlugin *plug;
5632 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5633 _("Loading `%s' transport plugin\n"), name);
5634 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5635 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5636 create_environment (plug);
5637 plug->short_name = GNUNET_strdup (name);
5638 plug->lib_name = libname;
5639 plug->next = plugins;
5641 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5642 if (plug->api == NULL)
5644 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5645 _("Failed to load transport plugin for `%s'\n"), name);
5646 GNUNET_free (plug->short_name);
5647 plugins = plug->next;
5648 GNUNET_free (libname);
5655 * Called whenever a client is disconnected. Frees our
5656 * resources associated with that client.
5658 * @param cls closure
5659 * @param client identification of the client
5662 client_disconnect_notification (void *cls,
5663 struct GNUNET_SERVER_Client *client)
5665 struct TransportClient *pos;
5666 struct TransportClient *prev;
5667 struct ClientMessageQueueEntry *mqe;
5668 struct Blacklisters *bl;
5669 struct BlacklistCheck *bc;
5674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5675 "Client disconnected, cleaning up.\n");
5677 /* clean up blacklister */
5681 if (bl->client == client)
5686 if (bc->bl_pos == bl)
5688 bc->bl_pos = bl->next;
5691 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5694 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5695 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5701 GNUNET_CONTAINER_DLL_remove (bl_head,
5704 GNUNET_SERVER_client_drop (bl->client);
5710 /* clean up 'normal' clients */
5713 while ((pos != NULL) && (pos->client != client))
5720 while (NULL != (mqe = pos->message_queue_head))
5722 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5723 pos->message_queue_tail,
5725 pos->message_count--;
5729 clients = pos->next;
5731 prev->next = pos->next;
5732 if (GNUNET_YES == pos->tcs_pending)
5737 if (pos->th != NULL)
5739 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5742 GNUNET_break (0 == pos->message_count);
5748 * Function called when the service shuts down. Unloads our plugins
5749 * and cancels pending validations.
5751 * @param cls closure, unused
5752 * @param tc task context (unused)
5755 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5757 struct TransportPlugin *plug;
5758 struct OwnAddressList *al;
5759 struct CheckHelloValidatedContext *chvc;
5761 while (neighbours != NULL)
5763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5764 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5766 disconnect_neighbour (neighbours, GNUNET_NO);
5769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5770 "Transport service is unloading plugins...\n");
5772 while (NULL != (plug = plugins))
5774 plugins = plug->next;
5775 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5777 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5778 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5780 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5781 GNUNET_free (plug->lib_name);
5782 GNUNET_free (plug->short_name);
5783 while (NULL != (al = plug->addresses))
5785 plug->addresses = al->next;
5790 if (my_private_key != NULL)
5791 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5792 GNUNET_free_non_null (our_hello);
5794 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5797 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5798 validation_map = NULL;
5802 /* free 'chvc' data structure */
5803 while (NULL != (chvc = chvc_head))
5805 chvc_head = chvc->next;
5806 if (chvc->piter != NULL)
5808 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5809 GNUNET_STATISTICS_update (stats,
5810 gettext_noop ("# outstanding peerinfo iterate requests"),
5816 GNUNET_assert (chvc->ve_count == 0);
5823 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5826 if (peerinfo != NULL)
5828 GNUNET_PEERINFO_disconnect (peerinfo);
5831 /* Can we assume those are gone by now, or do we need to clean up
5833 GNUNET_break (bl_head == NULL);
5834 GNUNET_break (bc_head == NULL);
5838 static int ats_evaluate_results (int result, int solution, char * problem)
5840 int cont = GNUNET_NO;
5841 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5843 error_kind = GNUNET_ERROR_TYPE_ERROR;
5847 case GLP_ESTOP : /* search terminated by application */
5848 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5850 case GLP_EITLIM : /* iteration limit exceeded */
5851 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5854 case GLP_ETMLIM : /* time limit exceeded */
5855 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5857 case GLP_ENOPFS : /* no primal feasible solution */
5858 case GLP_ENODFS : /* no dual feasible solution */
5859 GNUNET_log (error_kind, "%s No feasible solution", problem);
5862 case GLP_EBADB : /* invalid basis */
5863 case GLP_ESING : /* singular matrix */
5864 case GLP_ECOND : /* ill-conditioned matrix */
5865 case GLP_EBOUND : /* invalid bounds */
5866 case GLP_EFAIL : /* solver failed */
5867 case GLP_EOBJLL : /* objective lower limit reached */
5868 case GLP_EOBJUL : /* objective upper limit reached */
5869 case GLP_EROOT : /* root LP optimum not provided */
5870 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5874 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5880 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
5883 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
5887 GNUNET_log (error_kind, "%s solution is %s feasible, however, its optimality (or non-optimality) has not been proven, \n", problem, (0==strcmp(problem,"LP")?"":"integer"));
5891 GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem, (0==strcmp(problem,"LP")?"":"integer "));
5894 GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
5897 GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
5905 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)
5911 glp_prob *prob = ats->prob;
5914 glp_init_smcp(&opt_lp);
5917 opt_lp.msg_lev = GLP_MSG_ALL;
5919 opt_lp.msg_lev = GLP_MSG_OFF;
5921 //opt_lp.presolve = GLP_ON;
5922 result = glp_simplex(prob, &opt_lp);
5923 solution = glp_get_status (prob);
5925 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
5929 glp_init_iocp(&opt_mlp);
5930 /* maximum duration */
5931 //opt_mlp.presolve = GLP_ON;
5932 opt_mlp.tm_lim = max_dur;
5935 opt_mlp.msg_lev = GLP_MSG_ALL;
5937 opt_mlp.msg_lev = GLP_MSG_OFF;
5939 result = glp_intopt (prob, &opt_mlp);
5940 solution = glp_mip_status (prob);
5941 res->solution = solution;
5942 res->valid = GNUNET_NO;
5943 if (ats_evaluate_results(result, solution, "MLP") == GNUNET_YES)
5944 res->valid = GNUNET_YES;
5948 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
5951 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5952 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5953 glp_write_lp (prob, NULL, filename);
5954 GNUNET_free (filename);
5956 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
5959 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5960 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5961 glp_print_sol (prob, filename);
5962 GNUNET_free (filename);
5967 int error = GNUNET_NO;
5969 struct ATS_mechanism *t = NULL;
5970 for (c=1; c<= (c_peers); c++ )
5973 t = peers[c].m_head;
5976 bw = glp_get_col_prim(prob, t->col_index);
5980 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);
5982 if (check ==GNUNET_YES)
5984 glp_write_sol(prob, "invalid_solution.mlp");
5985 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
5986 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
5989 if (check ==GNUNET_NO)
5997 if (glp_get_col_prim(prob,2*c_mechs+1) != 1)
6000 for (c=1; c<= available_quality_metrics; c++ )
6002 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));
6004 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));
6005 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));
6006 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));
6007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value: %f\n", glp_mip_obj_val(ats->prob));
6012 static void ats_delete_problem ()
6016 for (c=0; c< (ats->res).c_mechs; c++)
6017 GNUNET_free_non_null (ats->mechanisms[c].rc);
6019 if (ats->mechanisms!=NULL)
6021 GNUNET_free(ats->mechanisms);
6022 ats->mechanisms = NULL;
6024 if (ats->peers!=NULL)
6026 GNUNET_free(ats->peers);
6030 if (ats->prob != NULL)
6032 glp_delete_prob(ats->prob);
6036 ats->res.begin_cr = GNUNET_SYSERR;
6037 ats->res.begin_qm = GNUNET_SYSERR;
6038 ats->res.c_mechs = 0;
6039 ats->res.c_peers = 0;
6040 ats->res.end_cr = GNUNET_SYSERR;
6041 ats->res.end_qm = GNUNET_SYSERR;
6042 ats->res.solution = GNUNET_SYSERR;
6043 ats->res.valid = GNUNET_SYSERR;
6046 static void ats_update_problem_qm ()
6051 int c_q_metrics = available_quality_metrics;
6053 int *ja = GNUNET_malloc ((1 + ats->res.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6054 double *ar = GNUNET_malloc ((1 + ats->res.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6055 if (ats->res.c_mechs>10)
6056 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6057 row_index = ats->res.begin_qm;
6059 for (c=1; c <= c_q_metrics; c++)
6064 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6067 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6068 for (c2=1; c2<=ats->res.c_mechs; c2++)
6070 ja[array_index] = c2;
6072 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6075 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6076 if (v1 < 1) v0 = 0.1;
6077 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6078 if (v1 < 1) v0 = 0.1;
6079 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6080 if (v1 < 1) v0 = 0.1;
6081 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6084 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6087 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6089 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6091 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6093 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6095 value = (double) 10 / value;
6099 ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, row_index, ja[array_index], ar[array_index]);
6105 ja[array_index] = (2*ats->res.c_mechs) + 3 +c;
6106 ar[array_index] = -1;
6109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6111 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6117 GNUNET_free_non_null (ja);
6118 GNUNET_free_non_null (ar);
6123 static void ats_update_problem_cr ()
6129 double ct_max, ct_min;
6131 int *ja = GNUNET_malloc ((1 + ats->res.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6132 double *ar = GNUNET_malloc ((1 + ats->res.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6135 row_index = ats->res.begin_cr;
6137 for (c=0; c<available_ressources; c++)
6139 ct_max = ressources[c].c_max;
6140 ct_min = ressources[c].c_min;
6142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6144 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6146 for (c2=1; c2<=ats->res.c_mechs; c2++)
6149 ja[array_index] = c2;
6150 value = ats->mechanisms[c2].addr->ressources[c].c;
6151 ar[array_index] = value;
6153 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, rowrow_indexs, ja[array_index], ar[array_index]);
6157 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6163 GNUNET_free_non_null (ja);
6164 GNUNET_free_non_null (ar);
6168 /** solve the bandwidth distribution problem
6169 * @param max_it maximum iterations
6170 * @param max_dur maximum duration in ms
6171 * @param D weight for diversity
6172 * @param U weight for utility
6173 * @param R weight for relativity
6174 * @param v_b_min minimal bandwidth per peer
6175 * @param v_n_min minimum number of connections
6176 * @param res result struct
6177 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6179 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
6181 if (ats->prob != NULL)
6182 glp_delete_prob(ats->prob);
6184 ats->prob = glp_create_prob();
6190 int c_c_ressources = available_ressources;
6191 int c_q_metrics = available_quality_metrics;
6193 double M = VERY_BIG_DOUBLE_VALUE;
6194 double Q[c_q_metrics+1];
6195 for (c=1; c<=c_q_metrics; c++)
6200 struct NeighbourList *next = neighbours;
6203 struct ReadyList *r_next = next->plugins;
6204 while (r_next != NULL)
6206 struct ForeignAddressList * a_next = r_next->addresses;
6207 while (a_next != NULL)
6210 a_next = a_next->next;
6212 r_next = r_next->next;
6221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6223 res->valid = GNUNET_NO;
6226 return GNUNET_SYSERR;
6229 ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6230 ats->peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6232 struct ATS_mechanism * mechanisms = ats->mechanisms;
6233 struct ATS_peer * peers = ats->peers;
6240 peers[c_peers].peer = next->id;
6241 peers[c_peers].m_head = NULL;
6242 peers[c_peers].m_tail = NULL;
6244 peers[c_peers].f = 1.0 / c_mechs;
6246 struct ReadyList *r_next = next->plugins;
6247 while (r_next != NULL)
6249 struct ForeignAddressList * a_next = r_next->addresses;
6250 while (a_next != NULL)
6252 mechanisms[c_mechs].addr = a_next;
6253 mechanisms[c_mechs].col_index = c_mechs;
6254 mechanisms[c_mechs].peer = &peers[c_peers];
6255 mechanisms[c_mechs].next = NULL;
6256 mechanisms[c_mechs].plugin = r_next->plugin;
6258 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6260 a_next = a_next->next;
6262 r_next = r_next->next;
6270 if (v_n_min > c_peers)
6274 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);
6277 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6280 int * ia = GNUNET_malloc (size * sizeof (int));
6281 int * ja = GNUNET_malloc (size * sizeof (int));
6282 double * ar = GNUNET_malloc(size* sizeof (double));
6284 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6285 glp_set_obj_dir(ats->prob, GLP_MAX);
6287 /* adding columns */
6289 glp_add_cols(ats->prob, 2 * c_mechs);
6290 /* adding b_t cols */
6291 for (c=1; c <= c_mechs; c++)
6294 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6295 glp_set_col_name(ats->prob, c, name);
6297 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6298 glp_set_obj_coef(ats->prob, c, 0);
6301 /* adding n_t cols */
6302 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6304 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6305 glp_set_col_name(ats->prob, c, name);
6307 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6308 glp_set_col_kind(ats->prob, c, GLP_IV);
6309 glp_set_obj_coef(ats->prob, c, 0);
6312 /* feasibility constraints */
6313 /* Constraint 1: one address per peer*/
6315 glp_add_rows(ats->prob, c_peers);
6316 for (c=1; c<=c_peers; c++)
6318 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6320 struct ATS_mechanism *m = peers[c].m_head;
6323 ia[array_index] = row_index;
6324 ja[array_index] = (c_mechs + m->col_index);
6325 ar[array_index] = 1;
6327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6335 /* Constraint 2: only active mechanism gets bandwidth assigned */
6336 glp_add_rows(ats->prob, c_mechs);
6337 for (c=1; c<=c_mechs; c++)
6339 /* b_t - n_t * M <= 0 */
6341 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6343 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6345 ia[array_index] = row_index;
6346 ja[array_index] = mechanisms[c].col_index;
6347 ar[array_index] = 1;
6349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6352 ia[array_index] = row_index;
6353 ja[array_index] = c_mechs + mechanisms[c].col_index;
6354 ar[array_index] = -M;
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 3: minimum bandwidth*/
6363 glp_add_rows(ats->prob, c_mechs);
6364 for (c=1; c<=c_mechs; c++)
6366 /* b_t - n_t * b_min <= 0 */
6368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6370 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6372 ia[array_index] = row_index;
6373 ja[array_index] = mechanisms[c].col_index;
6374 ar[array_index] = 1;
6376 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6379 ia[array_index] = row_index;
6380 ja[array_index] = c_mechs + mechanisms[c].col_index;
6381 ar[array_index] = -v_b_min;
6383 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6389 /* Constraint 4: max ressource capacity */
6390 /* V cr: bt * ct_r <= cr_max
6392 glp_add_rows(ats->prob, available_ressources);
6393 double ct_max = VERY_BIG_DOUBLE_VALUE;
6394 double ct_min = 0.0;
6396 res->begin_cr = array_index;
6398 for (c=0; c<available_ressources; c++)
6400 ct_max = ressources[c].c_max;
6401 ct_min = ressources[c].c_min;
6403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6405 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6407 for (c2=1; c2<=c_mechs; c2++)
6410 ia[array_index] = row_index;
6411 ja[array_index] = c2;
6412 value = mechanisms[c2].addr->ressources[c].c;
6413 ar[array_index] = value;
6415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6421 res->end_cr = array_index--;
6423 /* Constraint 5: min number of connections*/
6424 glp_add_rows(ats->prob, 1);
6425 for (c=1; c<=c_mechs; c++)
6427 // b_t - n_t * b_min >= 0
6429 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6431 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6433 ia[array_index] = row_index;
6434 ja[array_index] = c_mechs + mechanisms[c].col_index;
6435 ar[array_index] = 1;
6437 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6443 // optimisation constraints
6447 // Constraint 6: optimize for diversity
6448 glp_add_cols(ats->prob, 1);
6449 glp_set_col_name(ats->prob, (2*c_mechs) + 1, "d");
6450 glp_set_obj_coef(ats->prob, (2*c_mechs) + 1, D);
6451 glp_set_col_bnds(ats->prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6452 glp_add_rows(ats->prob, 1);
6454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6456 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6457 for (c=1; c<=c_mechs; c++)
6459 // b_t - n_t * b_min >= 0
6460 ia[array_index] = row_index;
6461 ja[array_index] = c_mechs + mechanisms[c].col_index;
6462 ar[array_index] = 1;
6464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6468 ia[array_index] = row_index;
6469 ja[array_index] = (2*c_mechs) + 1;
6470 ar[array_index] = -1;
6472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6477 // Constraint 8: optimize bandwidth utility
6478 glp_add_cols(ats->prob, 1);
6479 glp_set_col_name(ats->prob, (2*c_mechs) + 2, "u");
6480 glp_set_obj_coef(ats->prob, (2*c_mechs) + 2, U);
6481 glp_set_col_bnds(ats->prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6482 glp_add_rows(ats->prob, 1);
6484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6486 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6487 for (c=1; c<=c_mechs; c++)
6489 ia[array_index] = row_index;
6490 ja[array_index] = c;
6491 ar[array_index] = mechanisms[c].peer->f;
6493 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6497 ia[array_index] = row_index;
6498 ja[array_index] = (2*c_mechs) + 2;
6499 ar[array_index] = -1;
6501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6507 // Constraint 9: optimize relativity
6508 glp_add_cols(ats->prob, 1);
6509 glp_set_col_name(ats->prob, (2*c_mechs) + 3, "r");
6510 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3, R);
6511 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6512 glp_add_rows(ats->prob, c_peers);
6513 for (c=1; c<=c_peers; c++)
6515 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6517 struct ATS_mechanism *m = peers[c].m_head;
6520 ia[array_index] = row_index;
6521 ja[array_index] = m->col_index;
6522 ar[array_index] = 1 / mechanisms[c].peer->f;
6524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6529 ia[array_index] = row_index;
6530 ja[array_index] = (2*c_mechs) + 3;
6531 ar[array_index] = -1;
6533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6540 // Constraint 7: optimize for quality
6541 glp_add_cols(ats->prob, c_q_metrics);
6542 for (c=1; c<= c_q_metrics; c++)
6544 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6545 glp_set_col_name(ats->prob, (2*c_mechs) + 3 + c, name);
6546 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6548 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3 + c, Q[c]);
6550 glp_add_rows(ats->prob, available_quality_metrics);
6551 res->begin_qm = row_index;
6552 for (c=1; c <= c_q_metrics; c++)
6555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6558 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6559 for (c2=1; c2<=c_mechs; c2++)
6562 ia[array_index] = row_index;
6563 ja[array_index] = c2;
6564 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6567 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6568 if (v1 < 1) v0 = 0.1;
6569 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6570 if (v1 < 1) v0 = 0.1;
6571 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6572 if (v1 < 1) v0 = 0.1;
6573 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6576 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6579 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6581 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6583 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6585 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6587 value = (double) 10 / value;
6591 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6593 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]);
6598 ia[array_index] = row_index;
6599 ja[array_index] = (2*c_mechs) + 3 +c;
6600 ar[array_index] = -1;
6602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6607 res->end_qm = row_index-1;
6609 /* Loading the matrix */
6610 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6612 res->c_mechs = c_mechs;
6613 res->c_peers = c_peers;
6615 res->valid = GNUNET_YES;
6627 void ats_notify_ats_data (
6628 const struct GNUNET_PeerIdentity *peer,
6629 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6632 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6634 ats_calculate_bandwidth_distribution(ats);
6640 ats_calculate_bandwidth_distribution ()
6643 struct GNUNET_TIME_Absolute start;
6644 struct GNUNET_TIME_Relative duration;
6646 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6647 if (delta.rel_value < ats->min_delta.rel_value)
6650 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6656 if (INT_MAX < ats->max_exec_duration.rel_value)
6659 dur = (int) ats->max_exec_duration.rel_value;
6661 start = GNUNET_TIME_absolute_get();
6662 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6664 ats->modified_addr = GNUNET_NO;
6665 ats_delete_problem ();
6666 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->res);
6668 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... new problem: %i peer, %i mechs\n", ats->res.c_peers, ats->res.c_mechs);
6671 else if (ats->modified_resources == GNUNET_YES)
6673 ats_update_problem_cr();
6675 else if (ats->modified_quality == GNUNET_YES)
6677 ats_update_problem_qm();
6680 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6683 if (ats->res.valid == GNUNET_YES)
6685 ats->res.solution = GNUNET_SYSERR;
6686 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->res.c_peers, ats->res.c_mechs, &ats->res);
6687 if (ats->res.solution != 5)
6688 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem solution is not optimal: %i\n", ats->res.solution);
6691 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6693 if (ats->res.valid == GNUNET_YES)
6697 if (ats->res.c_mechs > 8)
6698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", ats->res.c_mechs, duration.rel_value);
6700 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6701 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->res.c_mechs, GNUNET_NO);
6702 GNUNET_STATISTICS_set (stats, "ATS peers", ats->res.c_peers, GNUNET_NO);
6703 GNUNET_STATISTICS_set (stats, "ATS solution", ats->res.solution, GNUNET_NO);
6704 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6707 else if (ats->res.valid == GNUNET_NO)
6709 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6712 ats->last = GNUNET_TIME_absolute_get();
6714 ats->modified_addr = GNUNET_NO;
6715 ats->modified_resources = GNUNET_NO;
6716 ats->modified_quality = GNUNET_NO;
6724 ats_schedule_calculation (void *cls,
6725 const struct GNUNET_SCHEDULER_TaskContext *tc)
6727 struct ATS_info *ats = (struct ATS_info *) cls;
6731 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6732 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6739 ats_calculate_bandwidth_distribution (ats);
6741 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6742 &ats_schedule_calculation, ats);
6748 unsigned long long value;
6751 ats = GNUNET_malloc(sizeof (struct ATS_info));
6753 ats->min_delta = ATS_MIN_INTERVAL;
6754 ats->exec_intervall = ATS_EXEC_INTERVAL;
6755 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6756 ats->max_iterations = ATS_MAX_ITERATIONS;
6757 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active");
6767 ats->v_b_min = 64000;
6773 /* loading cost ressources */
6774 for (c=0; c<available_ressources; c++)
6776 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6777 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6779 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6784 ressources[c].c_max = value;
6787 GNUNET_free (section);
6788 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6789 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6791 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6796 ressources[c].c_min = value;
6799 GNUNET_free (section);
6802 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6803 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6805 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6806 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6808 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6812 static void ats_shutdown ()
6815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6817 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6818 GNUNET_SCHEDULER_cancel(ats->ats_task);
6819 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6821 ats_delete_problem ();
6827 void ats_notify_peer_connect (
6828 const struct GNUNET_PeerIdentity *peer,
6829 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
6832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6835 //update_addr_ats();
6836 ats->modified_addr = GNUNET_YES;
6838 ats_calculate_bandwidth_distribution(ats);
6841 void ats_notify_peer_disconnect (
6842 const struct GNUNET_PeerIdentity *peer)
6845 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6848 ats->modified_addr = GNUNET_YES;
6850 ats_calculate_bandwidth_distribution (ats);
6853 struct ForeignAddressList * ats_get_preferred_address (
6854 struct NeighbourList *n)
6857 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6859 struct ReadyList *next = n->plugins;
6860 while (next != NULL)
6863 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6867 return find_ready_address(n);
6871 * Initiate transport service.
6873 * @param cls closure
6874 * @param server the initialized server
6875 * @param c configuration to use
6879 struct GNUNET_SERVER_Handle *server,
6880 const struct GNUNET_CONFIGURATION_Handle *c)
6882 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6883 {&handle_start, NULL,
6884 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6885 {&handle_hello, NULL,
6886 GNUNET_MESSAGE_TYPE_HELLO, 0},
6887 {&handle_send, NULL,
6888 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6889 {&handle_request_connect, NULL,
6890 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6891 {&handle_set_quota, NULL,
6892 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6893 {&handle_address_lookup, NULL,
6894 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6896 {&handle_blacklist_init, NULL,
6897 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6898 {&handle_blacklist_reply, NULL,
6899 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6905 unsigned long long tneigh;
6909 stats = GNUNET_STATISTICS_create ("transport", cfg);
6910 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6911 /* parse configuration */
6913 GNUNET_CONFIGURATION_get_value_number (c,
6918 GNUNET_CONFIGURATION_get_value_filename (c,
6920 "HOSTKEY", &keyfile)))
6922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6924 ("Transport service is lacking key configuration settings. Exiting.\n"));
6925 GNUNET_SCHEDULER_shutdown ();
6928 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6931 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6932 validation_map = NULL;
6936 max_connect_per_transport = (uint32_t) tneigh;
6937 peerinfo = GNUNET_PEERINFO_connect (cfg);
6938 if (peerinfo == NULL)
6940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6941 _("Could not access PEERINFO service. Exiting.\n"));
6942 GNUNET_SCHEDULER_shutdown ();
6945 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6948 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6949 validation_map = NULL;
6950 GNUNET_free (keyfile);
6953 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6954 GNUNET_free (keyfile);
6955 if (my_private_key == NULL)
6957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6959 ("Transport service could not access hostkey. Exiting.\n"));
6960 GNUNET_SCHEDULER_shutdown ();
6963 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6966 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6967 validation_map = NULL;
6970 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6971 GNUNET_CRYPTO_hash (&my_public_key,
6972 sizeof (my_public_key), &my_identity.hashPubKey);
6973 /* setup notification */
6974 GNUNET_SERVER_disconnect_notify (server,
6975 &client_disconnect_notification, NULL);
6976 /* load plugins... */
6979 GNUNET_CONFIGURATION_get_value_string (c,
6980 "TRANSPORT", "PLUGINS", &plugs))
6982 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6983 _("Starting transport plugins `%s'\n"), plugs);
6984 pos = strtok (plugs, " ");
6987 start_transport (server, pos);
6989 pos = strtok (NULL, " ");
6991 GNUNET_free (plugs);
6993 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6994 &shutdown_task, NULL);
7001 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7003 /* If we have a blacklist file, read from it */
7004 read_blacklist_file(cfg);
7005 /* process client requests */
7006 GNUNET_SERVER_add_handlers (server, handlers);
7011 * The main function for the transport service.
7013 * @param argc number of arguments from the command line
7014 * @param argv command line arguments
7015 * @return 0 ok, 1 on error
7018 main (int argc, char *const *argv)
7020 a2s (NULL, NULL, 0); /* make compiler happy */
7021 return (GNUNET_OK ==
7022 GNUNET_SERVICE_run (argc,
7025 GNUNET_SERVICE_OPTION_NONE,
7026 &run, NULL)) ? 0 : 1;
7029 /* end of gnunet-service-transport.c */