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 #define ATS_Q_UPDATED 1
159 #define ATS_C_UPDATED 2
160 #define ATS_QC_UPDATED 3
161 #define ATS_UNMODIFIED 4
164 * List of addresses of other peers
166 struct ForeignAddressList
169 * This is a linked list.
171 struct ForeignAddressList *next;
174 * Which ready list does this entry belong to.
176 struct ReadyList *ready_list;
179 * How long until we auto-expire this address (unless it is
180 * re-confirmed by the transport)?
182 struct GNUNET_TIME_Absolute expires;
185 * Task used to re-validate addresses, updates latencies and
188 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
196 * Session (or NULL if no valid session currently exists or if the
197 * plugin does not use sessions).
199 struct Session *session;
201 struct ATS_ressource_entry * ressources;
203 struct ATS_quality_entry * quality;
206 * What was the last latency observed for this address, plugin and peer?
208 struct GNUNET_TIME_Relative latency;
211 * If we did not successfully transmit a message to the given peer
212 * via this connection during the specified time, we should consider
213 * the connection to be dead. This is used in the case that a TCP
214 * transport simply stalls writing to the stream but does not
215 * formerly get a signal that the other peer died.
217 struct GNUNET_TIME_Absolute timeout;
220 * How often have we tried to connect using this plugin? Used to
221 * discriminate against addresses that do not work well.
222 * FIXME: not yet used, but should be!
224 unsigned int connect_attempts;
227 * DV distance to this peer (1 if no DV is used).
228 * FIXME: need to set this from transport plugins!
238 * Have we ever estimated the latency of this address? Used to
239 * ensure that the first time we add an address, we immediately
245 * Are we currently connected via this address? The first time we
246 * successfully transmit or receive data to a peer via a particular
247 * address, we set this to GNUNET_YES. If we later get an error
248 * (disconnect notification, transmission failure, timeout), we set
249 * it back to GNUNET_NO.
254 * Is this plugin currently busy transmitting to the specific target?
255 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
256 * messages do not count as 'in transmit'.
261 * Has this address been validated yet?
269 * Entry in linked list of network addresses for ourselves. Also
270 * includes a cached signature for 'struct TransportPongMessage's.
272 struct OwnAddressList
275 * This is a linked list.
277 struct OwnAddressList *next;
280 * How long until we actually auto-expire this address (unless it is
281 * re-confirmed by the transport)?
283 struct GNUNET_TIME_Absolute expires;
286 * How long until the current signature expires? (ZERO if the
287 * signature was never created).
289 struct GNUNET_TIME_Absolute pong_sig_expires;
292 * Signature for a 'struct TransportPongMessage' for this address.
294 struct GNUNET_CRYPTO_RsaSignature pong_signature;
305 * Entry in linked list of all of our plugins.
307 struct TransportPlugin
311 * This is a linked list.
313 struct TransportPlugin *next;
316 * API of the transport as returned by the plugin's
317 * initialization function.
319 struct GNUNET_TRANSPORT_PluginFunctions *api;
322 * Short name for the plugin (i.e. "tcp").
327 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
332 * List of our known addresses for this transport.
334 struct OwnAddressList *addresses;
337 * Environment this transport service is using
340 struct GNUNET_TRANSPORT_PluginEnvironment env;
343 * ID of task that is used to clean up expired addresses.
345 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
348 * Set to GNUNET_YES if we need to scrap the existing list of
349 * "addresses" and start fresh when we receive the next address
350 * update from a transport. Set to GNUNET_NO if we should just add
351 * the new address to the list and wait for the commit call.
355 struct ATS_plugin * rc;
358 * Hashmap of blacklisted peers for this particular transport.
360 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
363 struct NeighbourList;
366 * For each neighbour we keep a list of messages
367 * that we still want to transmit to the neighbour.
373 * This is a doubly linked list.
375 struct MessageQueue *next;
378 * This is a doubly linked list.
380 struct MessageQueue *prev;
383 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
384 * stuck together in memory. Allocated at the end of this struct.
386 const char *message_buf;
389 * Size of the message buf
391 size_t message_buf_size;
394 * Client responsible for queueing the message;
395 * used to check that a client has no two messages
396 * pending for the same target. Can be NULL.
398 struct TransportClient *client;
401 * Using which specific address should we send this message?
403 struct ForeignAddressList *specific_address;
406 * Peer ID of the Neighbour this entry belongs to.
408 struct GNUNET_PeerIdentity neighbour_id;
411 * Plugin that we used for the transmission.
412 * NULL until we scheduled a transmission.
414 struct TransportPlugin *plugin;
417 * At what time should we fail?
419 struct GNUNET_TIME_Absolute timeout;
422 * Internal message of the transport system that should not be
423 * included in the usual SEND-SEND_OK transmission confirmation
424 * traffic management scheme. Typically, "internal_msg" will
425 * be set whenever "client" is NULL (but it is not strictly
431 * How important is the message?
433 unsigned int priority;
439 * For a given Neighbour, which plugins are available
440 * to talk to this peer and what are their costs?
445 * This is a linked list.
447 struct ReadyList *next;
450 * Which of our transport plugins does this entry
453 struct TransportPlugin *plugin;
456 * Transport addresses, latency, and readiness for
457 * this particular plugin.
459 struct ForeignAddressList *addresses;
462 * To which neighbour does this ready list belong to?
464 struct NeighbourList *neighbour;
469 * Entry in linked list of all of our current neighbours.
475 * This is a linked list.
477 struct NeighbourList *next;
480 * Which of our transports is connected to this peer
481 * and what is their status?
483 struct ReadyList *plugins;
486 * Head of list of messages we would like to send to this peer;
487 * must contain at most one message per client.
489 struct MessageQueue *messages_head;
492 * Tail of list of messages we would like to send to this peer; must
493 * contain at most one message per client.
495 struct MessageQueue *messages_tail;
498 * Buffer for at most one payload message used when we receive
499 * payload data before our PING-PONG has succeeded. We then
500 * store such messages in this intermediary buffer until the
501 * connection is fully up.
503 struct GNUNET_MessageHeader *pre_connect_message_buffer;
506 * Context for peerinfo iteration.
507 * NULL after we are done processing peerinfo's information.
509 struct GNUNET_PEERINFO_IteratorContext *piter;
512 * Public key for this peer. Valid only if the respective flag is set below.
514 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
517 * Identity of this neighbour.
519 struct GNUNET_PeerIdentity id;
522 * ID of task scheduled to run when this peer is about to
523 * time out (will free resources associated with the peer).
525 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
528 * ID of task scheduled to run when we should retry transmitting
529 * the head of the message queue. Actually triggered when the
530 * transmission is timing out (we trigger instantly when we have
531 * a chance of success).
533 GNUNET_SCHEDULER_TaskIdentifier retry_task;
536 * How long until we should consider this peer dead
537 * (if we don't receive another message in the
540 struct GNUNET_TIME_Absolute peer_timeout;
543 * Tracker for inbound bandwidth.
545 struct GNUNET_BANDWIDTH_Tracker in_tracker;
548 * The latency we have seen for this particular address for
549 * this particular peer. This latency may have been calculated
550 * over multiple transports. This value reflects how long it took
551 * us to receive a response when SENDING via this particular
552 * transport/neighbour/address combination!
554 * FIXME: we need to periodically send PINGs to update this
555 * latency (at least more often than the current "huge" (11h?)
558 struct GNUNET_TIME_Relative latency;
561 * How often has the other peer (recently) violated the
562 * inbound traffic limit? Incremented by 10 per violation,
563 * decremented by 1 per non-violation (for each
566 unsigned int quota_violation_count;
569 * DV distance to this peer (1 if no DV is used).
574 * Have we seen an PONG from this neighbour in the past (and
575 * not had a disconnect since)?
580 * Do we have a valid public key for this neighbour?
582 int public_key_valid;
585 * Performance data for the peer.
587 struct GNUNET_TRANSPORT_ATS_Information *ats;
590 * Identity of the neighbour.
592 struct GNUNET_PeerIdentity peer;
597 * Message used to ask a peer to validate receipt (to check an address
598 * from a HELLO). Followed by the address we are trying to validate,
599 * or an empty address if we are just sending a PING to confirm that a
600 * connection which the receiver (of the PING) initiated is still valid.
602 struct TransportPingMessage
606 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
608 struct GNUNET_MessageHeader header;
611 * Challenge code (to ensure fresh reply).
613 uint32_t challenge GNUNET_PACKED;
616 * Who is the intended recipient?
618 struct GNUNET_PeerIdentity target;
624 * Message used to validate a HELLO. The challenge is included in the
625 * confirmation to make matching of replies to requests possible. The
626 * signature signs our public key, an expiration time and our address.<p>
628 * This message is followed by our transport address that the PING tried
629 * to confirm (if we liked it). The address can be empty (zero bytes)
630 * if the PING had not address either (and we received the request via
631 * a connection that we initiated).
633 struct TransportPongMessage
637 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
639 struct GNUNET_MessageHeader header;
642 * Challenge code from PING (showing freshness). Not part of what
643 * is signed so that we can re-use signatures.
645 uint32_t challenge GNUNET_PACKED;
650 struct GNUNET_CRYPTO_RsaSignature signature;
653 * What are we signing and why? Two possible reason codes can be here:
654 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
655 * plausible address for this peer (pid is set to identity of signer); or
656 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
657 * an address we used to connect to the peer with the given pid.
659 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
662 * When does this signature expire?
664 struct GNUNET_TIME_AbsoluteNBO expiration;
667 * Either the identity of the peer Who signed this message, or the
668 * identity of the peer that we're connected to using the given
669 * address (depending on purpose.type).
671 struct GNUNET_PeerIdentity pid;
674 * Size of address appended to this message (part of what is
675 * being signed, hence not redundant).
683 * Linked list of messages to be transmitted to the client. Each
684 * entry is followed by the actual message.
686 struct ClientMessageQueueEntry
689 * This is a doubly-linked list.
691 struct ClientMessageQueueEntry *next;
694 * This is a doubly-linked list.
696 struct ClientMessageQueueEntry *prev;
701 * Client connected to the transport service.
703 struct TransportClient
707 * This is a linked list.
709 struct TransportClient *next;
712 * Handle to the client.
714 struct GNUNET_SERVER_Client *client;
717 * Linked list of messages yet to be transmitted to
720 struct ClientMessageQueueEntry *message_queue_head;
723 * Tail of linked list of messages yet to be transmitted to the
726 struct ClientMessageQueueEntry *message_queue_tail;
729 * Current transmit request handle.
731 struct GNUNET_CONNECTION_TransmitHandle *th;
734 * Is a call to "transmit_send_continuation" pending? If so, we
735 * must not free this struct (even if the corresponding client
736 * disconnects) and instead only remove it from the linked list and
737 * set the "client" field to NULL.
742 * Length of the list of messages pending for this client.
744 unsigned int message_count;
750 * Context of currently active requests to peerinfo
751 * for validation of HELLOs.
753 struct CheckHelloValidatedContext;
757 * Entry in map of all HELLOs awaiting validation.
759 struct ValidationEntry
763 * NULL if this entry is not part of a larger HELLO validation.
765 struct CheckHelloValidatedContext *chvc;
768 * The address, actually a pointer to the end
769 * of this struct. Do not free!
774 * Name of the transport.
776 char *transport_name;
779 * The public key of the peer.
781 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
784 * ID of task that will clean up this entry if we don't succeed
785 * with the validation first.
787 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
790 * At what time did we send this validation?
792 struct GNUNET_TIME_Absolute send_time;
795 * Session being validated (or NULL for none).
797 struct Session *session;
800 * Challenge number we used.
813 * Context of currently active requests to peerinfo
814 * for validation of HELLOs.
816 struct CheckHelloValidatedContext
820 * This is a doubly-linked list.
822 struct CheckHelloValidatedContext *next;
825 * This is a doubly-linked list.
827 struct CheckHelloValidatedContext *prev;
830 * Hello that we are validating.
832 const struct GNUNET_HELLO_Message *hello;
835 * Context for peerinfo iteration.
836 * NULL after we are done processing peerinfo's information.
838 struct GNUNET_PEERINFO_IteratorContext *piter;
841 * Was a HELLO known for this peer to peerinfo?
846 * Number of validation entries currently referring to this
849 unsigned int ve_count;
852 struct ATS_quality_metric
861 struct ATS_mechanism * prev;
862 struct ATS_mechanism * next;
863 struct ForeignAddressList * addr;
864 struct TransportPlugin * plugin;
865 struct ATS_peer * peer;
868 struct ATS_ressource_cost * rc;
874 struct GNUNET_PeerIdentity peer;
875 struct NeighbourList * n;
876 struct ATS_mechanism * m_head;
877 struct ATS_mechanism * m_tail;
879 /* preference value f */
887 * result of last GLPK run
893 * Ressource costs or quality metrics changed
894 * update problem before solving
896 int modified_resources;
899 * Ressource costs or quality metrics changed, update matrix
900 * update problem before solving
902 int modified_quality;
905 * Peers have connected or disconnected
906 * problem has to be recreated
908 int recreate_problem;
911 * Was the available basis invalid and we needed to rerun simplex?
913 int simplex_rerun_required;
916 * is problem currently valid and can it be solved
921 * Number of transport mechanisms in the problem
926 * Number of transport mechanisms in the problem
931 * row index where quality related rows start
936 * row index where quality related rows end
941 * row index where ressource cost related rows start
946 * row index where ressource cost related rows end
951 * column index for objective function value d
956 * column index for objective function value u
961 * column index for objective function value r
966 * column index for objective function value quality metrics
971 * column index for objective function value cost ressources
976 struct ATS_ressource_entry
978 /* index in ressources array */
980 /* depending ATSi parameter to calculcate limits */
989 /* index in ressources array */
991 /* depending ATSi parameter to calculcate limits */
993 /* cfg option to load limits */
1000 /* cofficients for the specific plugins */
1010 static struct ATS_ressource ressources[] =
1012 /* FIXME: the coefficients for the specific plugins */
1013 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
1014 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
1015 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
1017 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
1018 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
1019 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
1020 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
1023 static int available_ressources = 3;
1031 * Time of last execution
1033 struct GNUNET_TIME_Absolute last;
1035 * Minimum intervall between two executions
1037 struct GNUNET_TIME_Relative min_delta;
1039 * Regular intervall when execution is triggered
1041 struct GNUNET_TIME_Relative exec_interval;
1043 * Maximum execution time per calculation
1045 struct GNUNET_TIME_Relative max_exec_duration;
1049 * GLPK (MLP) problem object
1055 * task to recalculate the bandwidth assignment
1057 GNUNET_SCHEDULER_TaskIdentifier ats_task;
1060 * Current state of the GLPK problem
1062 struct ATS_stat stat;
1065 * mechanisms used in current problem
1066 * needed for problem modification
1068 struct ATS_mechanism * mechanisms;
1071 * peers used in current problem
1072 * needed for problem modification
1074 struct ATS_peer * peers;
1077 * number of successful executions
1079 int successful_executions;
1082 * number with an invalid result
1084 int invalid_executions;
1087 * Maximum number of LP iterations per calculation
1092 * Dump problem to a file?
1097 * Dump solution to a file
1102 * Dump solution when minimum peers:
1107 * Dump solution when minimum addresses:
1112 * Dump solution overwrite file:
1132 * Minimum bandwidth per peer
1137 * Minimum number of connections per peer
1144 * Our HELLO message.
1146 static struct GNUNET_HELLO_Message *our_hello;
1151 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1156 static struct GNUNET_PeerIdentity my_identity;
1161 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1164 * Our configuration.
1166 const struct GNUNET_CONFIGURATION_Handle *cfg;
1169 * Linked list of all clients to this service.
1171 static struct TransportClient *clients;
1174 * All loaded plugins.
1176 static struct TransportPlugin *plugins;
1179 * Handle to peerinfo service.
1181 static struct GNUNET_PEERINFO_Handle *peerinfo;
1184 * All known neighbours and their HELLOs.
1186 static struct NeighbourList *neighbours;
1189 * Number of neighbours we'd like to have.
1191 static uint32_t max_connect_per_transport;
1194 * Head of linked list.
1196 static struct CheckHelloValidatedContext *chvc_head;
1199 * Tail of linked list.
1201 static struct CheckHelloValidatedContext *chvc_tail;
1204 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1205 * of the given peer that we are currently validating).
1207 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1210 * Handle for reporting statistics.
1212 static struct GNUNET_STATISTICS_Handle *stats;
1215 * Handle for ats information
1217 static struct ATS_info *ats;
1219 struct ATS_quality_entry
1227 static struct ATS_quality_metric qm[] =
1229 {1, 1028, "QUALITY_NET_DISTANCE"},
1230 {2, 1034, "QUALITY_NET_DELAY"},
1232 static int available_quality_metrics = 2;
1236 * The peer specified by the given neighbour has timed-out or a plugin
1237 * has disconnected. We may either need to do nothing (other plugins
1238 * still up), or trigger a full disconnect and clean up. This
1239 * function updates our state and do the necessary notifications.
1240 * Also notifies our clients that the neighbour is now officially
1243 * @param n the neighbour list entry for the peer
1244 * @param check should we just check if all plugins
1245 * disconnected or must we ask all plugins to
1248 static void disconnect_neighbour (struct NeighbourList *n, int check);
1251 * Check the ready list for the given neighbour and if a plugin is
1252 * ready for transmission (and if we have a message), do so!
1254 * @param nexi target peer for which to transmit
1256 static void try_transmission_to_peer (struct NeighbourList *n);
1258 static void ats_shutdown ( );
1260 static void ats_notify_peer_connect (
1261 const struct GNUNET_PeerIdentity *peer,
1262 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
1264 static void ats_notify_peer_disconnect (
1265 const struct GNUNET_PeerIdentity *peer);
1268 static void ats_notify_ats_data (
1269 const struct GNUNET_PeerIdentity *peer,
1270 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1273 struct ForeignAddressList * ats_get_preferred_address (
1274 struct NeighbourList *n);
1277 ats_calculate_bandwidth_distribution ();
1280 * Find an entry in the neighbour list for a particular peer.
1282 * @return NULL if not found.
1284 static struct NeighbourList *
1285 find_neighbour (const struct GNUNET_PeerIdentity *key)
1287 struct NeighbourList *head = neighbours;
1289 while ((head != NULL) &&
1290 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1295 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1298 int set = GNUNET_NO;
1299 for (c=0; c<available_quality_metrics; c++)
1301 if (ats_index == qm[c].atis_index)
1303 fal->quality[c].values[0] = fal->quality[c].values[1];
1304 fal->quality[c].values[1] = fal->quality[c].values[2];
1305 fal->quality[c].values[2] = value;
1307 ats->stat.modified_quality = GNUNET_YES;
1310 if (set == GNUNET_NO)
1312 for (c=0; c<available_ressources; c++)
1314 if (ats_index == ressources[c].atis_index)
1316 fal->ressources[c].c = value;
1318 ats->stat.modified_resources = GNUNET_YES;
1327 update_addr_ats (struct ForeignAddressList *fal,
1328 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1333 for (c1=0; c1<ats_count; c1++)
1335 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1341 * Find an entry in the transport list for a particular transport.
1343 * @return NULL if not found.
1345 static struct TransportPlugin *
1346 find_transport (const char *short_name)
1348 struct TransportPlugin *head = plugins;
1349 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1355 * Is a particular peer blacklisted for a particular transport?
1357 * @param peer the peer to check for
1358 * @param plugin the plugin used to connect to the peer
1360 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1363 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1366 if (plugin->blacklist != NULL)
1368 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1372 "Peer `%s:%s' is blacklisted!\n",
1373 plugin->short_name, GNUNET_i2s (peer));
1376 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1386 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1387 char *transport_name)
1389 struct TransportPlugin *plugin;
1391 plugin = find_transport(transport_name);
1392 if (plugin == NULL) /* Nothing to do */
1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1396 "Adding peer `%s' with plugin `%s' to blacklist\n",
1400 if (plugin->blacklist == NULL)
1401 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1402 GNUNET_assert(plugin->blacklist != NULL);
1403 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1405 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1410 * Read the blacklist file, containing transport:peer entries.
1411 * Provided the transport is loaded, set up hashmap with these
1412 * entries to blacklist peers by transport.
1416 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1423 struct GNUNET_PeerIdentity pid;
1425 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1426 unsigned int entries_found;
1427 char *transport_name;
1430 GNUNET_CONFIGURATION_get_value_filename (cfg,
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437 "Option `%s' in section `%s' not specified!\n",
1443 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1444 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1445 | GNUNET_DISK_PERM_USER_WRITE);
1446 if (0 != STAT (fn, &frstat))
1448 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1449 _("Could not read blacklist file `%s'\n"), fn);
1453 if (frstat.st_size == 0)
1456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1457 _("Blacklist file `%s' is empty.\n"),
1463 /* FIXME: use mmap */
1464 data = GNUNET_malloc_large (frstat.st_size);
1465 GNUNET_assert(data != NULL);
1466 if (frstat.st_size !=
1467 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1470 _("Failed to read blacklist from `%s'\n"), fn);
1477 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1479 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1480 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1483 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1486 if (colon_pos >= frstat.st_size)
1488 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1489 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1490 (unsigned long long) colon_pos);
1496 if (isspace( (unsigned char) data[colon_pos]))
1498 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1499 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1500 (unsigned long long) colon_pos);
1502 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1506 tsize = colon_pos - pos;
1507 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1509 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1510 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1511 (unsigned long long) colon_pos);
1520 transport_name = GNUNET_malloc(tsize + 1);
1521 memcpy(transport_name, &data[pos], tsize);
1522 pos = colon_pos + 1;
1524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525 "Read transport name %s in blacklist file.\n",
1528 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1529 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1531 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1532 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1533 (unsigned long long) pos);
1535 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1537 GNUNET_free_non_null(transport_name);
1540 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1541 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1543 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1544 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1545 (unsigned long long) pos,
1550 if (0 != memcmp (&pid,
1552 sizeof (struct GNUNET_PeerIdentity)))
1555 add_peer_to_blacklist (&pid,
1560 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1561 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1565 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1566 GNUNET_free_non_null(transport_name);
1567 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1570 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1577 * Function called to notify a client about the socket being ready to
1578 * queue more data. "buf" will be NULL and "size" zero if the socket
1579 * was closed for writing in the meantime.
1581 * @param cls closure
1582 * @param size number of bytes available in buf
1583 * @param buf where the callee should write the message
1584 * @return number of bytes written to buf
1587 transmit_to_client_callback (void *cls, size_t size, void *buf)
1589 struct TransportClient *client = cls;
1590 struct ClientMessageQueueEntry *q;
1593 const struct GNUNET_MessageHeader *msg;
1600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601 "Transmission to client failed, closing connection.\n");
1603 /* fatal error with client, free message queue! */
1604 while (NULL != (q = client->message_queue_head))
1606 GNUNET_STATISTICS_update (stats,
1607 gettext_noop ("# bytes discarded (could not transmit to client)"),
1608 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1610 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1611 client->message_queue_tail,
1615 client->message_count = 0;
1620 while (NULL != (q = client->message_queue_head))
1622 msg = (const struct GNUNET_MessageHeader *) &q[1];
1623 msize = ntohs (msg->size);
1624 if (msize + tsize > size)
1627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1628 "Transmitting message of type %u to client.\n",
1631 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1632 client->message_queue_tail,
1634 memcpy (&cbuf[tsize], msg, msize);
1637 client->message_count--;
1641 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1642 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1644 GNUNET_TIME_UNIT_FOREVER_REL,
1645 &transmit_to_client_callback,
1647 GNUNET_assert (client->th != NULL);
1654 * Convert an address to a string.
1656 * @param plugin name of the plugin responsible for the address
1657 * @param addr binary address
1658 * @param addr_len number of bytes in addr
1659 * @return NULL on error, otherwise address string
1662 a2s (const char *plugin,
1666 struct TransportPlugin *p;
1670 p = find_transport (plugin);
1673 return p->api->address_to_string (p->api->cls,
1680 * Mark the given FAL entry as 'connected' (and hence preferred for
1681 * sending); also mark all others for the same peer as 'not connected'
1682 * (since only one can be preferred).
1684 * @param fal address to set to 'connected'
1687 mark_address_connected (struct ForeignAddressList *fal)
1689 struct ForeignAddressList *pos;
1692 GNUNET_assert (GNUNET_YES == fal->validated);
1693 if (fal->connected == GNUNET_YES)
1694 return; /* nothing to do */
1696 pos = fal->ready_list->addresses;
1699 if (GNUNET_YES == pos->connected)
1702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1703 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1704 a2s (pos->ready_list->plugin->short_name,
1708 GNUNET_break (cnt == GNUNET_YES);
1710 pos->connected = GNUNET_NO;
1711 GNUNET_STATISTICS_update (stats,
1712 gettext_noop ("# connected addresses"),
1718 fal->connected = GNUNET_YES;
1719 if (GNUNET_YES == cnt)
1721 GNUNET_STATISTICS_update (stats,
1722 gettext_noop ("# connected addresses"),
1730 * Send the specified message to the specified client. Since multiple
1731 * messages may be pending for the same client at a time, this code
1732 * makes sure that no message is lost.
1734 * @param client client to transmit the message to
1735 * @param msg the message to send
1736 * @param may_drop can this message be dropped if the
1737 * message queue for this client is getting far too large?
1740 transmit_to_client (struct TransportClient *client,
1741 const struct GNUNET_MessageHeader *msg, int may_drop)
1743 struct ClientMessageQueueEntry *q;
1746 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1748 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1750 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1753 client->message_count,
1755 GNUNET_STATISTICS_update (stats,
1756 gettext_noop ("# messages dropped due to slow client"),
1761 msize = ntohs (msg->size);
1762 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1763 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1764 memcpy (&q[1], msg, msize);
1765 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1766 client->message_queue_tail,
1767 client->message_queue_tail,
1769 client->message_count++;
1770 if (client->th == NULL)
1772 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1774 GNUNET_TIME_UNIT_FOREVER_REL,
1775 &transmit_to_client_callback,
1777 GNUNET_assert (client->th != NULL);
1783 * Transmit a 'SEND_OK' notification to the given client for the
1786 * @param client who to notify
1787 * @param n neighbour to notify about, can be NULL (on failure)
1788 * @param target target of the transmission
1789 * @param result status code for the transmission request
1792 transmit_send_ok (struct TransportClient *client,
1793 struct NeighbourList *n,
1794 const struct GNUNET_PeerIdentity *target,
1797 struct SendOkMessage send_ok_msg;
1799 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1800 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1801 send_ok_msg.success = htonl (result);
1803 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1805 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1806 send_ok_msg.peer = *target;
1807 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1812 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1813 * upon "completion" of a send request. This tells the API
1814 * that it is now legal to send another message to the given
1817 * @param cls closure, identifies the entry on the
1818 * message queue that was transmitted and the
1819 * client responsible for queuing the message
1820 * @param target the peer receiving the message
1821 * @param result GNUNET_OK on success, if the transmission
1822 * failed, we should not tell the client to transmit
1826 transmit_send_continuation (void *cls,
1827 const struct GNUNET_PeerIdentity *target,
1830 struct MessageQueue *mq = cls;
1831 struct NeighbourList *n;
1833 GNUNET_STATISTICS_update (stats,
1834 gettext_noop ("# bytes pending with plugins"),
1835 - (int64_t) mq->message_buf_size,
1837 if (result == GNUNET_OK)
1839 GNUNET_STATISTICS_update (stats,
1840 gettext_noop ("# bytes successfully transmitted by plugins"),
1841 mq->message_buf_size,
1846 GNUNET_STATISTICS_update (stats,
1847 gettext_noop ("# bytes with transmission failure by plugins"),
1848 mq->message_buf_size,
1851 if (mq->specific_address != NULL)
1853 if (result == GNUNET_OK)
1855 mq->specific_address->timeout =
1856 GNUNET_TIME_relative_to_absolute
1857 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1858 if (mq->specific_address->validated == GNUNET_YES)
1859 mark_address_connected (mq->specific_address);
1863 if (mq->specific_address->connected != GNUNET_NO)
1866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1867 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1868 a2s (mq->specific_address->ready_list->plugin->short_name,
1869 mq->specific_address->addr,
1870 mq->specific_address->addrlen));
1872 GNUNET_STATISTICS_update (stats,
1873 gettext_noop ("# connected addresses"),
1876 mq->specific_address->connected = GNUNET_NO;
1879 if (! mq->internal_msg)
1880 mq->specific_address->in_transmit = GNUNET_NO;
1882 n = find_neighbour(&mq->neighbour_id);
1883 if (mq->client != NULL)
1884 transmit_send_ok (mq->client, n, target, result);
1887 try_transmission_to_peer (n);
1892 * Find an address in any of the available transports for
1893 * the given neighbour that would be good for message
1894 * transmission. This is essentially the transport selection
1897 * @param neighbour for whom to select an address
1898 * @return selected address, NULL if we have none
1900 struct ForeignAddressList *
1901 find_ready_address(struct NeighbourList *neighbour)
1903 struct ReadyList *head = neighbour->plugins;
1904 struct ForeignAddressList *addresses;
1905 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1906 struct ForeignAddressList *best_address;
1908 /* Hack to prefer unix domain sockets */
1909 struct ForeignAddressList *unix_address = NULL;
1911 best_address = NULL;
1912 while (head != NULL)
1914 addresses = head->addresses;
1915 while (addresses != NULL)
1917 if ( (addresses->timeout.abs_value < now.abs_value) &&
1918 (addresses->connected == GNUNET_YES) )
1921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1922 "Marking long-time inactive connection to `%4s' as down.\n",
1923 GNUNET_i2s (&neighbour->id));
1925 GNUNET_STATISTICS_update (stats,
1926 gettext_noop ("# connected addresses"),
1929 addresses->connected = GNUNET_NO;
1931 addresses = addresses->next;
1934 addresses = head->addresses;
1935 while (addresses != NULL)
1937 #if DEBUG_TRANSPORT > 1
1938 if (addresses->addr != NULL)
1939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1940 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1941 a2s (head->plugin->short_name,
1943 addresses->addrlen),
1944 GNUNET_i2s (&neighbour->id),
1945 addresses->connected,
1946 addresses->in_transmit,
1947 addresses->validated,
1948 addresses->connect_attempts,
1949 (unsigned long long) addresses->timeout.abs_value,
1950 (unsigned int) addresses->distance);
1952 if (0==strcmp(head->plugin->short_name,"unix"))
1954 if ((unix_address == NULL) || ((unix_address != NULL) &&
1955 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1956 unix_address = addresses;
1958 if ( ( (best_address == NULL) ||
1959 (addresses->connected == GNUNET_YES) ||
1960 (best_address->connected == GNUNET_NO) ) &&
1961 (addresses->in_transmit == GNUNET_NO) &&
1962 ( (best_address == NULL) ||
1963 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1964 best_address = addresses;
1965 /* FIXME: also give lower-latency addresses that are not
1966 connected a chance some times... */
1967 addresses = addresses->next;
1969 if (unix_address != NULL)
1973 if (unix_address != NULL)
1975 best_address = unix_address;
1977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1980 if (best_address != NULL)
1984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1985 "Best address found (`%s') has latency of %llu ms.\n",
1986 (best_address->addrlen > 0)
1987 ? a2s (best_address->ready_list->plugin->short_name,
1989 best_address->addrlen)
1991 best_address->latency.rel_value);
1996 GNUNET_STATISTICS_update (stats,
1997 gettext_noop ("# transmission attempts failed (no address)"),
2002 return best_address;
2008 * We should re-try transmitting to the given peer,
2009 * hopefully we've learned something in the meantime.
2012 retry_transmission_task (void *cls,
2013 const struct GNUNET_SCHEDULER_TaskContext *tc)
2015 struct NeighbourList *n = cls;
2017 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2018 try_transmission_to_peer (n);
2023 * Check the ready list for the given neighbour and if a plugin is
2024 * ready for transmission (and if we have a message), do so!
2026 * @param neighbour target peer for which to transmit
2029 try_transmission_to_peer (struct NeighbourList *n)
2031 struct ReadyList *rl;
2032 struct MessageQueue *mq;
2033 struct GNUNET_TIME_Relative timeout;
2037 if (n->messages_head == NULL)
2040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2041 "Transmission queue for `%4s' is empty\n",
2042 GNUNET_i2s (&n->id));
2044 return; /* nothing to do */
2047 mq = n->messages_head;
2048 force_address = GNUNET_YES;
2049 if (mq->specific_address == NULL)
2052 mq->specific_address = ats_get_preferred_address(n);
2053 GNUNET_STATISTICS_update (stats,
2054 gettext_noop ("# transport selected peer address freely"),
2057 force_address = GNUNET_NO;
2059 if (mq->specific_address == NULL)
2061 GNUNET_STATISTICS_update (stats,
2062 gettext_noop ("# transport failed to selected peer address"),
2065 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
2066 if (timeout.rel_value == 0)
2069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2070 "No destination address available to transmit message of size %u to peer `%4s'\n",
2071 mq->message_buf_size,
2072 GNUNET_i2s (&mq->neighbour_id));
2074 GNUNET_STATISTICS_update (stats,
2075 gettext_noop ("# bytes in message queue for other peers"),
2076 - (int64_t) mq->message_buf_size,
2078 GNUNET_STATISTICS_update (stats,
2079 gettext_noop ("# bytes discarded (no destination address available)"),
2080 mq->message_buf_size,
2082 if (mq->client != NULL)
2083 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
2084 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2088 return; /* nobody ready */
2090 GNUNET_STATISTICS_update (stats,
2091 gettext_noop ("# message delivery deferred (no address)"),
2094 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2095 GNUNET_SCHEDULER_cancel (n->retry_task);
2096 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
2097 &retry_transmission_task,
2100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2101 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
2102 mq->message_buf_size,
2103 GNUNET_i2s (&mq->neighbour_id),
2106 /* FIXME: might want to trigger peerinfo lookup here
2107 (unless that's already pending...) */
2110 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2113 if (mq->specific_address->connected == GNUNET_NO)
2114 mq->specific_address->connect_attempts++;
2115 rl = mq->specific_address->ready_list;
2116 mq->plugin = rl->plugin;
2117 if (!mq->internal_msg)
2118 mq->specific_address->in_transmit = GNUNET_YES;
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
2122 mq->message_buf_size,
2123 GNUNET_i2s (&n->id),
2124 (mq->specific_address->addr != NULL)
2125 ? a2s (mq->plugin->short_name,
2126 mq->specific_address->addr,
2127 mq->specific_address->addrlen)
2129 rl->plugin->short_name);
2131 GNUNET_STATISTICS_update (stats,
2132 gettext_noop ("# bytes in message queue for other peers"),
2133 - (int64_t) mq->message_buf_size,
2135 GNUNET_STATISTICS_update (stats,
2136 gettext_noop ("# bytes pending with plugins"),
2137 mq->message_buf_size,
2139 ret = rl->plugin->api->send (rl->plugin->api->cls,
2142 mq->message_buf_size,
2144 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2145 mq->specific_address->session,
2146 mq->specific_address->addr,
2147 mq->specific_address->addrlen,
2149 &transmit_send_continuation, mq);
2152 /* failure, but 'send' would not call continuation in this case,
2153 so we need to do it here! */
2154 transmit_send_continuation (mq,
2162 * Send the specified message to the specified peer.
2164 * @param client source of the transmission request (can be NULL)
2165 * @param peer_address ForeignAddressList where we should send this message
2166 * @param priority how important is the message
2167 * @param timeout how long do we have to transmit?
2168 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
2169 * @param message_buf_size total size of all messages in message_buf
2170 * @param is_internal is this an internal message; these are pre-pended and
2171 * also do not count for plugins being "ready" to transmit
2172 * @param neighbour handle to the neighbour for transmission
2175 transmit_to_peer (struct TransportClient *client,
2176 struct ForeignAddressList *peer_address,
2177 unsigned int priority,
2178 struct GNUNET_TIME_Relative timeout,
2179 const char *message_buf,
2180 size_t message_buf_size,
2181 int is_internal, struct NeighbourList *neighbour)
2183 struct MessageQueue *mq;
2188 /* check for duplicate submission */
2189 mq = neighbour->messages_head;
2192 if (mq->client == client)
2194 /* client transmitted to same peer twice
2195 before getting SEND_OK! */
2203 GNUNET_STATISTICS_update (stats,
2204 gettext_noop ("# bytes in message queue for other peers"),
2207 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2208 mq->specific_address = peer_address;
2209 mq->client = client;
2210 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2211 memcpy (&mq[1], message_buf, message_buf_size);
2212 mq->message_buf = (const char*) &mq[1];
2213 mq->message_buf_size = message_buf_size;
2214 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2215 mq->internal_msg = is_internal;
2216 mq->priority = priority;
2217 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2219 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2220 neighbour->messages_tail,
2223 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2224 neighbour->messages_tail,
2225 neighbour->messages_tail,
2227 try_transmission_to_peer (neighbour);
2234 struct GeneratorContext
2236 struct TransportPlugin *plug_pos;
2237 struct OwnAddressList *addr_pos;
2238 struct GNUNET_TIME_Absolute expiration;
2246 address_generator (void *cls, size_t max, void *buf)
2248 struct GeneratorContext *gc = cls;
2251 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2253 gc->plug_pos = gc->plug_pos->next;
2254 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2256 if (NULL == gc->plug_pos)
2261 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2264 gc->addr_pos->addrlen, buf, max);
2265 gc->addr_pos = gc->addr_pos->next;
2271 * Construct our HELLO message from all of the addresses of
2272 * all of the transports.
2277 struct GNUNET_HELLO_Message *hello;
2278 struct TransportClient *cpos;
2279 struct NeighbourList *npos;
2280 struct GeneratorContext gc;
2282 gc.plug_pos = plugins;
2283 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2284 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2285 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2288 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2290 GNUNET_STATISTICS_update (stats,
2291 gettext_noop ("# refreshed my HELLO"),
2295 while (cpos != NULL)
2297 transmit_to_client (cpos,
2298 (const struct GNUNET_MessageHeader *) hello,
2303 GNUNET_free_non_null (our_hello);
2305 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2307 while (npos != NULL)
2310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2311 "Transmitting updated `%s' to neighbour `%4s'\n",
2312 "HELLO", GNUNET_i2s (&npos->id));
2314 GNUNET_STATISTICS_update (stats,
2315 gettext_noop ("# transmitted my HELLO to other peers"),
2318 transmit_to_peer (NULL, NULL, 0,
2319 HELLO_ADDRESS_EXPIRATION,
2320 (const char *) our_hello,
2321 GNUNET_HELLO_size(our_hello),
2329 * Task used to clean up expired addresses for a plugin.
2331 * @param cls closure
2335 expire_address_task (void *cls,
2336 const struct GNUNET_SCHEDULER_TaskContext *tc);
2340 * Update the list of addresses for this plugin,
2341 * expiring those that are past their expiration date.
2343 * @param plugin addresses of which plugin should be recomputed?
2344 * @param fresh set to GNUNET_YES if a new address was added
2345 * and we need to regenerate the HELLO even if nobody
2349 update_addresses (struct TransportPlugin *plugin,
2352 static struct GNUNET_TIME_Absolute last_update;
2353 struct GNUNET_TIME_Relative min_remaining;
2354 struct GNUNET_TIME_Relative remaining;
2355 struct GNUNET_TIME_Absolute now;
2356 struct OwnAddressList *pos;
2357 struct OwnAddressList *prev;
2358 struct OwnAddressList *next;
2361 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2362 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2363 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2364 now = GNUNET_TIME_absolute_get ();
2365 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2366 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2368 pos = plugin->addresses;
2372 if (pos->expires.abs_value < now.abs_value)
2374 expired = GNUNET_YES;
2376 plugin->addresses = pos->next;
2378 prev->next = pos->next;
2383 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2384 if (remaining.rel_value < min_remaining.rel_value)
2385 min_remaining = remaining;
2391 if (expired || fresh)
2396 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2397 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2399 plugin->address_update_task
2400 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2401 &expire_address_task, plugin);
2406 * Task used to clean up expired addresses for a plugin.
2408 * @param cls closure
2412 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2414 struct TransportPlugin *plugin = cls;
2416 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2417 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2418 update_addresses (plugin, GNUNET_NO);
2423 * Iterator over hash map entries that NULLs the session of validation
2424 * entries that match the given session.
2426 * @param cls closure (the 'struct Session*' to match against)
2427 * @param key current key code (peer ID, not used)
2428 * @param value value in the hash map ('struct ValidationEntry*')
2429 * @return GNUNET_YES (we should continue to iterate)
2432 remove_session_validations (void *cls,
2433 const GNUNET_HashCode * key,
2436 struct Session *session = cls;
2437 struct ValidationEntry *ve = value;
2439 if (session == ve->session)
2446 * We've been disconnected from the other peer (for some
2447 * connection-oriented transport). Either quickly
2448 * re-establish the connection or signal the disconnect
2451 * Only signal CORE level disconnect if ALL addresses
2452 * for the peer are exhausted.
2454 * @param p overall plugin context
2455 * @param nl neighbour that was disconnected
2458 try_fast_reconnect (struct TransportPlugin *p,
2459 struct NeighbourList *nl)
2461 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2462 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2463 "try_fast_reconnect not implemented!\n");
2464 /* Note: the idea here is to hide problems with transports (or
2465 switching between plugins) from the core to eliminate the need to
2466 re-negotiate session keys and the like; OTOH, we should tell core
2467 quickly (much faster than timeout) `if a connection was lost and
2468 could not be re-established (i.e. other peer went down or is
2469 unable / refuses to communicate);
2471 So we should consider:
2472 1) ideally: our own willingness / need to connect
2473 2) prior failures to connect to this peer (by plugin)
2474 3) ideally: reasons why other peer terminated (as far as knowable)
2476 Most importantly, it must be POSSIBLE for another peer to terminate
2477 a connection for a while (without us instantly re-establishing it).
2478 Similarly, if another peer is gone we should quickly notify CORE.
2479 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2480 on the other end), we should reconnect in such a way that BOTH CORE
2481 services never even notice.
2482 Furthermore, the same mechanism (or small variation) could be used
2483 to switch to a better-performing plugin (ATS).
2485 Finally, this needs to be tested throughly... */
2488 * GNUNET_NO in the call below makes transport disconnect the peer,
2489 * even if only a single address (out of say, six) went away. This
2490 * function must be careful to ONLY disconnect if the peer is gone,
2491 * not just a specifi address.
2493 * More specifically, half the places it was used had it WRONG.
2496 /* No reconnect, signal disconnect instead! */
2498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2499 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2500 "try_fast_reconnect");
2502 disconnect_neighbour (nl, GNUNET_YES);
2507 * Function that will be called whenever the plugin internally
2508 * cleans up a session pointer and hence the service needs to
2509 * discard all of those sessions as well. Plugins that do not
2510 * use sessions can simply omit calling this function and always
2511 * use NULL wherever a session pointer is needed.
2513 * @param cls closure
2514 * @param peer which peer was the session for
2515 * @param session which session is being destoyed
2518 plugin_env_session_end (void *cls,
2519 const struct GNUNET_PeerIdentity *peer,
2520 struct Session *session)
2522 struct TransportPlugin *p = cls;
2523 struct NeighbourList *nl;
2524 struct ReadyList *rl;
2525 struct ForeignAddressList *pos;
2526 struct ForeignAddressList *prev;
2529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2530 "Session ended with peer `%4s', %s\n",
2532 "plugin_env_session_end");
2534 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2535 &remove_session_validations,
2537 nl = find_neighbour (peer);
2541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2542 "No neighbour record found for peer `%4s'\n",
2545 return; /* was never marked as connected */
2550 if (rl->plugin == p)
2557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2558 "Plugin was associated with peer `%4s'\n",
2561 disconnect_neighbour (nl, GNUNET_YES);
2565 pos = rl->addresses;
2566 while ( (pos != NULL) &&
2567 (pos->session != session) )
2575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2576 "Session was never marked as ready for peer `%4s'\n",
2579 disconnect_neighbour (nl, GNUNET_YES);
2580 return; /* was never marked as connected */
2582 pos->session = NULL;
2583 if (pos->addrlen != 0)
2585 if (nl->received_pong != GNUNET_NO)
2586 try_fast_reconnect (p, nl);
2588 disconnect_neighbour (nl, GNUNET_YES);
2591 /* was inbound connection, free 'pos' */
2593 rl->addresses = pos->next;
2595 prev->next = pos->next;
2596 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2598 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2599 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2601 GNUNET_free_non_null(pos->ressources);
2602 GNUNET_free_non_null(pos->quality);
2604 ats->stat.recreate_problem = GNUNET_YES;
2605 if (nl->received_pong == GNUNET_NO)
2607 disconnect_neighbour (nl, GNUNET_YES);
2608 return; /* nothing to do, never connected... */
2610 /* check if we have any validated addresses left */
2611 pos = rl->addresses;
2616 try_fast_reconnect (p, nl);
2621 /* no valid addresses left, signal disconnect! */
2624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2625 "Disconnecting peer `%4s', %s\n",
2627 "plugin_env_session_end");
2629 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2630 * it means there aren't any left for this PLUGIN/PEER combination! So
2631 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2632 * when it isn't necessary. Using GNUNET_YES at least checks to see
2633 * if there are any addresses that work first, so as not to overdo it.
2636 disconnect_neighbour (nl, GNUNET_YES);
2641 * Function that must be called by each plugin to notify the
2642 * transport service about the addresses under which the transport
2643 * provided by the plugin can be reached.
2645 * @param cls closure
2646 * @param name name of the transport that generated the address
2647 * @param addr one of the addresses of the host, NULL for the last address
2648 * the specific address format depends on the transport
2649 * @param addrlen length of the address
2650 * @param expires when should this address automatically expire?
2653 plugin_env_notify_address (void *cls,
2657 struct GNUNET_TIME_Relative expires)
2659 struct TransportPlugin *p = cls;
2660 struct OwnAddressList *al;
2661 struct GNUNET_TIME_Absolute abex;
2663 GNUNET_assert (addr != NULL);
2664 abex = GNUNET_TIME_relative_to_absolute (expires);
2665 GNUNET_assert (p == find_transport (name));
2669 if ( (addrlen == al->addrlen) &&
2670 (0 == memcmp (addr, &al[1], addrlen)) )
2673 update_addresses (p, GNUNET_NO);
2678 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2679 al->next = p->addresses;
2682 al->addrlen = addrlen;
2683 memcpy (&al[1], addr, addrlen);
2684 update_addresses (p, GNUNET_YES);
2689 * Notify all of our clients about a peer connecting.
2692 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2693 struct GNUNET_TIME_Relative latency,
2696 struct ConnectInfoMessage * cim;
2697 struct TransportClient *cpos;
2702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2703 "Notifying clients about connection from `%s'\n",
2706 GNUNET_STATISTICS_update (stats,
2707 gettext_noop ("# peers connected"),
2712 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2713 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2717 cim = GNUNET_malloc (size);
2719 cim->header.size = htons (size);
2720 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2721 cim->ats_count = htonl(2);
2722 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2723 (&(cim->ats))[0].value = htonl (distance);
2724 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2725 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2726 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2727 (&(cim->ats))[2].value = htonl (0);
2728 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2730 /* notify ats about connecting peer */
2731 ats_notify_peer_connect (peer, &(cim->ats), 2);
2734 while (cpos != NULL)
2736 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2745 * Notify all of our clients about a peer disconnecting.
2748 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2750 struct DisconnectInfoMessage dim;
2751 struct TransportClient *cpos;
2754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2755 "Notifying clients about lost connection to `%s'\n",
2758 GNUNET_STATISTICS_update (stats,
2759 gettext_noop ("# peers connected"),
2762 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2763 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2764 dim.reserved = htonl (0);
2765 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2767 /* notify ats about connecting peer */
2768 ats_notify_peer_disconnect (peer);
2771 while (cpos != NULL)
2773 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2780 * Find a ForeignAddressList entry for the given neighbour
2781 * that matches the given address and transport.
2783 * @param neighbour which peer we care about
2784 * @param tname name of the transport plugin
2785 * @param session session to look for, NULL for 'any'; otherwise
2786 * can be used for the service to "learn" this session ID
2788 * @param addr binary address
2789 * @param addrlen length of addr
2790 * @return NULL if no such entry exists
2792 static struct ForeignAddressList *
2793 find_peer_address(struct NeighbourList *neighbour,
2795 struct Session *session,
2799 struct ReadyList *head;
2800 struct ForeignAddressList *pos;
2802 head = neighbour->plugins;
2803 while (head != NULL)
2805 if (0 == strcmp (tname, head->plugin->short_name))
2811 pos = head->addresses;
2812 while ( (pos != NULL) &&
2813 ( (pos->addrlen != addrlen) ||
2814 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2816 if ( (session != NULL) &&
2817 (pos->session == session) )
2821 if ( (session != NULL) && (pos != NULL) )
2822 pos->session = session; /* learn it! */
2828 * Get the peer address struct for the given neighbour and
2829 * address. If it doesn't yet exist, create it.
2831 * @param neighbour which peer we care about
2832 * @param tname name of the transport plugin
2833 * @param session session of the plugin, or NULL for none
2834 * @param addr binary address
2835 * @param addrlen length of addr
2836 * @return NULL if we do not have a transport plugin for 'tname'
2838 static struct ForeignAddressList *
2839 add_peer_address (struct NeighbourList *neighbour,
2841 struct Session *session,
2845 struct ReadyList *head;
2846 struct ForeignAddressList *ret;
2849 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2852 head = neighbour->plugins;
2854 while (head != NULL)
2856 if (0 == strcmp (tname, head->plugin->short_name))
2862 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2863 ret->session = session;
2864 if ((addrlen > 0) && (addr != NULL))
2866 ret->addr = (const char*) &ret[1];
2867 memcpy (&ret[1], addr, addrlen);
2874 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2875 for (c=0; c<available_ressources; c++)
2877 struct ATS_ressource_entry *r = ret->ressources;
2879 r[c].atis_index = ressources[c].atis_index;
2880 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2882 r[c].c = ressources[c].c_unix;
2884 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2886 r[c].c = ressources[c].c_udp;
2888 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2890 r[c].c = ressources[c].c_tcp;
2892 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2894 r[c].c = ressources[c].c_http;
2896 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2898 r[c].c = ressources[c].c_https;
2900 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2902 r[c].c = ressources[c].c_wlan;
2906 r[c].c = ressources[c].c_default;
2907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2908 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2909 GNUNET_i2s(&neighbour->peer),
2910 neighbour->plugins->plugin->short_name);
2914 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2915 ret->addrlen = addrlen;
2916 ret->expires = GNUNET_TIME_relative_to_absolute
2917 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2918 ret->latency = GNUNET_TIME_relative_get_forever();
2920 ret->timeout = GNUNET_TIME_relative_to_absolute
2921 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2922 ret->ready_list = head;
2923 ret->next = head->addresses;
2924 head->addresses = ret;
2930 * Closure for 'add_validated_address'.
2932 struct AddValidatedAddressContext
2935 * Entry that has been validated.
2937 const struct ValidationEntry *ve;
2940 * Flag set after we have added the address so
2941 * that we terminate the iteration next time.
2948 * Callback function used to fill a buffer of max bytes with a list of
2949 * addresses in the format used by HELLOs. Should use
2950 * "GNUNET_HELLO_add_address" as a helper function.
2952 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2953 * @param max maximum number of bytes that can be written to buf
2954 * @param buf where to write the address information
2955 * @return number of bytes written, 0 to signal the
2956 * end of the iteration.
2959 add_validated_address (void *cls,
2960 size_t max, void *buf)
2962 struct AddValidatedAddressContext *avac = cls;
2963 const struct ValidationEntry *ve = avac->ve;
2965 if (GNUNET_YES == avac->done)
2967 avac->done = GNUNET_YES;
2968 return GNUNET_HELLO_add_address (ve->transport_name,
2969 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2979 * Closure for 'check_address_exists'.
2981 struct CheckAddressExistsClosure
2984 * Address to check for.
2989 * Name of the transport.
2996 struct Session *session;
2999 * Set to GNUNET_YES if the address exists.
3012 * Iterator over hash map entries. Checks if the given
3013 * validation entry is for the same address as what is given
3016 * @param cls the 'struct CheckAddressExistsClosure*'
3017 * @param key current key code (ignored)
3018 * @param value value in the hash map ('struct ValidationEntry')
3019 * @return GNUNET_YES if we should continue to
3020 * iterate (mismatch), GNUNET_NO if not (entry matched)
3023 check_address_exists (void *cls,
3024 const GNUNET_HashCode * key,
3027 struct CheckAddressExistsClosure *caec = cls;
3028 struct ValidationEntry *ve = value;
3030 if ( (0 == strcmp (caec->tname,
3031 ve->transport_name)) &&
3032 (caec->addrlen == ve->addrlen) &&
3033 (0 == memcmp (caec->addr,
3037 caec->exists = GNUNET_YES;
3040 if ( (ve->session != NULL) &&
3041 (caec->session == ve->session) )
3043 caec->exists = GNUNET_YES;
3052 * Iterator to free entries in the validation_map.
3054 * @param cls closure (unused)
3055 * @param key current key code
3056 * @param value value in the hash map (validation to abort)
3057 * @return GNUNET_YES (always)
3060 abort_validation (void *cls,
3061 const GNUNET_HashCode * key,
3064 struct ValidationEntry *va = value;
3066 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
3067 GNUNET_SCHEDULER_cancel (va->timeout_task);
3068 GNUNET_free (va->transport_name);
3069 if (va->chvc != NULL)
3071 va->chvc->ve_count--;
3072 if (va->chvc->ve_count == 0)
3074 GNUNET_CONTAINER_DLL_remove (chvc_head,
3077 GNUNET_free (va->chvc);
3087 * HELLO validation cleanup task (validation failed).
3089 * @param cls the 'struct ValidationEntry' that failed
3090 * @param tc scheduler context (unused)
3093 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3095 struct ValidationEntry *va = cls;
3096 struct GNUNET_PeerIdentity pid;
3098 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3099 GNUNET_STATISTICS_update (stats,
3100 gettext_noop ("# address validation timeouts"),
3103 GNUNET_CRYPTO_hash (&va->publicKey,
3105 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3107 GNUNET_break (GNUNET_OK ==
3108 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3111 abort_validation (NULL, NULL, va);
3116 neighbour_timeout_task (void *cls,
3117 const struct GNUNET_SCHEDULER_TaskContext *tc)
3119 struct NeighbourList *n = cls;
3122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3123 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3125 GNUNET_STATISTICS_update (stats,
3126 gettext_noop ("# disconnects due to timeout"),
3129 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3130 disconnect_neighbour (n, GNUNET_NO);
3135 * Schedule the job that will cause us to send a PING to the
3136 * foreign address to evaluate its validity and latency.
3138 * @param fal address to PING
3141 schedule_next_ping (struct ForeignAddressList *fal);
3145 * Add the given address to the list of foreign addresses
3146 * available for the given peer (check for duplicates).
3148 * @param cls the respective 'struct NeighbourList' to update
3149 * @param tname name of the transport
3150 * @param expiration expiration time
3151 * @param addr the address
3152 * @param addrlen length of the address
3153 * @return GNUNET_OK (always)
3156 add_to_foreign_address_list (void *cls,
3158 struct GNUNET_TIME_Absolute expiration,
3162 struct NeighbourList *n = cls;
3163 struct ForeignAddressList *fal;
3166 GNUNET_STATISTICS_update (stats,
3167 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3171 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3174 #if DEBUG_TRANSPORT_HELLO
3175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3176 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3177 a2s (tname, addr, addrlen),
3179 GNUNET_i2s (&n->id),
3180 expiration.abs_value);
3182 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3185 GNUNET_STATISTICS_update (stats,
3186 gettext_noop ("# previously validated addresses lacking transport"),
3192 fal->expires = GNUNET_TIME_absolute_max (expiration,
3194 schedule_next_ping (fal);
3200 fal->expires = GNUNET_TIME_absolute_max (expiration,
3206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3207 "Failed to add new address for `%4s'\n",
3208 GNUNET_i2s (&n->id));
3212 if (fal->validated == GNUNET_NO)
3214 fal->validated = GNUNET_YES;
3215 GNUNET_STATISTICS_update (stats,
3216 gettext_noop ("# peer addresses considered valid"),
3220 if (try == GNUNET_YES)
3223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3224 "Have new addresses, will try to trigger transmissions.\n");
3226 try_transmission_to_peer (n);
3233 * Add addresses in validated HELLO "h" to the set of addresses
3234 * we have for this peer.
3236 * @param cls closure ('struct NeighbourList*')
3237 * @param peer id of the peer, NULL for last call
3238 * @param h hello message for the peer (can be NULL)
3239 * @param err_msg NULL if successful, otherwise contains error message
3242 add_hello_for_peer (void *cls,
3243 const struct GNUNET_PeerIdentity *peer,
3244 const struct GNUNET_HELLO_Message *h,
3245 const char *err_msg)
3247 struct NeighbourList *n = cls;
3249 if (err_msg != NULL)
3252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3253 _("Error in communication with PEERINFO service: %s\n"),
3260 GNUNET_STATISTICS_update (stats,
3261 gettext_noop ("# outstanding peerinfo iterate requests"),
3268 return; /* no HELLO available */
3270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3271 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3275 if (GNUNET_YES != n->public_key_valid)
3277 GNUNET_HELLO_get_key (h, &n->publicKey);
3278 n->public_key_valid = GNUNET_YES;
3280 GNUNET_HELLO_iterate_addresses (h,
3282 &add_to_foreign_address_list,
3288 * Create a fresh entry in our neighbour list for the given peer.
3289 * Will try to transmit our current HELLO to the new neighbour.
3290 * Do not call this function directly, use 'setup_peer_check_blacklist.
3292 * @param peer the peer for which we create the entry
3293 * @param do_hello should we schedule transmitting a HELLO
3294 * @return the new neighbour list entry
3296 static struct NeighbourList *
3297 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3300 struct NeighbourList *n;
3301 struct TransportPlugin *tp;
3302 struct ReadyList *rl;
3305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3306 "Setting up state for neighbour `%4s'\n",
3309 GNUNET_assert (our_hello != NULL);
3310 GNUNET_STATISTICS_update (stats,
3311 gettext_noop ("# active neighbours"),
3314 n = GNUNET_malloc (sizeof (struct NeighbourList));
3315 n->next = neighbours;
3319 GNUNET_TIME_relative_to_absolute
3320 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3321 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3322 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3323 MAX_BANDWIDTH_CARRY_S);
3327 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3329 rl = GNUNET_malloc (sizeof (struct ReadyList));
3331 rl->next = n->plugins;
3334 rl->addresses = NULL;
3338 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3340 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3341 &neighbour_timeout_task, n);
3344 GNUNET_STATISTICS_update (stats,
3345 gettext_noop ("# peerinfo new neighbor iterate requests"),
3348 GNUNET_STATISTICS_update (stats,
3349 gettext_noop ("# outstanding peerinfo iterate requests"),
3352 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3353 GNUNET_TIME_UNIT_FOREVER_REL,
3354 &add_hello_for_peer, n);
3356 GNUNET_STATISTICS_update (stats,
3357 gettext_noop ("# HELLO's sent to new neighbors"),
3360 transmit_to_peer (NULL, NULL, 0,
3361 HELLO_ADDRESS_EXPIRATION,
3362 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3370 * Function called after we have checked if communicating
3371 * with a given peer is acceptable.
3373 * @param cls closure
3374 * @param n NULL if communication is not acceptable
3376 typedef void (*SetupContinuation)(void *cls,
3377 struct NeighbourList *n);
3381 * Information kept for each client registered to perform
3387 * This is a linked list.
3389 struct Blacklisters *next;
3392 * This is a linked list.
3394 struct Blacklisters *prev;
3397 * Client responsible for this entry.
3399 struct GNUNET_SERVER_Client *client;
3402 * Blacklist check that we're currently performing.
3404 struct BlacklistCheck *bc;
3410 * Head of DLL of blacklisting clients.
3412 static struct Blacklisters *bl_head;
3415 * Tail of DLL of blacklisting clients.
3417 static struct Blacklisters *bl_tail;
3421 * Context we use when performing a blacklist check.
3423 struct BlacklistCheck
3427 * This is a linked list.
3429 struct BlacklistCheck *next;
3432 * This is a linked list.
3434 struct BlacklistCheck *prev;
3437 * Peer being checked.
3439 struct GNUNET_PeerIdentity peer;
3442 * Option for setup neighbour afterwards.
3447 * Continuation to call with the result.
3449 SetupContinuation cont;
3457 * Current transmission request handle for this client, or NULL if no
3458 * request is pending.
3460 struct GNUNET_CONNECTION_TransmitHandle *th;
3463 * Our current position in the blacklisters list.
3465 struct Blacklisters *bl_pos;
3468 * Current task performing the check.
3470 GNUNET_SCHEDULER_TaskIdentifier task;
3475 * Head of DLL of active blacklisting queries.
3477 static struct BlacklistCheck *bc_head;
3480 * Tail of DLL of active blacklisting queries.
3482 static struct BlacklistCheck *bc_tail;
3486 * Perform next action in the blacklist check.
3488 * @param cls the 'struct BlacklistCheck*'
3492 do_blacklist_check (void *cls,
3493 const struct GNUNET_SCHEDULER_TaskContext *tc);
3496 * Transmit blacklist query to the client.
3498 * @param cls the 'struct BlacklistCheck'
3499 * @param size number of bytes allowed
3500 * @param buf where to copy the message
3501 * @return number of bytes copied to buf
3504 transmit_blacklist_message (void *cls,
3508 struct BlacklistCheck *bc = cls;
3509 struct Blacklisters *bl;
3510 struct BlacklistMessage bm;
3515 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3516 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3518 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3519 "Failed to send blacklist test for peer `%s' to client\n",
3520 GNUNET_i2s (&bc->peer));
3524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3525 "Sending blacklist test for peer `%s' to client\n",
3526 GNUNET_i2s (&bc->peer));
3529 bm.header.size = htons (sizeof (struct BlacklistMessage));
3530 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3531 bm.is_allowed = htonl (0);
3533 memcpy (buf, &bm, sizeof (bm));
3534 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3540 * Perform next action in the blacklist check.
3542 * @param cls the 'struct BlacklistCheck*'
3546 do_blacklist_check (void *cls,
3547 const struct GNUNET_SCHEDULER_TaskContext *tc)
3549 struct BlacklistCheck *bc = cls;
3550 struct Blacklisters *bl;
3552 bc->task = GNUNET_SCHEDULER_NO_TASK;
3557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3558 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3559 GNUNET_i2s (&bc->peer));
3561 bc->cont (bc->cont_cls,
3562 setup_new_neighbour (&bc->peer, bc->do_hello));
3569 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3570 sizeof (struct BlacklistMessage),
3571 GNUNET_TIME_UNIT_FOREVER_REL,
3572 &transmit_blacklist_message,
3579 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3580 * does not yet exist, check the blacklist. If the blacklist says creating
3581 * one is acceptable, create one and call the continuation; otherwise
3582 * call the continuation with NULL.
3584 * @param peer peer to setup or look up a struct NeighbourList for
3585 * @param do_hello should we also schedule sending our HELLO to the peer
3586 * if this is a new record
3587 * @param cont function to call with the 'struct NeigbhbourList*'
3588 * @param cont_cls closure for cont
3591 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3593 SetupContinuation cont,
3596 struct NeighbourList *n;
3597 struct BlacklistCheck *bc;
3599 n = find_neighbour(peer);
3603 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3604 "Neighbour record exists for peer `%s'\n",
3611 if (bl_head == NULL)
3614 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3616 setup_new_neighbour(peer, do_hello);
3619 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3620 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3622 bc->do_hello = do_hello;
3624 bc->cont_cls = cont_cls;
3625 bc->bl_pos = bl_head;
3626 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3632 * Function called with the result of querying a new blacklister about
3633 * it being allowed (or not) to continue to talk to an existing neighbour.
3635 * @param cls the original 'struct NeighbourList'
3636 * @param n NULL if we need to disconnect
3639 confirm_or_drop_neighbour (void *cls,
3640 struct NeighbourList *n)
3642 struct NeighbourList * orig = cls;
3647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3648 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3649 "confirm_or_drop_neighboUr");
3651 disconnect_neighbour (orig, GNUNET_NO);
3657 * Handle a request to start a blacklist.
3659 * @param cls closure (always NULL)
3660 * @param client identification of the client
3661 * @param message the actual message
3664 handle_blacklist_init (void *cls,
3665 struct GNUNET_SERVER_Client *client,
3666 const struct GNUNET_MessageHeader *message)
3668 struct Blacklisters *bl;
3669 struct BlacklistCheck *bc;
3670 struct NeighbourList *n;
3675 if (bl->client == client)
3678 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3683 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3684 bl->client = client;
3685 GNUNET_SERVER_client_keep (client);
3686 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3687 /* confirm that all existing connections are OK! */
3691 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3692 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3694 bc->do_hello = GNUNET_NO;
3695 bc->cont = &confirm_or_drop_neighbour;
3698 if (n == neighbours) /* all would wait for the same client, no need to
3699 create more than just the first task right now */
3700 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3708 * Handle a request to blacklist a peer.
3710 * @param cls closure (always NULL)
3711 * @param client identification of the client
3712 * @param message the actual message
3715 handle_blacklist_reply (void *cls,
3716 struct GNUNET_SERVER_Client *client,
3717 const struct GNUNET_MessageHeader *message)
3719 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3720 struct Blacklisters *bl;
3721 struct BlacklistCheck *bc;
3724 while ( (bl != NULL) &&
3725 (bl->client != client) )
3730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3731 "Blacklist client disconnected\n");
3733 /* FIXME: other error handling here!? */
3734 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3739 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3743 "Blacklist check failed, peer not allowed\n");
3745 bc->cont (bc->cont_cls, NULL);
3746 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3753 "Blacklist check succeeded, continuing with checks\n");
3755 bc->bl_pos = bc->bl_pos->next;
3756 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3759 /* check if any other bc's are waiting for this blacklister */
3763 if ( (bc->bl_pos == bl) &&
3764 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3765 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3773 * Send periodic PING messages to a given foreign address.
3775 * @param cls our 'struct PeriodicValidationContext*'
3776 * @param tc task context
3779 send_periodic_ping (void *cls,
3780 const struct GNUNET_SCHEDULER_TaskContext *tc)
3782 struct ForeignAddressList *peer_address = cls;
3783 struct TransportPlugin *tp;
3784 struct ValidationEntry *va;
3785 struct NeighbourList *neighbour;
3786 struct TransportPingMessage ping;
3787 struct CheckAddressExistsClosure caec;
3789 uint16_t hello_size;
3793 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3794 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3796 tp = peer_address->ready_list->plugin;
3797 neighbour = peer_address->ready_list->neighbour;
3798 if (GNUNET_YES != neighbour->public_key_valid)
3800 /* no public key yet, try again later */
3801 schedule_next_ping (peer_address);
3804 caec.addr = peer_address->addr;
3805 caec.addrlen = peer_address->addrlen;
3806 caec.tname = tp->short_name;
3807 caec.session = peer_address->session;
3808 caec.exists = GNUNET_NO;
3809 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3810 &check_address_exists,
3812 if (caec.exists == GNUNET_YES)
3814 /* During validation attempts we will likely trigger the other
3815 peer trying to validate our address which in turn will cause
3816 it to send us its HELLO, so we expect to hit this case rather
3817 frequently. Only print something if we are very verbose. */
3818 #if DEBUG_TRANSPORT > 1
3819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3820 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3821 (peer_address->addr != NULL)
3822 ? a2s (tp->short_name,
3824 peer_address->addrlen)
3827 GNUNET_i2s (&neighbour->id));
3829 schedule_next_ping (peer_address);
3832 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3833 va->transport_name = GNUNET_strdup (tp->short_name);
3834 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3836 va->send_time = GNUNET_TIME_absolute_get();
3837 va->session = peer_address->session;
3838 if (peer_address->addr != NULL)
3840 va->addr = (const void*) &va[1];
3841 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3842 va->addrlen = peer_address->addrlen;
3844 memcpy(&va->publicKey,
3845 &neighbour->publicKey,
3846 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3848 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3849 &timeout_hello_validation,
3851 GNUNET_CONTAINER_multihashmap_put (validation_map,
3852 &neighbour->id.hashPubKey,
3854 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3856 if (peer_address->validated != GNUNET_YES)
3857 hello_size = GNUNET_HELLO_size(our_hello);
3861 tsize = sizeof(struct TransportPingMessage) + hello_size;
3863 if (peer_address->addr != NULL)
3865 slen = strlen (tp->short_name) + 1;
3866 tsize += slen + peer_address->addrlen;
3870 slen = 0; /* make gcc happy */
3872 message_buf = GNUNET_malloc(tsize);
3873 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3874 ping.challenge = htonl(va->challenge);
3875 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3876 if (peer_address->validated != GNUNET_YES)
3878 memcpy(message_buf, our_hello, hello_size);
3881 if (peer_address->addr != NULL)
3883 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3884 peer_address->addrlen +
3886 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3889 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3891 peer_address->addrlen);
3895 ping.header.size = htons(sizeof(struct TransportPingMessage));
3898 memcpy(&message_buf[hello_size],
3900 sizeof(struct TransportPingMessage));
3902 #if DEBUG_TRANSPORT_REVALIDATION
3903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3904 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3905 (peer_address->addr != NULL)
3906 ? a2s (peer_address->plugin->short_name,
3908 peer_address->addrlen)
3911 GNUNET_i2s (&neighbour->id),
3912 "HELLO", hello_size,
3915 if (peer_address->validated != GNUNET_YES)
3916 GNUNET_STATISTICS_update (stats,
3917 gettext_noop ("# PING with HELLO messages sent"),
3921 GNUNET_STATISTICS_update (stats,
3922 gettext_noop ("# PING without HELLO messages sent"),
3925 GNUNET_STATISTICS_update (stats,
3926 gettext_noop ("# PING messages sent for re-validation"),
3929 transmit_to_peer (NULL, peer_address,
3930 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3931 HELLO_VERIFICATION_TIMEOUT,
3933 GNUNET_YES, neighbour);
3934 GNUNET_free(message_buf);
3935 schedule_next_ping (peer_address);
3940 * Schedule the job that will cause us to send a PING to the
3941 * foreign address to evaluate its validity and latency.
3943 * @param fal address to PING
3946 schedule_next_ping (struct ForeignAddressList *fal)
3948 struct GNUNET_TIME_Relative delay;
3950 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3952 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3953 delay.rel_value /= 2; /* do before expiration */
3954 delay = GNUNET_TIME_relative_min (delay,
3955 LATENCY_EVALUATION_MAX_DELAY);
3956 if (GNUNET_YES != fal->estimated)
3958 delay = GNUNET_TIME_UNIT_ZERO;
3959 fal->estimated = GNUNET_YES;
3961 if (GNUNET_YES == fal->connected)
3963 delay = GNUNET_TIME_relative_min (delay,
3964 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3966 /* FIXME: also adjust delay based on how close the last
3967 observed latency is to the latency of the best alternative */
3968 /* bound how fast we can go */
3969 delay = GNUNET_TIME_relative_max (delay,
3970 GNUNET_TIME_UNIT_SECONDS);
3971 /* randomize a bit (to avoid doing all at the same time) */
3972 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3973 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3974 &send_periodic_ping,
3982 * Function that will be called if we receive some payload
3983 * from another peer.
3985 * @param message the payload
3986 * @param n peer who claimed to be the sender
3989 handle_payload_message (const struct GNUNET_MessageHeader *message,
3990 struct NeighbourList *n)
3992 struct InboundMessage *im;
3993 struct TransportClient *cpos;
3996 msize = ntohs (message->size);
3997 if (n->received_pong == GNUNET_NO)
4000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4001 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
4002 ntohs (message->type),
4003 ntohs (message->size),
4004 GNUNET_i2s (&n->id));
4006 GNUNET_free_non_null (n->pre_connect_message_buffer);
4007 n->pre_connect_message_buffer = GNUNET_malloc (msize);
4008 memcpy (n->pre_connect_message_buffer, message, msize);
4013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4014 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4015 ntohs (message->type),
4016 ntohs (message->size),
4017 GNUNET_i2s (&n->id));
4019 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4022 n->quota_violation_count++;
4024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4025 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
4026 n->in_tracker.available_bytes_per_s__,
4027 n->quota_violation_count);
4029 /* Discount 32k per violation */
4030 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4035 if (n->quota_violation_count > 0)
4037 /* try to add 32k back */
4038 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4040 n->quota_violation_count--;
4043 GNUNET_STATISTICS_update (stats,
4044 gettext_noop ("# payload received from other peers"),
4047 /* transmit message to all clients */
4048 uint32_t ats_count = 2;
4049 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
4050 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4053 im = GNUNET_malloc (size);
4054 im->header.size = htons (size);
4055 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4057 im->ats_count = htonl(ats_count);
4058 /* Setting ATS data */
4059 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4060 (&(im->ats))[0].value = htonl (n->distance);
4061 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4062 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4063 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4064 (&(im->ats))[ats_count].value = htonl (0);
4066 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
4068 while (cpos != NULL)
4070 transmit_to_client (cpos, &im->header, GNUNET_YES);
4078 * Iterator over hash map entries. Checks if the given validation
4079 * entry is for the same challenge as what is given in the PONG.
4081 * @param cls the 'struct TransportPongMessage*'
4082 * @param key peer identity
4083 * @param value value in the hash map ('struct ValidationEntry')
4084 * @return GNUNET_YES if we should continue to
4085 * iterate (mismatch), GNUNET_NO if not (entry matched)
4088 check_pending_validation (void *cls,
4089 const GNUNET_HashCode * key,
4092 const struct TransportPongMessage *pong = cls;
4093 struct ValidationEntry *ve = value;
4094 struct AddValidatedAddressContext avac;
4095 unsigned int challenge = ntohl(pong->challenge);
4096 struct GNUNET_HELLO_Message *hello;
4097 struct GNUNET_PeerIdentity target;
4098 struct NeighbourList *n;
4099 struct ForeignAddressList *fal;
4100 struct OwnAddressList *oal;
4101 struct TransportPlugin *tp;
4102 struct GNUNET_MessageHeader *prem;
4108 ps = ntohs (pong->header.size);
4109 if (ps < sizeof (struct TransportPongMessage))
4111 GNUNET_break_op (0);
4114 addr = (const char*) &pong[1];
4115 slen = strlen (ve->transport_name) + 1;
4116 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4117 (ve->challenge != challenge) ||
4118 (addr[slen-1] != '\0') ||
4119 (0 != strcmp (addr, ve->transport_name)) ||
4120 (ntohl (pong->purpose.size)
4121 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4123 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4124 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4129 alen = ps - sizeof (struct TransportPongMessage) - slen;
4130 switch (ntohl (pong->purpose.purpose))
4132 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4133 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4134 (0 != memcmp (&addr[slen],
4138 return GNUNET_YES; /* different entry, keep trying! */
4140 if (0 != memcmp (&pong->pid,
4142 sizeof (struct GNUNET_PeerIdentity)))
4144 GNUNET_break_op (0);
4148 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4153 GNUNET_break_op (0);
4158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4159 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4161 a2s (ve->transport_name,
4162 (const struct sockaddr *) ve->addr,
4164 ve->transport_name);
4167 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4168 if (0 != memcmp (&pong->pid,
4170 sizeof (struct GNUNET_PeerIdentity)))
4173 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4176 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4177 GNUNET_i2s (&my_identity),
4183 if (ve->addrlen != 0)
4185 /* must have been for a different validation entry */
4188 tp = find_transport (ve->transport_name);
4194 oal = tp->addresses;
4197 if ( (oal->addrlen == alen) &&
4198 (0 == memcmp (&oal[1],
4206 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4207 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
4208 a2s (ve->transport_name,
4214 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4219 GNUNET_break_op (0);
4224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4225 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4227 a2s (ve->transport_name,
4230 ve->transport_name);
4234 GNUNET_break_op (0);
4237 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4239 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4240 _("Received expired signature. Check system time.\n"));
4243 GNUNET_STATISTICS_update (stats,
4244 gettext_noop ("# address validation successes"),
4247 /* create the updated HELLO */
4248 GNUNET_CRYPTO_hash (&ve->publicKey,
4249 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4250 &target.hashPubKey);
4251 if (ve->addr != NULL)
4253 avac.done = GNUNET_NO;
4255 hello = GNUNET_HELLO_create (&ve->publicKey,
4256 &add_validated_address,
4258 GNUNET_PEERINFO_add_peer (peerinfo,
4260 GNUNET_free (hello);
4262 n = find_neighbour (&target);
4265 n->publicKey = ve->publicKey;
4266 n->public_key_valid = GNUNET_YES;
4267 fal = add_peer_address (n,
4272 GNUNET_assert (fal != NULL);
4273 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4274 fal->validated = GNUNET_YES;
4275 mark_address_connected (fal);
4276 GNUNET_STATISTICS_update (stats,
4277 gettext_noop ("# peer addresses considered valid"),
4280 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4281 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4283 schedule_next_ping (fal);
4284 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4285 n->latency = fal->latency;
4287 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4289 n->distance = fal->distance;
4290 if (GNUNET_NO == n->received_pong)
4292 n->received_pong = GNUNET_YES;
4294 notify_clients_connect (&target, n->latency, n->distance);
4295 if (NULL != (prem = n->pre_connect_message_buffer))
4297 n->pre_connect_message_buffer = NULL;
4298 handle_payload_message (prem, n);
4302 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4304 GNUNET_SCHEDULER_cancel (n->retry_task);
4305 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4306 try_transmission_to_peer (n);
4310 /* clean up validation entry */
4311 GNUNET_assert (GNUNET_YES ==
4312 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4315 abort_validation (NULL, NULL, ve);
4321 * Function that will be called if we receive a validation
4322 * of an address challenge that we transmitted to another
4323 * peer. Note that the validation should only be considered
4324 * acceptable if the challenge matches AND if the sender
4325 * address is at least a plausible address for this peer
4326 * (otherwise we may be seeing a MiM attack).
4328 * @param cls closure
4329 * @param message the pong message
4330 * @param peer who responded to our challenge
4331 * @param sender_address string describing our sender address (as observed
4332 * by the other peer in binary format)
4333 * @param sender_address_len number of bytes in 'sender_address'
4336 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4337 const struct GNUNET_PeerIdentity *peer,
4338 const char *sender_address,
4339 size_t sender_address_len)
4341 #if DEBUG_TRANSPORT > 1
4342 /* we get tons of these that just get discarded, only log
4343 if we are quite verbose */
4344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4345 "Receiving `%s' message from `%4s'.\n", "PONG",
4348 GNUNET_STATISTICS_update (stats,
4349 gettext_noop ("# PONG messages received"),
4352 if (GNUNET_SYSERR !=
4353 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4355 &check_pending_validation,
4358 /* This is *expected* to happen a lot since we send
4359 PONGs to *all* known addresses of the sender of
4360 the PING, so most likely we get multiple PONGs
4361 per PING, and all but the first PONG will end up
4362 here. So really we should not print anything here
4363 unless we want to be very, very verbose... */
4364 #if DEBUG_TRANSPORT > 2
4365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4366 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4378 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4380 * @param cls the 'struct ValidationEntry*'
4381 * @param neighbour neighbour to validate, NULL if validation failed
4384 transmit_hello_and_ping (void *cls,
4385 struct NeighbourList *neighbour)
4387 struct ValidationEntry *va = cls;
4388 struct ForeignAddressList *peer_address;
4389 struct TransportPingMessage ping;
4390 uint16_t hello_size;
4393 struct GNUNET_PeerIdentity id;
4396 GNUNET_CRYPTO_hash (&va->publicKey,
4397 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4399 if (neighbour == NULL)
4401 /* FIXME: stats... */
4402 GNUNET_break (GNUNET_OK ==
4403 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4406 abort_validation (NULL, NULL, va);
4409 neighbour->publicKey = va->publicKey;
4410 neighbour->public_key_valid = GNUNET_YES;
4411 peer_address = add_peer_address (neighbour,
4412 va->transport_name, NULL,
4413 (const void*) &va[1],
4415 if (peer_address == NULL)
4417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4418 "Failed to add peer `%4s' for plugin `%s'\n",
4419 GNUNET_i2s (&neighbour->id),
4420 va->transport_name);
4421 GNUNET_break (GNUNET_OK ==
4422 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4425 abort_validation (NULL, NULL, va);
4428 hello_size = GNUNET_HELLO_size(our_hello);
4429 slen = strlen(va->transport_name) + 1;
4430 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4431 message_buf = GNUNET_malloc(tsize);
4432 ping.challenge = htonl(va->challenge);
4433 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4434 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4435 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4436 memcpy(message_buf, our_hello, hello_size);
4437 memcpy(&message_buf[hello_size],
4439 sizeof(struct TransportPingMessage));
4440 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4443 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4448 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4451 : a2s (va->transport_name,
4452 (const void*) &va[1], va->addrlen),
4454 GNUNET_i2s (&neighbour->id),
4455 "HELLO", hello_size,
4456 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4459 GNUNET_STATISTICS_update (stats,
4460 gettext_noop ("# PING messages sent for initial validation"),
4463 transmit_to_peer (NULL, peer_address,
4464 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4465 HELLO_VERIFICATION_TIMEOUT,
4467 GNUNET_YES, neighbour);
4468 GNUNET_free(message_buf);
4473 * Check if the given address is already being validated; if not,
4474 * append the given address to the list of entries that are being be
4475 * validated and initiate validation.
4477 * @param cls closure ('struct CheckHelloValidatedContext *')
4478 * @param tname name of the transport
4479 * @param expiration expiration time
4480 * @param addr the address
4481 * @param addrlen length of the address
4482 * @return GNUNET_OK (always)
4485 run_validation (void *cls,
4487 struct GNUNET_TIME_Absolute expiration,
4491 struct CheckHelloValidatedContext *chvc = cls;
4492 struct GNUNET_PeerIdentity id;
4493 struct TransportPlugin *tp;
4494 struct ValidationEntry *va;
4495 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4496 struct CheckAddressExistsClosure caec;
4497 struct OwnAddressList *oal;
4499 GNUNET_assert (addr != NULL);
4501 GNUNET_STATISTICS_update (stats,
4502 gettext_noop ("# peer addresses scheduled for validation"),
4505 tp = find_transport (tname);
4508 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4509 GNUNET_ERROR_TYPE_BULK,
4511 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4513 GNUNET_STATISTICS_update (stats,
4514 gettext_noop ("# peer addresses not validated (plugin not available)"),
4519 /* check if this is one of our own addresses */
4520 oal = tp->addresses;
4523 if ( (oal->addrlen == addrlen) &&
4524 (0 == memcmp (&oal[1],
4528 /* not plausible, this address is equivalent to our own address! */
4529 GNUNET_STATISTICS_update (stats,
4530 gettext_noop ("# peer addresses not validated (loopback)"),
4537 GNUNET_HELLO_get_key (chvc->hello, &pk);
4538 GNUNET_CRYPTO_hash (&pk,
4540 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4543 if (is_blacklisted(&id, tp))
4546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4547 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4555 caec.addrlen = addrlen;
4556 caec.session = NULL;
4558 caec.exists = GNUNET_NO;
4559 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4560 &check_address_exists,
4562 if (caec.exists == GNUNET_YES)
4564 /* During validation attempts we will likely trigger the other
4565 peer trying to validate our address which in turn will cause
4566 it to send us its HELLO, so we expect to hit this case rather
4567 frequently. Only print something if we are very verbose. */
4568 #if DEBUG_TRANSPORT > 1
4569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4570 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4571 a2s (tname, addr, addrlen),
4575 GNUNET_STATISTICS_update (stats,
4576 gettext_noop ("# peer addresses not validated (in progress)"),
4581 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4584 va->transport_name = GNUNET_strdup (tname);
4585 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4587 va->send_time = GNUNET_TIME_absolute_get();
4588 va->addr = (const void*) &va[1];
4589 memcpy (&va[1], addr, addrlen);
4590 va->addrlen = addrlen;
4591 GNUNET_HELLO_get_key (chvc->hello,
4593 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4594 &timeout_hello_validation,
4596 GNUNET_CONTAINER_multihashmap_put (validation_map,
4599 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4600 setup_peer_check_blacklist (&id, GNUNET_NO,
4601 &transmit_hello_and_ping,
4608 * Check if addresses in validated hello "h" overlap with
4609 * those in "chvc->hello" and validate the rest.
4611 * @param cls closure
4612 * @param peer id of the peer, NULL for last call
4613 * @param h hello message for the peer (can be NULL)
4614 * @param err_msg NULL if successful, otherwise contains error message
4617 check_hello_validated (void *cls,
4618 const struct GNUNET_PeerIdentity *peer,
4619 const struct GNUNET_HELLO_Message *h,
4620 const char *err_msg)
4622 struct CheckHelloValidatedContext *chvc = cls;
4623 struct GNUNET_HELLO_Message *plain_hello;
4624 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4625 struct GNUNET_PeerIdentity target;
4626 struct NeighbourList *n;
4628 if (err_msg != NULL)
4631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4632 _("Error in communication with PEERINFO service: %s\n"),
4640 GNUNET_STATISTICS_update (stats,
4641 gettext_noop ("# outstanding peerinfo iterate requests"),
4645 if (GNUNET_NO == chvc->hello_known)
4647 /* notify PEERINFO about the peer now, so that we at least
4648 have the public key if some other component needs it */
4649 GNUNET_HELLO_get_key (chvc->hello, &pk);
4650 GNUNET_CRYPTO_hash (&pk,
4651 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4652 &target.hashPubKey);
4653 plain_hello = GNUNET_HELLO_create (&pk,
4656 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4657 GNUNET_free (plain_hello);
4658 #if DEBUG_TRANSPORT_HELLO
4659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4660 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4662 GNUNET_i2s (&target));
4664 GNUNET_STATISTICS_update (stats,
4665 gettext_noop ("# new HELLOs requiring full validation"),
4668 GNUNET_HELLO_iterate_addresses (chvc->hello,
4675 GNUNET_STATISTICS_update (stats,
4676 gettext_noop ("# duplicate HELLO (peer known)"),
4681 if (chvc->ve_count == 0)
4683 GNUNET_CONTAINER_DLL_remove (chvc_head,
4692 #if DEBUG_TRANSPORT_HELLO
4693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4694 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4698 chvc->hello_known = GNUNET_YES;
4699 n = find_neighbour (peer);
4702 #if DEBUG_TRANSPORT_HELLO
4703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4704 "Calling hello_iterate_addresses for %s!\n",
4707 GNUNET_HELLO_iterate_addresses (h,
4709 &add_to_foreign_address_list,
4711 try_transmission_to_peer (n);
4715 #if DEBUG_TRANSPORT_HELLO
4716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4717 "No existing neighbor record for %s!\n",
4720 GNUNET_STATISTICS_update (stats,
4721 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4725 GNUNET_STATISTICS_update (stats,
4726 gettext_noop ("# HELLO validations (update case)"),
4729 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4731 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4738 * Process HELLO-message.
4740 * @param plugin transport involved, may be NULL
4741 * @param message the actual message
4742 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4745 process_hello (struct TransportPlugin *plugin,
4746 const struct GNUNET_MessageHeader *message)
4749 struct GNUNET_PeerIdentity target;
4750 const struct GNUNET_HELLO_Message *hello;
4751 struct CheckHelloValidatedContext *chvc;
4752 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4753 #if DEBUG_TRANSPORT_HELLO > 2
4756 hsize = ntohs (message->size);
4757 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4758 (hsize < sizeof (struct GNUNET_MessageHeader)))
4761 return GNUNET_SYSERR;
4763 GNUNET_STATISTICS_update (stats,
4764 gettext_noop ("# HELLOs received for validation"),
4768 /* first, check if load is too high */
4769 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4771 GNUNET_STATISTICS_update (stats,
4772 gettext_noop ("# HELLOs ignored due to high load"),
4775 #if DEBUG_TRANSPORT_HELLO
4776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4777 "Ignoring `%s' for `%4s', load too high.\n",
4779 GNUNET_i2s (&target));
4783 hello = (const struct GNUNET_HELLO_Message *) message;
4784 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4786 #if DEBUG_TRANSPORT_HELLO
4787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4788 "Unable to get public key from `%s' for `%4s'!\n",
4790 GNUNET_i2s (&target));
4792 GNUNET_break_op (0);
4793 return GNUNET_SYSERR;
4796 GNUNET_CRYPTO_hash (&publicKey,
4797 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4798 &target.hashPubKey);
4800 #if DEBUG_TRANSPORT_HELLO
4801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4802 "Received `%s' message for `%4s'\n",
4804 GNUNET_i2s (&target));
4807 if (0 == memcmp (&my_identity,
4809 sizeof (struct GNUNET_PeerIdentity)))
4811 GNUNET_STATISTICS_update (stats,
4812 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4818 while (NULL != chvc)
4820 if (GNUNET_HELLO_equals (hello,
4822 GNUNET_TIME_absolute_get ()).abs_value > 0)
4824 #if DEBUG_TRANSPORT_HELLO > 2
4825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4826 "Received duplicate `%s' message for `%4s'; ignored\n",
4828 GNUNET_i2s (&target));
4830 return GNUNET_OK; /* validation already pending */
4832 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4833 GNUNET_break (0 != memcmp (hello, chvc->hello,
4834 GNUNET_HELLO_size(hello)));
4839 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4840 if ((NULL != temp_neighbor))
4842 fprintf(stderr, "Already know peer, ignoring hello\n");
4847 #if DEBUG_TRANSPORT_HELLO > 2
4850 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4853 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4856 GNUNET_i2s (&target),
4858 GNUNET_HELLO_size(hello));
4863 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4865 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4866 memcpy (&chvc[1], hello, hsize);
4867 GNUNET_CONTAINER_DLL_insert (chvc_head,
4870 /* finally, check if HELLO was previously validated
4871 (continuation will then schedule actual validation) */
4872 GNUNET_STATISTICS_update (stats,
4873 gettext_noop ("# peerinfo process hello iterate requests"),
4876 GNUNET_STATISTICS_update (stats,
4877 gettext_noop ("# outstanding peerinfo iterate requests"),
4880 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4882 HELLO_VERIFICATION_TIMEOUT,
4883 &check_hello_validated, chvc);
4889 * The peer specified by the given neighbour has timed-out or a plugin
4890 * has disconnected. We may either need to do nothing (other plugins
4891 * still up), or trigger a full disconnect and clean up. This
4892 * function updates our state and does the necessary notifications.
4893 * Also notifies our clients that the neighbour is now officially
4896 * @param n the neighbour list entry for the peer
4897 * @param check GNUNET_YES to check if ALL addresses for this peer
4898 * are gone, GNUNET_NO to force a disconnect of the peer
4899 * regardless of whether other addresses exist.
4902 disconnect_neighbour (struct NeighbourList *n, int check)
4904 struct ReadyList *rpos;
4905 struct NeighbourList *npos;
4906 struct NeighbourList *nprev;
4907 struct MessageQueue *mq;
4908 struct ForeignAddressList *peer_addresses;
4909 struct ForeignAddressList *peer_pos;
4911 if (GNUNET_YES == check)
4914 while (NULL != rpos)
4916 peer_addresses = rpos->addresses;
4917 while (peer_addresses != NULL)
4919 if (GNUNET_YES == peer_addresses->connected)
4922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4923 "NOT Disconnecting from `%4s', still have live addresses!\n",
4924 GNUNET_i2s (&n->id));
4926 return; /* still connected */
4928 peer_addresses = peer_addresses->next;
4934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4935 "Disconnecting from `%4s'\n",
4936 GNUNET_i2s (&n->id));
4938 /* remove n from neighbours list */
4941 while ((npos != NULL) && (npos != n))
4946 GNUNET_assert (npos != NULL);
4948 neighbours = n->next;
4950 nprev->next = n->next;
4952 /* notify all clients about disconnect */
4953 if (GNUNET_YES == n->received_pong)
4954 notify_clients_disconnect (&n->id);
4956 /* clean up all plugins, cancel connections and pending transmissions */
4957 while (NULL != (rpos = n->plugins))
4959 n->plugins = rpos->next;
4960 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4961 while (rpos->addresses != NULL)
4963 peer_pos = rpos->addresses;
4964 rpos->addresses = peer_pos->next;
4965 if (peer_pos->connected == GNUNET_YES)
4966 GNUNET_STATISTICS_update (stats,
4967 gettext_noop ("# connected addresses"),
4970 if (GNUNET_YES == peer_pos->validated)
4971 GNUNET_STATISTICS_update (stats,
4972 gettext_noop ("# peer addresses considered valid"),
4975 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4977 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4978 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4980 GNUNET_free(peer_pos->ressources);
4981 peer_pos->ressources = NULL;
4982 GNUNET_free(peer_pos->quality);
4983 peer_pos->ressources = NULL;
4984 GNUNET_free(peer_pos);
4985 ats->stat.recreate_problem = GNUNET_YES;
4990 /* free all messages on the queue */
4991 while (NULL != (mq = n->messages_head))
4993 GNUNET_STATISTICS_update (stats,
4994 gettext_noop ("# bytes in message queue for other peers"),
4995 - (int64_t) mq->message_buf_size,
4997 GNUNET_STATISTICS_update (stats,
4998 gettext_noop ("# bytes discarded due to disconnect"),
4999 mq->message_buf_size,
5001 GNUNET_CONTAINER_DLL_remove (n->messages_head,
5004 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
5006 sizeof(struct GNUNET_PeerIdentity)));
5009 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
5011 GNUNET_SCHEDULER_cancel (n->timeout_task);
5012 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
5014 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
5016 GNUNET_SCHEDULER_cancel (n->retry_task);
5017 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
5019 if (n->piter != NULL)
5021 GNUNET_PEERINFO_iterate_cancel (n->piter);
5022 GNUNET_STATISTICS_update (stats,
5023 gettext_noop ("# outstanding peerinfo iterate requests"),
5028 /* finally, free n itself */
5029 GNUNET_STATISTICS_update (stats,
5030 gettext_noop ("# active neighbours"),
5033 GNUNET_free_non_null (n->pre_connect_message_buffer);
5039 * We have received a PING message from someone. Need to send a PONG message
5040 * in response to the peer by any means necessary.
5043 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
5044 const struct GNUNET_PeerIdentity *peer,
5045 struct Session *session,
5046 const char *sender_address,
5047 uint16_t sender_address_len)
5049 struct TransportPlugin *plugin = cls;
5050 struct SessionHeader *session_header = (struct SessionHeader*) session;
5051 struct TransportPingMessage *ping;
5052 struct TransportPongMessage *pong;
5053 struct NeighbourList *n;
5054 struct ReadyList *rl;
5055 struct ForeignAddressList *fal;
5056 struct OwnAddressList *oal;
5061 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5063 GNUNET_break_op (0);
5064 return GNUNET_SYSERR;
5067 ping = (struct TransportPingMessage *) message;
5068 if (0 != memcmp (&ping->target,
5069 plugin->env.my_identity,
5070 sizeof (struct GNUNET_PeerIdentity)))
5073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5074 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5076 (sender_address != NULL)
5077 ? a2s (plugin->short_name,
5078 (const struct sockaddr *)sender_address,
5081 GNUNET_i2s (&ping->target));
5083 return GNUNET_SYSERR;
5086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5087 "Processing `%s' from `%s'\n",
5089 (sender_address != NULL)
5090 ? a2s (plugin->short_name,
5091 (const struct sockaddr *)sender_address,
5095 GNUNET_STATISTICS_update (stats,
5096 gettext_noop ("# PING messages received"),
5099 addr = (const char*) &ping[1];
5100 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5101 slen = strlen (plugin->short_name) + 1;
5104 /* peer wants to confirm that we have an outbound connection to him */
5105 if (session == NULL)
5107 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5108 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5110 return GNUNET_SYSERR;
5112 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5113 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5114 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5115 pong->purpose.size =
5116 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5118 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5119 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5120 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5121 pong->challenge = ping->challenge;
5122 pong->addrlen = htonl(sender_address_len + slen);
5125 sizeof(struct GNUNET_PeerIdentity));
5129 if ((sender_address!=NULL) && (sender_address_len > 0))
5130 memcpy (&((char*)&pong[1])[slen],
5132 sender_address_len);
5133 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5135 /* create / update cached sig */
5137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5138 "Creating PONG signature to indicate active connection.\n");
5140 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5141 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5142 GNUNET_assert (GNUNET_OK ==
5143 GNUNET_CRYPTO_rsa_sign (my_private_key,
5145 &session_header->pong_signature));
5149 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5151 memcpy (&pong->signature,
5152 &session_header->pong_signature,
5153 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5159 /* peer wants to confirm that this is one of our addresses */
5163 plugin->api->check_address (plugin->api->cls,
5167 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5168 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5169 a2s (plugin->short_name,
5174 oal = plugin->addresses;
5177 if ( (oal->addrlen == alen) &&
5184 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5185 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5186 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5187 pong->purpose.size =
5188 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5190 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5191 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5192 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5193 pong->challenge = ping->challenge;
5194 pong->addrlen = htonl(alen + slen);
5197 sizeof(struct GNUNET_PeerIdentity));
5198 memcpy (&pong[1], plugin->short_name, slen);
5199 memcpy (&((char*)&pong[1])[slen], addr, alen);
5200 if ( (oal != NULL) &&
5201 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5203 /* create / update cached sig */
5205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5206 "Creating PONG signature to indicate ownership.\n");
5208 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
5209 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5210 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5211 GNUNET_assert (GNUNET_OK ==
5212 GNUNET_CRYPTO_rsa_sign (my_private_key,
5214 &oal->pong_signature));
5215 memcpy (&pong->signature,
5216 &oal->pong_signature,
5217 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5219 else if (oal == NULL)
5221 /* not using cache (typically DV-only) */
5222 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5223 GNUNET_assert (GNUNET_OK ==
5224 GNUNET_CRYPTO_rsa_sign (my_private_key,
5230 /* can used cached version */
5231 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5232 memcpy (&pong->signature,
5233 &oal->pong_signature,
5234 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5237 n = find_neighbour(peer);
5238 GNUNET_assert (n != NULL);
5239 /* first try reliable response transmission */
5243 fal = rl->addresses;
5246 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5249 ntohs (pong->header.size),
5250 TRANSPORT_PONG_PRIORITY,
5251 HELLO_VERIFICATION_TIMEOUT,
5259 GNUNET_STATISTICS_update (stats,
5260 gettext_noop ("# PONGs unicast via reliable transport"),
5270 /* no reliable method found, do multicast */
5271 GNUNET_STATISTICS_update (stats,
5272 gettext_noop ("# PONGs multicast to all available addresses"),
5278 fal = rl->addresses;
5281 transmit_to_peer(NULL, fal,
5282 TRANSPORT_PONG_PRIORITY,
5283 HELLO_VERIFICATION_TIMEOUT,
5285 ntohs(pong->header.size),
5301 * Function called by the plugin for each received message.
5302 * Update data volumes, possibly notify plugins about
5303 * reducing the rate at which they read from the socket
5304 * and generally forward to our receive callback.
5306 * @param cls the "struct TransportPlugin *" we gave to the plugin
5307 * @param peer (claimed) identity of the other peer
5308 * @param message the message, NULL if we only care about
5309 * learning about the delay until we should receive again
5310 * @param ats_data information for automatic transport selection
5311 * @param ats_count number of elements in ats not including 0-terminator
5312 * @param session identifier used for this session (can be NULL)
5313 * @param sender_address binary address of the sender (if observed)
5314 * @param sender_address_len number of bytes in sender_address
5315 * @return how long in ms the plugin should wait until receiving more data
5316 * (plugins that do not support this, can ignore the return value)
5318 static struct GNUNET_TIME_Relative
5319 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5320 const struct GNUNET_MessageHeader *message,
5321 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5323 struct Session *session,
5324 const char *sender_address,
5325 uint16_t sender_address_len)
5327 struct TransportPlugin *plugin = cls;
5328 struct ReadyList *service_context;
5329 struct ForeignAddressList *peer_address;
5331 struct NeighbourList *n;
5332 struct GNUNET_TIME_Relative ret;
5333 if (is_blacklisted (peer, plugin))
5334 return GNUNET_TIME_UNIT_FOREVER_REL;
5338 n = find_neighbour (peer);
5340 n = setup_new_neighbour (peer, GNUNET_YES);
5341 service_context = n->plugins;
5342 while ((service_context != NULL) && (plugin != service_context->plugin))
5343 service_context = service_context->next;
5344 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5345 peer_address = NULL;
5348 for (c=0; c<ats_count; c++)
5350 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5352 distance = ntohl(ats_data[c].value);
5356 /* notify ATS about incoming data */
5357 //ats_notify_ats_data(peer, ats_data);
5360 if (message != NULL)
5362 if ( (session != NULL) ||
5363 (sender_address != NULL) )
5364 peer_address = add_peer_address (n,
5368 sender_address_len);
5369 if (peer_address != NULL)
5372 update_addr_ats(peer_address, ats_data, ats_count);
5373 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5375 peer_address->distance = distance;
5376 if (GNUNET_YES == peer_address->validated)
5377 mark_address_connected (peer_address);
5378 peer_address->timeout
5380 GNUNET_TIME_relative_to_absolute
5381 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5382 schedule_next_ping (peer_address);
5384 /* update traffic received amount ... */
5385 msize = ntohs (message->size);
5387 GNUNET_STATISTICS_update (stats,
5388 gettext_noop ("# bytes received from other peers"),
5391 n->distance = distance;
5393 GNUNET_TIME_relative_to_absolute
5394 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5395 GNUNET_SCHEDULER_cancel (n->timeout_task);
5397 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5398 &neighbour_timeout_task, n);
5399 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5401 /* dropping message due to frequent inbound volume violations! */
5402 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5403 GNUNET_ERROR_TYPE_BULK,
5405 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5406 n->in_tracker.available_bytes_per_s__,
5407 n->quota_violation_count);
5408 GNUNET_STATISTICS_update (stats,
5409 gettext_noop ("# bandwidth quota violations by other peers"),
5412 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5414 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5415 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5417 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5418 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5419 /* Force ressource and quality update */
5422 ats->stat.modified_resources = GNUNET_YES;
5423 ats->stat.modified_quality = GNUNET_YES;
5425 /* Force cost update */
5427 ats->stat.modified_resources = GNUNET_YES;
5428 /* Force quality update */
5430 ats->stat.modified_quality = GNUNET_YES;
5431 /* Force full rebuild */
5433 ats->stat.recreate_problem = GNUNET_YES;
5437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5438 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5439 ntohs (message->type),
5440 ntohs (message->size),
5443 switch (ntohs (message->type))
5445 case GNUNET_MESSAGE_TYPE_HELLO:
5446 GNUNET_STATISTICS_update (stats,
5447 gettext_noop ("# HELLO messages received from other peers"),
5450 process_hello (plugin, message);
5452 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5453 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5455 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5456 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5458 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5461 handle_payload_message (message, n);
5465 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5466 if (ret.rel_value > 0)
5469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5470 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5471 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5472 (unsigned int) n->in_tracker.available_bytes_per_s__,
5473 (unsigned long long) ret.rel_value);
5475 GNUNET_STATISTICS_update (stats,
5476 gettext_noop ("# ms throttling suggested"),
5477 (int64_t) ret.rel_value,
5484 * Handle START-message. This is the first message sent to us
5485 * by any client which causes us to add it to our list.
5487 * @param cls closure (always NULL)
5488 * @param client identification of the client
5489 * @param message the actual message
5492 handle_start (void *cls,
5493 struct GNUNET_SERVER_Client *client,
5494 const struct GNUNET_MessageHeader *message)
5496 const struct StartMessage *start;
5497 struct TransportClient *c;
5498 struct ConnectInfoMessage * cim;
5499 struct NeighbourList *n;
5503 start = (const struct StartMessage*) message;
5505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5506 "Received `%s' request from client\n", "START");
5511 if (c->client == client)
5513 /* client already on our list! */
5515 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5520 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5521 (0 != memcmp (&start->self,
5523 sizeof (struct GNUNET_PeerIdentity))) )
5525 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5526 _("Rejecting control connection from peer `%s', which is not me!\n"),
5527 GNUNET_i2s (&start->self));
5528 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5531 c = GNUNET_malloc (sizeof (struct TransportClient));
5535 if (our_hello != NULL)
5538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5539 "Sending our own `%s' to new client\n", "HELLO");
5541 transmit_to_client (c,
5542 (const struct GNUNET_MessageHeader *) our_hello,
5544 /* tell new client about all existing connections */
5546 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5547 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5551 cim = GNUNET_malloc (size);
5552 cim->header.size = htons (size);
5553 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5554 cim->ats_count = htonl(ats_count);
5555 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5556 (&(cim->ats))[2].value = htonl (0);
5560 if (GNUNET_YES == n->received_pong)
5562 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5563 (&(cim->ats))[0].value = htonl (n->distance);
5564 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5565 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5567 transmit_to_client (c, &cim->header, GNUNET_NO);
5573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5578 * Handle HELLO-message.
5580 * @param cls closure (always NULL)
5581 * @param client identification of the client
5582 * @param message the actual message
5585 handle_hello (void *cls,
5586 struct GNUNET_SERVER_Client *client,
5587 const struct GNUNET_MessageHeader *message)
5591 GNUNET_STATISTICS_update (stats,
5592 gettext_noop ("# HELLOs received from clients"),
5595 ret = process_hello (NULL, message);
5596 GNUNET_SERVER_receive_done (client, ret);
5601 * Closure for 'transmit_client_message'; followed by
5602 * 'msize' bytes of the actual message.
5604 struct TransmitClientMessageContext
5607 * Client on whom's behalf we are sending.
5609 struct GNUNET_SERVER_Client *client;
5612 * Timeout for the transmission.
5614 struct GNUNET_TIME_Absolute timeout;
5622 * Size of the message in bytes.
5629 * Schedule transmission of a message we got from a client to a peer.
5631 * @param cls the 'struct TransmitClientMessageContext*'
5632 * @param n destination, or NULL on error (in that case, drop the message)
5635 transmit_client_message (void *cls,
5636 struct NeighbourList *n)
5638 struct TransmitClientMessageContext *tcmc = cls;
5639 struct TransportClient *tc;
5642 while ((tc != NULL) && (tc->client != tcmc->client))
5647 transmit_to_peer (tc, NULL, tcmc->priority,
5648 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5650 tcmc->msize, GNUNET_NO, n);
5652 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5653 GNUNET_SERVER_client_drop (tcmc->client);
5659 * Handle SEND-message.
5661 * @param cls closure (always NULL)
5662 * @param client identification of the client
5663 * @param message the actual message
5666 handle_send (void *cls,
5667 struct GNUNET_SERVER_Client *client,
5668 const struct GNUNET_MessageHeader *message)
5670 const struct OutboundMessage *obm;
5671 const struct GNUNET_MessageHeader *obmm;
5672 struct TransmitClientMessageContext *tcmc;
5676 size = ntohs (message->size);
5678 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5681 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5684 GNUNET_STATISTICS_update (stats,
5685 gettext_noop ("# payload received for other peers"),
5688 obm = (const struct OutboundMessage *) message;
5689 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5690 msize = size - sizeof (struct OutboundMessage);
5692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5693 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5694 "SEND", GNUNET_i2s (&obm->peer),
5698 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5699 tcmc->client = client;
5700 tcmc->priority = ntohl (obm->priority);
5701 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5702 tcmc->msize = msize;
5703 /* FIXME: this memcpy can be up to 7% of our total runtime */
5704 memcpy (&tcmc[1], obmm, msize);
5705 GNUNET_SERVER_client_keep (client);
5706 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5707 &transmit_client_message,
5713 * Handle request connect message
5715 * @param cls closure (always NULL)
5716 * @param client identification of the client
5717 * @param message the actual message
5720 handle_request_connect (void *cls,
5721 struct GNUNET_SERVER_Client *client,
5722 const struct GNUNET_MessageHeader *message)
5724 const struct TransportRequestConnectMessage *trcm =
5725 (const struct TransportRequestConnectMessage *) message;
5727 GNUNET_STATISTICS_update (stats,
5728 gettext_noop ("# REQUEST CONNECT messages received"),
5732 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5733 "Received a request connect message for peer `%s'\n",
5734 GNUNET_i2s(&trcm->peer));
5736 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5738 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5743 * Handle SET_QUOTA-message.
5745 * @param cls closure (always NULL)
5746 * @param client identification of the client
5747 * @param message the actual message
5750 handle_set_quota (void *cls,
5751 struct GNUNET_SERVER_Client *client,
5752 const struct GNUNET_MessageHeader *message)
5754 const struct QuotaSetMessage *qsm =
5755 (const struct QuotaSetMessage *) message;
5756 struct NeighbourList *n;
5758 GNUNET_STATISTICS_update (stats,
5759 gettext_noop ("# SET QUOTA messages received"),
5762 n = find_neighbour (&qsm->peer);
5765 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5766 GNUNET_STATISTICS_update (stats,
5767 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5774 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5776 (unsigned int) ntohl (qsm->quota.value__),
5777 (unsigned int) n->in_tracker.available_bytes_per_s__,
5778 GNUNET_i2s (&qsm->peer));
5780 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5782 if (0 == ntohl (qsm->quota.value__))
5785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5786 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5789 disconnect_neighbour (n, GNUNET_NO);
5791 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5796 * Take the given address and append it to the set of results sent back to
5799 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5800 * @param address the resolved name, NULL to indicate the last response
5803 transmit_address_to_client (void *cls, const char *address)
5805 struct GNUNET_SERVER_TransmitContext *tc = cls;
5808 if (NULL == address)
5811 slen = strlen (address) + 1;
5813 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5814 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5815 if (NULL == address)
5816 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5821 * Handle AddressLookup-message.
5823 * @param cls closure (always NULL)
5824 * @param client identification of the client
5825 * @param message the actual message
5828 handle_address_lookup (void *cls,
5829 struct GNUNET_SERVER_Client *client,
5830 const struct GNUNET_MessageHeader *message)
5832 const struct AddressLookupMessage *alum;
5833 struct TransportPlugin *lsPlugin;
5834 const char *nameTransport;
5835 const char *address;
5837 struct GNUNET_SERVER_TransmitContext *tc;
5838 struct GNUNET_TIME_Absolute timeout;
5839 struct GNUNET_TIME_Relative rtimeout;
5842 size = ntohs (message->size);
5843 if (size < sizeof (struct AddressLookupMessage))
5845 GNUNET_break_op (0);
5846 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5849 alum = (const struct AddressLookupMessage *) message;
5850 uint32_t addressLen = ntohl (alum->addrlen);
5851 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5853 GNUNET_break_op (0);
5854 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5857 address = (const char *) &alum[1];
5858 nameTransport = (const char *) &address[addressLen];
5860 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5862 GNUNET_break_op (0);
5863 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5866 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5867 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5868 numeric = ntohl (alum->numeric_only);
5869 lsPlugin = find_transport (nameTransport);
5870 if (NULL == lsPlugin)
5872 tc = GNUNET_SERVER_transmit_context_create (client);
5873 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5874 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5875 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5878 tc = GNUNET_SERVER_transmit_context_create (client);
5879 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5881 address, addressLen,
5884 &transmit_address_to_client, tc);
5889 * Setup the environment for this plugin.
5892 create_environment (struct TransportPlugin *plug)
5894 plug->env.cfg = cfg;
5895 plug->env.my_identity = &my_identity;
5896 plug->env.our_hello = &our_hello;
5897 plug->env.cls = plug;
5898 plug->env.receive = &plugin_env_receive;
5899 plug->env.notify_address = &plugin_env_notify_address;
5900 plug->env.session_end = &plugin_env_session_end;
5901 plug->env.max_connections = max_connect_per_transport;
5902 plug->env.stats = stats;
5907 * Start the specified transport (load the plugin).
5910 start_transport (struct GNUNET_SERVER_Handle *server,
5913 struct TransportPlugin *plug;
5916 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5917 _("Loading `%s' transport plugin\n"), name);
5918 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5919 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5920 create_environment (plug);
5921 plug->short_name = GNUNET_strdup (name);
5922 plug->lib_name = libname;
5923 plug->next = plugins;
5925 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5926 if (plug->api == NULL)
5928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5929 _("Failed to load transport plugin for `%s'\n"), name);
5930 GNUNET_free (plug->short_name);
5931 plugins = plug->next;
5932 GNUNET_free (libname);
5939 * Called whenever a client is disconnected. Frees our
5940 * resources associated with that client.
5942 * @param cls closure
5943 * @param client identification of the client
5946 client_disconnect_notification (void *cls,
5947 struct GNUNET_SERVER_Client *client)
5949 struct TransportClient *pos;
5950 struct TransportClient *prev;
5951 struct ClientMessageQueueEntry *mqe;
5952 struct Blacklisters *bl;
5953 struct BlacklistCheck *bc;
5958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5959 "Client disconnected, cleaning up.\n");
5961 /* clean up blacklister */
5965 if (bl->client == client)
5970 if (bc->bl_pos == bl)
5972 bc->bl_pos = bl->next;
5975 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5978 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5979 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5985 GNUNET_CONTAINER_DLL_remove (bl_head,
5988 GNUNET_SERVER_client_drop (bl->client);
5994 /* clean up 'normal' clients */
5997 while ((pos != NULL) && (pos->client != client))
6004 while (NULL != (mqe = pos->message_queue_head))
6006 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6007 pos->message_queue_tail,
6009 pos->message_count--;
6013 clients = pos->next;
6015 prev->next = pos->next;
6016 if (GNUNET_YES == pos->tcs_pending)
6021 if (pos->th != NULL)
6023 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6026 GNUNET_break (0 == pos->message_count);
6032 * Function called when the service shuts down. Unloads our plugins
6033 * and cancels pending validations.
6035 * @param cls closure, unused
6036 * @param tc task context (unused)
6039 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6041 struct TransportPlugin *plug;
6042 struct OwnAddressList *al;
6043 struct CheckHelloValidatedContext *chvc;
6045 while (neighbours != NULL)
6048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6049 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6052 disconnect_neighbour (neighbours, GNUNET_NO);
6055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6056 "Transport service is unloading plugins...\n");
6058 while (NULL != (plug = plugins))
6060 plugins = plug->next;
6061 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6063 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6064 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6066 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6067 GNUNET_free (plug->lib_name);
6068 GNUNET_free (plug->short_name);
6069 while (NULL != (al = plug->addresses))
6071 plug->addresses = al->next;
6076 if (my_private_key != NULL)
6077 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6078 GNUNET_free_non_null (our_hello);
6080 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6083 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6084 validation_map = NULL;
6088 /* free 'chvc' data structure */
6089 while (NULL != (chvc = chvc_head))
6091 chvc_head = chvc->next;
6092 if (chvc->piter != NULL)
6094 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6095 GNUNET_STATISTICS_update (stats,
6096 gettext_noop ("# outstanding peerinfo iterate requests"),
6103 GNUNET_assert (chvc->ve_count == 0);
6110 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6113 if (peerinfo != NULL)
6115 GNUNET_PEERINFO_disconnect (peerinfo);
6118 /* Can we assume those are gone by now, or do we need to clean up
6120 GNUNET_break (bl_head == NULL);
6121 GNUNET_break (bc_head == NULL);
6125 static int ats_evaluate_results (int result, int solution, char * problem)
6127 int cont = GNUNET_NO;
6128 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
6130 error_kind = GNUNET_ERROR_TYPE_ERROR;
6134 case GLP_ESTOP : /* search terminated by application */
6135 GNUNET_log (error_kind, "%s , Search terminated by application\n", problem);
6137 case GLP_EITLIM : /* iteration limit exceeded */
6138 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Iteration limit exceeded\n", problem);
6141 case GLP_ETMLIM : /* time limit exceeded */
6142 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Time limit exceeded\n", problem);
6144 case GLP_ENOPFS : /* no primal feasible solution */
6145 case GLP_ENODFS : /* no dual feasible solution */
6146 GNUNET_log (error_kind, "%s No feasible solution\n", problem);
6149 case GLP_EBADB : /* invalid basis */
6150 case GLP_ESING : /* singular matrix */
6151 case GLP_ECOND : /* ill-conditioned matrix */
6152 case GLP_EBOUND : /* invalid bounds */
6153 case GLP_EFAIL : /* solver failed */
6154 case GLP_EOBJLL : /* objective lower limit reached */
6155 case GLP_EOBJUL : /* objective upper limit reached */
6156 case GLP_EROOT : /* root LP optimum not provided */
6157 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
6161 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
6167 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
6170 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
6174 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"));
6178 GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem, (0==strcmp(problem,"LP")?"":"integer "));
6181 GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
6184 GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
6191 static void ats_solve_problem (unsigned int max_it, unsigned int max_dur, unsigned int c_peers, unsigned int c_mechs, struct ATS_stat *stat)
6200 glp_init_smcp(&opt_lp);
6202 opt_lp.msg_lev = GLP_MSG_ALL;
6204 opt_lp.msg_lev = GLP_MSG_OFF;
6207 // setting iteration limit
6208 opt_lp.it_lim = max_it;
6210 opt_lp.tm_lim = max_dur;
6212 if (ats->stat.recreate_problem == GNUNET_YES)
6213 opt_lp.presolve = GLP_ON;
6214 result = glp_simplex(ats->prob, &opt_lp);
6215 lp_solution = glp_get_status (ats->prob);
6217 if ((result == GLP_ETMLIM) || (result == GLP_ETMLIM))
6219 ats->stat.valid = GNUNET_NO;
6220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS exceeded time or iteration limit!\n");
6224 if (ats_evaluate_results(result, lp_solution, "LP") == GNUNET_YES)
6226 stat->valid = GNUNET_YES;
6230 ats->stat.simplex_rerun_required = GNUNET_YES;
6231 opt_lp.presolve = GLP_ON;
6232 result = glp_simplex(ats->prob, &opt_lp);
6233 lp_solution = glp_get_status (ats->prob);
6235 // TODO: Remove if this does not appear until release
6236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "EXECUTED SIMPLEX WITH PRESOLVER! %i \n", lp_solution);
6238 if (ats_evaluate_results(result, lp_solution, "LP") != GNUNET_YES)
6240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "After execution simplex with presolver: STILL INVALID!\n");
6242 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",ats->stat.c_peers, ats->stat.c_mechs, GNUNET_TIME_absolute_get().abs_value);
6243 glp_write_lp (ats->prob, NULL, filename);
6244 GNUNET_free (filename);
6245 stat->valid = GNUNET_NO;
6246 ats->stat.recreate_problem = GNUNET_YES;
6249 stat->valid = GNUNET_YES;
6254 glp_init_iocp(&opt_mlp);
6256 opt_mlp.tm_lim = max_dur;
6259 opt_mlp.msg_lev = GLP_MSG_ALL;
6261 opt_mlp.msg_lev = GLP_MSG_OFF;
6264 result = glp_intopt (ats->prob, &opt_mlp);
6265 mlp_solution = glp_mip_status (ats->prob);
6266 stat->solution = mlp_solution;
6268 if (ats_evaluate_results(result, mlp_solution, "MLP") == GNUNET_YES)
6270 stat->valid = GNUNET_YES;
6274 // TODO: Remove if this does not appear until release
6275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP SOLUTION INVALID: %i\n", lp_solution);
6276 stat->valid = GNUNET_NO;
6281 int error = GNUNET_NO;
6283 struct ATS_mechanism *t = NULL;
6284 for (c=1; c<= (c_peers); c++ )
6287 t = peers[c].m_head;
6290 bw = glp_get_col_prim(prob, t->col_index);
6294 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);
6296 if (check ==GNUNET_YES)
6298 glp_write_sol(prob, "invalid_solution.mlp");
6299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6300 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6303 if (check ==GNUNET_NO)
6311 if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
6314 for (c=1; c<= available_quality_metrics; c++ )
6316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3+c), glp_get_col_prim(ats->prob,2*c_mechs+3+c));
6318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+1), glp_get_col_prim(ats->prob,2*c_mechs+1));
6319 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+2), glp_get_col_prim(ats->prob,2*c_mechs+2));
6320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3), glp_get_col_prim(ats->prob,2*c_mechs+3));
6321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value: %f\n", glp_mip_obj_val(ats->prob));
6326 static void ats_delete_problem ()
6329 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting problem\n");
6333 for (c=0; c< (ats->stat).c_mechs; c++)
6334 GNUNET_free_non_null (ats->mechanisms[c].rc);
6337 if (ats->mechanisms!=NULL)
6339 GNUNET_free(ats->mechanisms);
6340 ats->mechanisms = NULL;
6343 if (ats->peers!=NULL)
6345 GNUNET_free(ats->peers);
6349 if (ats->prob != NULL)
6351 glp_delete_prob(ats->prob);
6355 ats->stat.begin_cr = GNUNET_SYSERR;
6356 ats->stat.begin_qm = GNUNET_SYSERR;
6357 ats->stat.c_mechs = 0;
6358 ats->stat.c_peers = 0;
6359 ats->stat.end_cr = GNUNET_SYSERR;
6360 ats->stat.end_qm = GNUNET_SYSERR;
6361 ats->stat.solution = GNUNET_SYSERR;
6362 ats->stat.valid = GNUNET_SYSERR;
6366 static void ats_update_problem_qm ()
6371 int c_q_metrics = available_quality_metrics;
6373 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6374 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6376 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6378 row_index = ats->stat.begin_qm;
6380 for (c=1; c <= c_q_metrics; c++)
6385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6388 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6389 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6391 ja[array_index] = c2;
6393 GNUNET_assert (ats->mechanisms[c2].addr != NULL);
6394 GNUNET_assert (ats->mechanisms[c2].peer != NULL);
6396 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6398 double v0 = 0, v1 = 0, v2 = 0;
6400 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6401 if (v1 < 1) v0 = 0.1;
6402 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6403 if (v1 < 1) v0 = 0.1;
6404 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6405 if (v1 < 1) v0 = 0.1;
6406 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6409 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6411 double v0 = 0, v1 = 0, v2 = 0;
6412 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6414 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6416 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6418 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6420 value = (double) 10 / value;
6424 ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6426 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]);
6430 ja[array_index] = ats->stat.col_qm + c - 1;
6431 ar[array_index] = -1;
6434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6436 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6442 GNUNET_free_non_null (ja);
6443 GNUNET_free_non_null (ar);
6447 static void ats_update_problem_cr ()
6453 double ct_max, ct_min;
6455 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6456 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6458 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6459 row_index = ats->stat.begin_cr;
6461 for (c=0; c<available_ressources; c++)
6463 ct_max = ressources[c].c_max;
6464 ct_min = ressources[c].c_min;
6466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6468 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6470 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6474 GNUNET_assert (ats->mechanisms[c2].addr != NULL);
6475 GNUNET_assert (ats->mechanisms[c2].peer != NULL);
6477 ja[array_index] = c2;
6478 value = ats->mechanisms[c2].addr->ressources[c].c;
6479 ar[array_index] = value;
6481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6485 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6491 GNUNET_free_non_null (ja);
6492 GNUNET_free_non_null (ar);
6497 static void ats_update_problem_qm_TEST ()
6502 int old_ja[ats->stat.c_mechs + 2];
6503 double old_ar[ats->stat.c_mechs + 2];
6507 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6508 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6510 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
6512 if (ats->stat.begin_qm >0)
6513 row_index = ats->stat.begin_qm;
6518 for (c=0; c<available_quality_metrics; c++)
6521 c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
6523 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6525 for (c2=1; c2<=c_old; c2++)
6527 ja[c2] = old_ja[c2];
6528 if ((changed < 3) && (c2>2) && (old_ar[c2] != -1))
6530 ar[c2] = old_ar[c2] + 5 - changed;
6534 ar[c2] = old_ar[c2];
6536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: old [%i,%i]=%f new [%i,%i]=%f\n",c2, row_index, old_ja[c2], old_ar[c2], row_index, ja[c2], ar[c2]);
6539 glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
6544 GNUNET_free_non_null (ja);
6545 GNUNET_free_non_null (ar);
6547 #endif //END: HAVE_LIBGLPK
6549 /** solve the bandwidth distribution problem
6550 * @param max_it maximum iterations
6551 * @param max_dur maximum duration in ms
6552 * @param D weight for diversity
6553 * @param U weight for utility
6554 * @param R weight for relativity
6555 * @param v_b_min minimal bandwidth per peer
6556 * @param v_n_min minimum number of connections
6557 * @param stat result struct
6558 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6560 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
6562 ats->prob = glp_create_prob();
6568 int c_c_ressources = available_ressources;
6569 int c_q_metrics = available_quality_metrics;
6571 double M = VERY_BIG_DOUBLE_VALUE;
6572 double Q[c_q_metrics+1];
6573 for (c=1; c<=c_q_metrics; c++)
6578 struct NeighbourList *next = neighbours;
6581 int found_addresses = GNUNET_NO;
6582 struct ReadyList *r_next = next->plugins;
6583 while (r_next != NULL)
6585 struct ForeignAddressList * a_next = r_next->addresses;
6586 while (a_next != NULL)
6589 found_addresses = GNUNET_YES;
6590 a_next = a_next->next;
6592 r_next = r_next->next;
6594 if (found_addresses) c_peers++;
6601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6603 stat->valid = GNUNET_NO;
6606 return GNUNET_SYSERR;
6609 ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6610 ats->peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6612 struct ATS_mechanism * mechanisms = ats->mechanisms;
6613 struct ATS_peer * peers = ats->peers;
6621 int found_addresses = GNUNET_NO;
6622 struct ReadyList *r_next = next->plugins;
6623 while (r_next != NULL)
6625 struct ForeignAddressList * a_next = r_next->addresses;
6626 while (a_next != NULL)
6628 if (found_addresses == GNUNET_NO)
6630 peers[c_peers].peer = next->id;
6631 peers[c_peers].m_head = NULL;
6632 peers[c_peers].m_tail = NULL;
6633 peers[c_peers].f = 1.0 / c_mechs;
6636 mechanisms[c_mechs].addr = a_next;
6637 mechanisms[c_mechs].col_index = c_mechs;
6638 mechanisms[c_mechs].peer = &peers[c_peers];
6639 mechanisms[c_mechs].next = NULL;
6640 mechanisms[c_mechs].plugin = r_next->plugin;
6642 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6643 found_addresses = GNUNET_YES;
6646 a_next = a_next->next;
6648 r_next = r_next->next;
6650 if (found_addresses == GNUNET_YES)
6657 if (v_n_min > c_peers)
6661 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);
6664 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6667 int * ia = GNUNET_malloc (size * sizeof (int));
6668 int * ja = GNUNET_malloc (size * sizeof (int));
6669 double * ar = GNUNET_malloc(size* sizeof (double));
6671 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6672 glp_set_obj_dir(ats->prob, GLP_MAX);
6674 /* adding columns */
6676 glp_add_cols(ats->prob, 2 * c_mechs);
6677 /* adding b_t cols */
6678 for (c=1; c <= c_mechs; c++)
6681 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6682 glp_set_col_name(ats->prob, c, name);
6684 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6685 glp_set_obj_coef(ats->prob, c, 0);
6688 /* adding n_t cols */
6689 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6691 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6692 glp_set_col_name(ats->prob, c, name);
6694 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6695 glp_set_col_kind(ats->prob, c, GLP_IV);
6696 glp_set_obj_coef(ats->prob, c, 0);
6699 /* feasibility constraints */
6700 /* Constraint 1: one address per peer*/
6702 glp_add_rows(ats->prob, c_peers);
6703 for (c=1; c<=c_peers; c++)
6706 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6708 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6710 struct ATS_mechanism *m = peers[c].m_head;
6713 ia[array_index] = row_index;
6714 ja[array_index] = (c_mechs + m->col_index);
6715 ar[array_index] = 1;
6717 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6725 /* Constraint 2: only active mechanism gets bandwidth assigned */
6726 glp_add_rows(ats->prob, c_mechs);
6727 for (c=1; c<=c_mechs; c++)
6729 /* b_t - n_t * M <= 0 */
6731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6733 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6735 ia[array_index] = row_index;
6736 ja[array_index] = mechanisms[c].col_index;
6737 ar[array_index] = 1;
6739 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6742 ia[array_index] = row_index;
6743 ja[array_index] = c_mechs + mechanisms[c].col_index;
6744 ar[array_index] = -M;
6746 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6752 /* Constraint 3: minimum bandwidth*/
6753 glp_add_rows(ats->prob, c_mechs);
6754 for (c=1; c<=c_mechs; c++)
6756 /* b_t - n_t * b_min <= 0 */
6758 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6760 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6762 ia[array_index] = row_index;
6763 ja[array_index] = mechanisms[c].col_index;
6764 ar[array_index] = 1;
6766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6769 ia[array_index] = row_index;
6770 ja[array_index] = c_mechs + mechanisms[c].col_index;
6771 ar[array_index] = -v_b_min;
6773 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6779 /* Constraint 4: max ressource capacity */
6780 /* V cr: bt * ct_r <= cr_max
6782 glp_add_rows(ats->prob, available_ressources);
6783 double ct_max = VERY_BIG_DOUBLE_VALUE;
6784 double ct_min = 0.0;
6786 stat->begin_cr = array_index;
6788 for (c=0; c<available_ressources; c++)
6790 ct_max = ressources[c].c_max;
6791 ct_min = ressources[c].c_min;
6793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6795 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6797 for (c2=1; c2<=c_mechs; c2++)
6800 ia[array_index] = row_index;
6801 ja[array_index] = c2;
6802 value = mechanisms[c2].addr->ressources[c].c;
6803 ar[array_index] = value;
6805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6811 stat->end_cr = array_index--;
6813 /* Constraint 5: min number of connections*/
6814 glp_add_rows(ats->prob, 1);
6815 for (c=1; c<=c_mechs; c++)
6817 // b_t - n_t * b_min >= 0
6819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6821 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6823 ia[array_index] = row_index;
6824 ja[array_index] = c_mechs + mechanisms[c].col_index;
6825 ar[array_index] = 1;
6827 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6833 // optimisation constraints
6837 // Constraint 6: optimize for diversity
6839 col_d = glp_add_cols(ats->prob, 1);
6840 stat->col_d = col_d;
6841 //GNUNET_assert (col_d == (2*c_mechs) + 1);
6842 glp_set_col_name(ats->prob, col_d, "d");
6843 glp_set_obj_coef(ats->prob, col_d, D);
6844 glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
6845 glp_add_rows(ats->prob, 1);
6847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6849 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6850 for (c=1; c<=c_mechs; c++)
6852 // b_t - n_t * b_min >= 0
6853 ia[array_index] = row_index;
6854 ja[array_index] = c_mechs + mechanisms[c].col_index;
6855 ar[array_index] = 1;
6857 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6861 ia[array_index] = row_index;
6862 ja[array_index] = col_d;
6863 ar[array_index] = -1;
6865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6871 // Constraint 7: optimize for quality
6873 col_qm = glp_add_cols(ats->prob, c_q_metrics);
6874 stat->col_qm = col_qm;
6875 //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
6876 for (c=0; c< c_q_metrics; c++)
6878 GNUNET_asprintf(&name, "Q_%s",qm[c].name);
6879 glp_set_col_name(ats->prob, col_qm + c, name);
6880 glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
6882 glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
6884 glp_add_rows(ats->prob, available_quality_metrics);
6885 stat->begin_qm = row_index;
6886 for (c=1; c <= c_q_metrics; c++)
6889 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6892 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6893 for (c2=1; c2<=c_mechs; c2++)
6896 ia[array_index] = row_index;
6897 ja[array_index] = c2;
6898 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6900 double v0 = 0, v1 = 0, v2 = 0;
6901 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6902 if (v1 < 1) v0 = 0.1;
6903 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6904 if (v1 < 1) v0 = 0.1;
6905 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6906 if (v1 < 1) v0 = 0.1;
6907 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6910 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6912 double v0 = 0, v1 = 0, v2 = 0;
6913 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6915 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6917 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6919 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6921 value = (double) 10 / value;
6925 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6927 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]);
6932 ia[array_index] = row_index;
6933 ja[array_index] = col_qm + c - 1;
6934 ar[array_index] = -1;
6936 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6941 stat->end_qm = row_index-1;
6943 // Constraint 8: optimize bandwidth utility
6945 col_u = glp_add_cols(ats->prob, 1);
6946 stat->col_u = col_u;
6947 //GNUNET_assert (col_u == (2*c_mechs) + 2);
6948 glp_set_col_name(ats->prob, col_u, "u");
6949 glp_set_obj_coef(ats->prob, col_u, U);
6950 glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
6951 glp_add_rows(ats->prob, 1);
6953 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6955 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6956 for (c=1; c<=c_mechs; c++)
6958 ia[array_index] = row_index;
6959 ja[array_index] = c;
6960 ar[array_index] = mechanisms[c].peer->f;
6962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6966 ia[array_index] = row_index;
6967 ja[array_index] = col_u;
6968 ar[array_index] = -1;
6970 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6976 // Constraint 9: optimize relativity
6978 col_r = glp_add_cols(ats->prob, 1);
6979 stat->col_r = col_r;
6980 //GNUNET_assert (col_r == (2*c_mechs) + 3);
6981 glp_set_col_name(ats->prob, col_r, "r");
6982 glp_set_obj_coef(ats->prob, col_r, R);
6983 glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
6984 glp_add_rows(ats->prob, c_peers);
6985 for (c=1; c<=c_peers; c++)
6987 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6989 struct ATS_mechanism *m = peers[c].m_head;
6992 ia[array_index] = row_index;
6993 ja[array_index] = m->col_index;
6994 ar[array_index] = 1 / mechanisms[c].peer->f;
6996 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7001 ia[array_index] = row_index;
7002 ja[array_index] = col_r;
7003 ar[array_index] = -1;
7005 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7012 /* Loading the matrix */
7013 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
7015 stat->c_mechs = c_mechs;
7016 stat->c_peers = c_peers;
7018 stat->valid = GNUNET_YES;
7030 void ats_notify_ats_data (
7031 const struct GNUNET_PeerIdentity *peer,
7032 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
7035 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
7037 ats_calculate_bandwidth_distribution();
7039 #endif //END: HAVE_LIBGLPK
7042 ats_calculate_bandwidth_distribution ()
7046 struct GNUNET_TIME_Absolute start;
7047 struct GNUNET_TIME_Relative creation;
7048 struct GNUNET_TIME_Relative solving;
7049 char *text = "unmodified";
7051 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (ats->last, GNUNET_TIME_absolute_get());
7052 if (delta.rel_value < ats->min_delta.rel_value)
7055 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
7061 if (INT_MAX < ats->max_exec_duration.rel_value)
7064 dur = (int) ats->max_exec_duration.rel_value;
7066 ats->stat.simplex_rerun_required = GNUNET_NO;
7067 start = GNUNET_TIME_absolute_get();
7068 if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL) || (ats->stat.valid == GNUNET_NO))
7071 ats->stat.recreate_problem = GNUNET_YES;
7072 ats_delete_problem ();
7073 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
7075 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... new problem: %i peer, %i mechs\n", ats->stat.c_peers, ats->stat.c_mechs);
7079 else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_resources == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
7081 text = "modified resources";
7082 ats_update_problem_cr();
7084 else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_quality == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
7086 text = "modified quality";
7087 ats_update_problem_qm();
7088 //ats_update_problem_qm_TEST ();
7092 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
7095 creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
7096 start = GNUNET_TIME_absolute_get();
7098 ats->stat.solution = GLP_UNDEF;
7099 if (ats->stat.valid == GNUNET_YES)
7101 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
7103 solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
7105 if (ats->stat.valid == GNUNET_YES)
7107 int msg_type = GNUNET_ERROR_TYPE_DEBUG;
7109 msg_type = GNUNET_ERROR_TYPE_ERROR;
7111 GNUNET_log (msg_type, "MLP %s: creation time: %llu, execution time: %llu, %i mechanisms, simplex rerun: %s, solution %s\n",
7112 text, creation.rel_value, solving.rel_value,
7114 (ats->stat.simplex_rerun_required == GNUNET_NO) ? "NO" : "YES", (ats->stat.solution == 5) ? "OPTIMAL" : "INVALID");
7115 ats->successful_executions ++;
7116 GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
7118 if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL))
7119 GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
7120 else if ((ats->stat.modified_resources == GNUNET_YES) &&
7121 (ats->stat.modified_quality == GNUNET_NO))
7122 GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
7123 else if ((ats->stat.modified_resources == GNUNET_NO) &&
7124 (ats->stat.modified_quality == GNUNET_YES) &&
7125 (ats->stat.simplex_rerun_required == GNUNET_NO))
7126 GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
7127 else if ((ats->stat.modified_resources == GNUNET_YES) &&
7128 (ats->stat.modified_quality == GNUNET_YES) &&
7129 (ats->stat.simplex_rerun_required == GNUNET_NO))
7130 GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
7131 else if (ats->stat.simplex_rerun_required == GNUNET_NO)
7132 GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
7136 if (ats->stat.c_peers != 0)
7138 ats->invalid_executions ++;
7139 GNUNET_STATISTICS_set (stats, "# ATS invalid executions", ats->invalid_executions, GNUNET_NO);
7143 GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
7147 GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
7148 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
7149 GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
7150 GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
7151 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
7153 if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
7156 if (ats->dump_overwrite == GNUNET_NO)
7158 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.mlp",
7159 ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
7160 glp_write_lp (ats->prob, NULL, filename);
7164 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",
7165 ats->stat.c_peers, ats->stat.c_mechs );
7166 glp_write_lp (ats->prob, NULL, filename);
7168 GNUNET_free (filename);
7170 if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
7173 if (ats->dump_overwrite == GNUNET_NO)
7175 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.sol",
7176 ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
7177 glp_print_sol (ats->prob, filename);
7181 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.sol",
7182 ats->stat.c_peers, ats->stat.c_mechs);
7183 glp_print_sol (ats->prob, filename);
7185 GNUNET_free (filename);
7188 ats->last = GNUNET_TIME_absolute_get();
7189 ats->stat.recreate_problem = GNUNET_NO;
7190 ats->stat.modified_resources = GNUNET_NO;
7191 ats->stat.modified_quality = GNUNET_NO;
7196 ats_schedule_calculation (void *cls,
7197 const struct GNUNET_SCHEDULER_TaskContext *tc)
7199 struct ATS_info *ats = (struct ATS_info *) cls;
7200 if (ats==NULL) return;
7202 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7203 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
7207 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
7210 ats_calculate_bandwidth_distribution (ats);
7212 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_interval,
7213 &ats_schedule_calculation, ats);
7219 unsigned long long value;
7222 ats = GNUNET_malloc(sizeof (struct ATS_info));
7224 ats->min_delta = ATS_MIN_INTERVAL;
7225 ats->exec_interval = ATS_EXEC_INTERVAL;
7226 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
7227 ats->max_iterations = ATS_MAX_ITERATIONS;
7228 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "GLPK not installed, ATS not active\n");
7238 ats->v_b_min = 64000;
7240 ats->dump_min_peers = 1;
7241 ats->dump_min_addr = 1;
7242 ats->dump_overwrite = GNUNET_NO;
7243 ats->mechanisms = NULL;
7245 ats->successful_executions = 0;
7246 ats->invalid_executions = 0;
7252 /* loading cost ressources */
7253 for (c=0; c<available_ressources; c++)
7255 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
7256 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7258 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7261 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7263 ressources[c].c_max = value;
7266 GNUNET_free (section);
7267 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
7268 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7270 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7275 ressources[c].c_min = value;
7278 GNUNET_free (section);
7281 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
7282 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
7284 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
7285 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
7286 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7287 ats->dump_overwrite = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_OVERWRITE");
7288 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
7290 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_PEERS", &value);
7291 ats->dump_min_peers= value;
7293 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_ADDRS"))
7295 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_ADDRS", &value);
7296 ats->dump_min_addr= value;
7298 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7300 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_OVERWRITE", &value);
7301 ats->min_delta.rel_value = value;
7304 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7306 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7307 ats->min_delta.rel_value = value;
7310 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_EXEC_INTERVAL"))
7312 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_EXEC_INTERVAL", &value);
7313 ats->exec_interval.rel_value = value;
7315 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7317 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7318 ats->min_delta.rel_value = value;
7321 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
7325 static void ats_shutdown ()
7328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
7330 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
7331 GNUNET_SCHEDULER_cancel(ats->ats_task);
7332 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7335 ats_delete_problem ();
7342 void ats_notify_peer_connect (
7343 const struct GNUNET_PeerIdentity *peer,
7344 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
7347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
7349 //update_addr_ats();
7350 ats->stat.recreate_problem = GNUNET_YES;
7351 ats_calculate_bandwidth_distribution(ats);
7354 void ats_notify_peer_disconnect (
7355 const struct GNUNET_PeerIdentity *peer)
7358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
7360 ats->stat.recreate_problem = GNUNET_YES;
7361 ats_calculate_bandwidth_distribution (ats);
7364 struct ForeignAddressList * ats_get_preferred_address (
7365 struct NeighbourList *n)
7368 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
7370 struct ReadyList *next = n->plugins;
7371 while (next != NULL)
7374 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
7378 return find_ready_address(n);
7382 * Initiate transport service.
7384 * @param cls closure
7385 * @param server the initialized server
7386 * @param c configuration to use
7390 struct GNUNET_SERVER_Handle *server,
7391 const struct GNUNET_CONFIGURATION_Handle *c)
7393 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
7394 {&handle_start, NULL,
7395 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
7396 {&handle_hello, NULL,
7397 GNUNET_MESSAGE_TYPE_HELLO, 0},
7398 {&handle_send, NULL,
7399 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
7400 {&handle_request_connect, NULL,
7401 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
7402 {&handle_set_quota, NULL,
7403 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
7404 {&handle_address_lookup, NULL,
7405 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
7407 {&handle_blacklist_init, NULL,
7408 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
7409 {&handle_blacklist_reply, NULL,
7410 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
7416 unsigned long long tneigh;
7420 stats = GNUNET_STATISTICS_create ("transport", cfg);
7421 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
7422 /* parse configuration */
7424 GNUNET_CONFIGURATION_get_value_number (c,
7429 GNUNET_CONFIGURATION_get_value_filename (c,
7431 "HOSTKEY", &keyfile)))
7433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7435 ("Transport service is lacking key configuration settings. Exiting.\n"));
7436 GNUNET_SCHEDULER_shutdown ();
7439 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7442 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7443 validation_map = NULL;
7447 max_connect_per_transport = (uint32_t) tneigh;
7448 peerinfo = GNUNET_PEERINFO_connect (cfg);
7449 if (peerinfo == NULL)
7451 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7452 _("Could not access PEERINFO service. Exiting.\n"));
7453 GNUNET_SCHEDULER_shutdown ();
7456 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7459 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7460 validation_map = NULL;
7461 GNUNET_free (keyfile);
7464 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
7465 GNUNET_free (keyfile);
7466 if (my_private_key == NULL)
7468 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7470 ("Transport service could not access hostkey. Exiting.\n"));
7471 GNUNET_SCHEDULER_shutdown ();
7474 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7477 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7478 validation_map = NULL;
7481 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
7482 GNUNET_CRYPTO_hash (&my_public_key,
7483 sizeof (my_public_key), &my_identity.hashPubKey);
7484 /* setup notification */
7485 GNUNET_SERVER_disconnect_notify (server,
7486 &client_disconnect_notification, NULL);
7487 /* load plugins... */
7490 GNUNET_CONFIGURATION_get_value_string (c,
7491 "TRANSPORT", "PLUGINS", &plugs))
7493 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7494 _("Starting transport plugins `%s'\n"), plugs);
7495 pos = strtok (plugs, " ");
7498 start_transport (server, pos);
7500 pos = strtok (NULL, " ");
7502 GNUNET_free (plugs);
7504 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
7505 &shutdown_task, NULL);
7512 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7514 /* If we have a blacklist file, read from it */
7515 read_blacklist_file(cfg);
7516 /* process client requests */
7517 GNUNET_SERVER_add_handlers (server, handlers);
7522 * The main function for the transport service.
7524 * @param argc number of arguments from the command line
7525 * @param argv command line arguments
7526 * @return 0 ok, 1 on error
7529 main (int argc, char *const *argv)
7531 a2s (NULL, NULL, 0); /* make compiler happy */
7532 return (GNUNET_OK ==
7533 GNUNET_SERVICE_run (argc,
7536 GNUNET_SERVICE_OPTION_NONE,
7537 &run, NULL)) ? 0 : 1;
7540 /* end of gnunet-service-transport.c */