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 * is problem currently valid and can it be solved
898 * Number of transport mechanisms in the problem
903 * Number of transport mechanisms in the problem
908 * row index where quality related rows start
913 * row index where quality related rows end
918 * row index where ressource cost related rows start
923 * row index where ressource cost related rows end
934 struct ATS_ressource_entry
936 /* index in ressources array */
938 /* depending ATSi parameter to calculcate limits */
947 /* index in ressources array */
949 /* depending ATSi parameter to calculcate limits */
951 /* cfg option to load limits */
958 /* cofficients for the specific plugins */
968 static struct ATS_ressource ressources[] =
970 /* FIXME: the coefficients for the specific plugins */
971 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
972 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
973 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
975 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
976 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
977 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
978 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
981 static int available_ressources = 3;
989 * Time of last execution
991 struct GNUNET_TIME_Absolute last;
993 * Minimum intervall between two executions
995 struct GNUNET_TIME_Relative min_delta;
997 * Regular intervall when execution is triggered
999 struct GNUNET_TIME_Relative exec_intervall;
1001 * Maximum execution time per calculation
1003 struct GNUNET_TIME_Relative max_exec_duration;
1007 * GLPK (MLP) problem object
1013 * task to recalculate the bandwidth assignment
1015 GNUNET_SCHEDULER_TaskIdentifier ats_task;
1018 * Current state of the GLPK problem
1020 struct ATS_stat stat;
1023 * mechanisms used in current problem
1024 * needed for problem modification
1026 struct ATS_mechanism * mechanisms;
1029 * peers used in current problem
1030 * needed for problem modification
1032 struct ATS_peer * peers;
1036 * Use built-in MLP presolver or simplex
1038 int builtin_mlp_presolver;
1041 * Maximum number of LP iterations per calculation
1046 * Dump problem to a file?
1051 * Dump solution to a file
1056 * Ressource costs or quality metrics changed
1057 * update problem before solving
1059 int modified_resources;
1062 * Ressource costs or quality metrics changed, update matrix
1063 * update problem before solving
1065 int modified_quality;
1068 * Peers have connected or disconnected
1069 * problem has to be recreated
1089 * Minimum bandwidth per peer
1094 * Minimum number of connections per peer
1101 * Our HELLO message.
1103 static struct GNUNET_HELLO_Message *our_hello;
1108 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1113 static struct GNUNET_PeerIdentity my_identity;
1118 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1121 * Our configuration.
1123 const struct GNUNET_CONFIGURATION_Handle *cfg;
1126 * Linked list of all clients to this service.
1128 static struct TransportClient *clients;
1131 * All loaded plugins.
1133 static struct TransportPlugin *plugins;
1136 * Handle to peerinfo service.
1138 static struct GNUNET_PEERINFO_Handle *peerinfo;
1141 * All known neighbours and their HELLOs.
1143 static struct NeighbourList *neighbours;
1146 * Number of neighbours we'd like to have.
1148 static uint32_t max_connect_per_transport;
1151 * Head of linked list.
1153 static struct CheckHelloValidatedContext *chvc_head;
1156 * Tail of linked list.
1158 static struct CheckHelloValidatedContext *chvc_tail;
1161 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1162 * of the given peer that we are currently validating).
1164 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1167 * Handle for reporting statistics.
1169 static struct GNUNET_STATISTICS_Handle *stats;
1172 * Handle for ats information
1174 static struct ATS_info *ats;
1176 struct ATS_quality_entry
1184 static struct ATS_quality_metric qm[] =
1186 {1, 1028, "QUALITY_NET_DISTANCE"},
1187 {2, 1034, "QUALITY_NET_DELAY"},
1189 static int available_quality_metrics = 2;
1193 * The peer specified by the given neighbour has timed-out or a plugin
1194 * has disconnected. We may either need to do nothing (other plugins
1195 * still up), or trigger a full disconnect and clean up. This
1196 * function updates our state and do the necessary notifications.
1197 * Also notifies our clients that the neighbour is now officially
1200 * @param n the neighbour list entry for the peer
1201 * @param check should we just check if all plugins
1202 * disconnected or must we ask all plugins to
1205 static void disconnect_neighbour (struct NeighbourList *n, int check);
1208 * Check the ready list for the given neighbour and if a plugin is
1209 * ready for transmission (and if we have a message), do so!
1211 * @param nexi target peer for which to transmit
1213 static void try_transmission_to_peer (struct NeighbourList *n);
1215 static void ats_shutdown ( );
1217 static void ats_notify_peer_connect (
1218 const struct GNUNET_PeerIdentity *peer,
1219 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
1221 static void ats_notify_peer_disconnect (
1222 const struct GNUNET_PeerIdentity *peer);
1225 static void ats_notify_ats_data (
1226 const struct GNUNET_PeerIdentity *peer,
1227 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1230 struct ForeignAddressList * ats_get_preferred_address (
1231 struct NeighbourList *n);
1234 ats_calculate_bandwidth_distribution ();
1237 * Find an entry in the neighbour list for a particular peer.
1239 * @return NULL if not found.
1241 static struct NeighbourList *
1242 find_neighbour (const struct GNUNET_PeerIdentity *key)
1244 struct NeighbourList *head = neighbours;
1246 while ((head != NULL) &&
1247 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1252 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1255 int set = GNUNET_NO;
1256 for (c=0; c<available_quality_metrics; c++)
1258 if (ats_index == qm[c].atis_index)
1260 fal->quality[c].values[0] = fal->quality[c].values[1];
1261 fal->quality[c].values[1] = fal->quality[c].values[2];
1262 fal->quality[c].values[2] = value;
1264 ats->modified_quality = GNUNET_YES;
1267 if (set == GNUNET_NO)
1269 for (c=0; c<available_ressources; c++)
1271 if (ats_index == ressources[c].atis_index)
1273 fal->ressources[c].c = value;
1275 ats->modified_resources = GNUNET_YES;
1283 static int update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1287 for (c1=0; c1<ats_count; c1++)
1289 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1295 * Find an entry in the transport list for a particular transport.
1297 * @return NULL if not found.
1299 static struct TransportPlugin *
1300 find_transport (const char *short_name)
1302 struct TransportPlugin *head = plugins;
1303 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1309 * Is a particular peer blacklisted for a particular transport?
1311 * @param peer the peer to check for
1312 * @param plugin the plugin used to connect to the peer
1314 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1317 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1320 if (plugin->blacklist != NULL)
1322 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Peer `%s:%s' is blacklisted!\n",
1327 plugin->short_name, GNUNET_i2s (peer));
1330 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1340 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1342 struct TransportPlugin *plugin;
1344 plugin = find_transport(transport_name);
1345 if (plugin == NULL) /* Nothing to do */
1347 if (plugin->blacklist == NULL)
1348 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1349 GNUNET_assert(plugin->blacklist != NULL);
1350 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1352 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1357 * Read the blacklist file, containing transport:peer entries.
1358 * Provided the transport is loaded, set up hashmap with these
1359 * entries to blacklist peers by transport.
1363 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1370 struct GNUNET_PeerIdentity pid;
1372 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1373 unsigned int entries_found;
1374 char *transport_name;
1377 GNUNET_CONFIGURATION_get_value_filename (cfg,
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1384 "Option `%s' in section `%s' not specified!\n",
1390 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1391 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1392 | GNUNET_DISK_PERM_USER_WRITE);
1393 if (0 != STAT (fn, &frstat))
1395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1396 _("Could not read blacklist file `%s'\n"), fn);
1400 if (frstat.st_size == 0)
1403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1404 _("Blacklist file `%s' is empty.\n"),
1410 /* FIXME: use mmap */
1411 data = GNUNET_malloc_large (frstat.st_size);
1412 GNUNET_assert(data != NULL);
1413 if (frstat.st_size !=
1414 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1417 _("Failed to read blacklist from `%s'\n"), fn);
1424 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1426 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1427 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1430 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1433 if (colon_pos >= frstat.st_size)
1435 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1436 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1437 (unsigned long long) colon_pos);
1443 if (isspace( (unsigned char) data[colon_pos]))
1445 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1446 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1447 (unsigned long long) colon_pos);
1449 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1453 tsize = colon_pos - pos;
1454 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1457 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1458 (unsigned long long) colon_pos);
1467 transport_name = GNUNET_malloc(tsize + 1);
1468 memcpy(transport_name, &data[pos], tsize);
1469 pos = colon_pos + 1;
1471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1472 "Read transport name %s in blacklist file.\n",
1475 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1476 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1478 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1479 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1480 (unsigned long long) pos);
1482 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1484 GNUNET_free_non_null(transport_name);
1487 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1488 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1490 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1491 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1492 (unsigned long long) pos,
1497 if (0 != memcmp (&pid,
1499 sizeof (struct GNUNET_PeerIdentity)))
1502 add_peer_to_blacklist (&pid,
1507 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1508 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1512 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1513 GNUNET_free_non_null(transport_name);
1514 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1517 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1524 * Function called to notify a client about the socket being ready to
1525 * queue more data. "buf" will be NULL and "size" zero if the socket
1526 * was closed for writing in the meantime.
1528 * @param cls closure
1529 * @param size number of bytes available in buf
1530 * @param buf where the callee should write the message
1531 * @return number of bytes written to buf
1534 transmit_to_client_callback (void *cls, size_t size, void *buf)
1536 struct TransportClient *client = cls;
1537 struct ClientMessageQueueEntry *q;
1540 const struct GNUNET_MessageHeader *msg;
1547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1548 "Transmission to client failed, closing connection.\n");
1550 /* fatal error with client, free message queue! */
1551 while (NULL != (q = client->message_queue_head))
1553 GNUNET_STATISTICS_update (stats,
1554 gettext_noop ("# bytes discarded (could not transmit to client)"),
1555 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1557 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1558 client->message_queue_tail,
1562 client->message_count = 0;
1567 while (NULL != (q = client->message_queue_head))
1569 msg = (const struct GNUNET_MessageHeader *) &q[1];
1570 msize = ntohs (msg->size);
1571 if (msize + tsize > size)
1574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575 "Transmitting message of type %u to client.\n",
1578 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1579 client->message_queue_tail,
1581 memcpy (&cbuf[tsize], msg, msize);
1584 client->message_count--;
1588 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1589 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1591 GNUNET_TIME_UNIT_FOREVER_REL,
1592 &transmit_to_client_callback,
1594 GNUNET_assert (client->th != NULL);
1601 * Convert an address to a string.
1603 * @param plugin name of the plugin responsible for the address
1604 * @param addr binary address
1605 * @param addr_len number of bytes in addr
1606 * @return NULL on error, otherwise address string
1609 a2s (const char *plugin,
1613 struct TransportPlugin *p;
1617 p = find_transport (plugin);
1620 return p->api->address_to_string (p->api->cls,
1627 * Mark the given FAL entry as 'connected' (and hence preferred for
1628 * sending); also mark all others for the same peer as 'not connected'
1629 * (since only one can be preferred).
1631 * @param fal address to set to 'connected'
1634 mark_address_connected (struct ForeignAddressList *fal)
1636 struct ForeignAddressList *pos;
1639 GNUNET_assert (GNUNET_YES == fal->validated);
1640 if (fal->connected == GNUNET_YES)
1641 return; /* nothing to do */
1643 pos = fal->ready_list->addresses;
1646 if (GNUNET_YES == pos->connected)
1649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1650 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1651 a2s (pos->ready_list->plugin->short_name,
1655 GNUNET_break (cnt == GNUNET_YES);
1657 pos->connected = GNUNET_NO;
1658 GNUNET_STATISTICS_update (stats,
1659 gettext_noop ("# connected addresses"),
1665 fal->connected = GNUNET_YES;
1666 if (GNUNET_YES == cnt)
1668 GNUNET_STATISTICS_update (stats,
1669 gettext_noop ("# connected addresses"),
1677 * Send the specified message to the specified client. Since multiple
1678 * messages may be pending for the same client at a time, this code
1679 * makes sure that no message is lost.
1681 * @param client client to transmit the message to
1682 * @param msg the message to send
1683 * @param may_drop can this message be dropped if the
1684 * message queue for this client is getting far too large?
1687 transmit_to_client (struct TransportClient *client,
1688 const struct GNUNET_MessageHeader *msg, int may_drop)
1690 struct ClientMessageQueueEntry *q;
1693 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1695 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1697 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1700 client->message_count,
1702 GNUNET_STATISTICS_update (stats,
1703 gettext_noop ("# messages dropped due to slow client"),
1708 msize = ntohs (msg->size);
1709 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1710 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1711 memcpy (&q[1], msg, msize);
1712 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1713 client->message_queue_tail,
1714 client->message_queue_tail,
1716 client->message_count++;
1717 if (client->th == NULL)
1719 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1721 GNUNET_TIME_UNIT_FOREVER_REL,
1722 &transmit_to_client_callback,
1724 GNUNET_assert (client->th != NULL);
1730 * Transmit a 'SEND_OK' notification to the given client for the
1733 * @param client who to notify
1734 * @param n neighbour to notify about, can be NULL (on failure)
1735 * @param target target of the transmission
1736 * @param result status code for the transmission request
1739 transmit_send_ok (struct TransportClient *client,
1740 struct NeighbourList *n,
1741 const struct GNUNET_PeerIdentity *target,
1744 struct SendOkMessage send_ok_msg;
1746 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1747 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1748 send_ok_msg.success = htonl (result);
1750 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1752 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1753 send_ok_msg.peer = *target;
1754 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1759 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1760 * upon "completion" of a send request. This tells the API
1761 * that it is now legal to send another message to the given
1764 * @param cls closure, identifies the entry on the
1765 * message queue that was transmitted and the
1766 * client responsible for queuing the message
1767 * @param target the peer receiving the message
1768 * @param result GNUNET_OK on success, if the transmission
1769 * failed, we should not tell the client to transmit
1773 transmit_send_continuation (void *cls,
1774 const struct GNUNET_PeerIdentity *target,
1777 struct MessageQueue *mq = cls;
1778 struct NeighbourList *n;
1780 GNUNET_STATISTICS_update (stats,
1781 gettext_noop ("# bytes pending with plugins"),
1782 - (int64_t) mq->message_buf_size,
1784 if (result == GNUNET_OK)
1786 GNUNET_STATISTICS_update (stats,
1787 gettext_noop ("# bytes successfully transmitted by plugins"),
1788 mq->message_buf_size,
1793 GNUNET_STATISTICS_update (stats,
1794 gettext_noop ("# bytes with transmission failure by plugins"),
1795 mq->message_buf_size,
1798 if (mq->specific_address != NULL)
1800 if (result == GNUNET_OK)
1802 mq->specific_address->timeout =
1803 GNUNET_TIME_relative_to_absolute
1804 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1805 if (mq->specific_address->validated == GNUNET_YES)
1806 mark_address_connected (mq->specific_address);
1810 if (mq->specific_address->connected != GNUNET_NO)
1813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1814 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1815 a2s (mq->specific_address->ready_list->plugin->short_name,
1816 mq->specific_address->addr,
1817 mq->specific_address->addrlen));
1819 GNUNET_STATISTICS_update (stats,
1820 gettext_noop ("# connected addresses"),
1823 mq->specific_address->connected = GNUNET_NO;
1826 if (! mq->internal_msg)
1827 mq->specific_address->in_transmit = GNUNET_NO;
1829 n = find_neighbour(&mq->neighbour_id);
1830 if (mq->client != NULL)
1831 transmit_send_ok (mq->client, n, target, result);
1834 try_transmission_to_peer (n);
1839 * Find an address in any of the available transports for
1840 * the given neighbour that would be good for message
1841 * transmission. This is essentially the transport selection
1844 * @param neighbour for whom to select an address
1845 * @return selected address, NULL if we have none
1847 struct ForeignAddressList *
1848 find_ready_address(struct NeighbourList *neighbour)
1850 struct ReadyList *head = neighbour->plugins;
1851 struct ForeignAddressList *addresses;
1852 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1853 struct ForeignAddressList *best_address;
1855 /* Hack to prefer unix domain sockets */
1856 struct ForeignAddressList *unix_address = NULL;
1858 best_address = NULL;
1859 while (head != NULL)
1861 addresses = head->addresses;
1862 while (addresses != NULL)
1864 if ( (addresses->timeout.abs_value < now.abs_value) &&
1865 (addresses->connected == GNUNET_YES) )
1868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1869 "Marking long-time inactive connection to `%4s' as down.\n",
1870 GNUNET_i2s (&neighbour->id));
1872 GNUNET_STATISTICS_update (stats,
1873 gettext_noop ("# connected addresses"),
1876 addresses->connected = GNUNET_NO;
1878 addresses = addresses->next;
1881 addresses = head->addresses;
1882 while (addresses != NULL)
1884 #if DEBUG_TRANSPORT > 1
1885 if (addresses->addr != NULL)
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1888 a2s (head->plugin->short_name,
1890 addresses->addrlen),
1891 GNUNET_i2s (&neighbour->id),
1892 addresses->connected,
1893 addresses->in_transmit,
1894 addresses->validated,
1895 addresses->connect_attempts,
1896 (unsigned long long) addresses->timeout.abs_value,
1897 (unsigned int) addresses->distance);
1899 if (0==strcmp(head->plugin->short_name,"unix"))
1901 if ((unix_address == NULL) || ((unix_address != NULL) &&
1902 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1903 unix_address = addresses;
1905 if ( ( (best_address == NULL) ||
1906 (addresses->connected == GNUNET_YES) ||
1907 (best_address->connected == GNUNET_NO) ) &&
1908 (addresses->in_transmit == GNUNET_NO) &&
1909 ( (best_address == NULL) ||
1910 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1911 best_address = addresses;
1912 /* FIXME: also give lower-latency addresses that are not
1913 connected a chance some times... */
1914 addresses = addresses->next;
1916 if (unix_address != NULL)
1920 if (unix_address != NULL)
1922 best_address = unix_address;
1924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1927 if (best_address != NULL)
1931 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1932 "Best address found (`%s') has latency of %llu ms.\n",
1933 (best_address->addrlen > 0)
1934 ? a2s (best_address->ready_list->plugin->short_name,
1936 best_address->addrlen)
1938 best_address->latency.rel_value);
1943 GNUNET_STATISTICS_update (stats,
1944 gettext_noop ("# transmission attempts failed (no address)"),
1949 return best_address;
1955 * We should re-try transmitting to the given peer,
1956 * hopefully we've learned something in the meantime.
1959 retry_transmission_task (void *cls,
1960 const struct GNUNET_SCHEDULER_TaskContext *tc)
1962 struct NeighbourList *n = cls;
1964 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1965 try_transmission_to_peer (n);
1970 * Check the ready list for the given neighbour and if a plugin is
1971 * ready for transmission (and if we have a message), do so!
1973 * @param neighbour target peer for which to transmit
1976 try_transmission_to_peer (struct NeighbourList *n)
1978 struct ReadyList *rl;
1979 struct MessageQueue *mq;
1980 struct GNUNET_TIME_Relative timeout;
1984 if (n->messages_head == NULL)
1987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1988 "Transmission queue for `%4s' is empty\n",
1989 GNUNET_i2s (&n->id));
1991 return; /* nothing to do */
1994 mq = n->messages_head;
1995 force_address = GNUNET_YES;
1996 if (mq->specific_address == NULL)
1999 mq->specific_address = ats_get_preferred_address(n);
2000 GNUNET_STATISTICS_update (stats,
2001 gettext_noop ("# transport selected peer address freely"),
2004 force_address = GNUNET_NO;
2006 if (mq->specific_address == NULL)
2008 GNUNET_STATISTICS_update (stats,
2009 gettext_noop ("# transport failed to selected peer address"),
2012 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
2013 if (timeout.rel_value == 0)
2016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2017 "No destination address available to transmit message of size %u to peer `%4s'\n",
2018 mq->message_buf_size,
2019 GNUNET_i2s (&mq->neighbour_id));
2021 GNUNET_STATISTICS_update (stats,
2022 gettext_noop ("# bytes in message queue for other peers"),
2023 - (int64_t) mq->message_buf_size,
2025 GNUNET_STATISTICS_update (stats,
2026 gettext_noop ("# bytes discarded (no destination address available)"),
2027 mq->message_buf_size,
2029 if (mq->client != NULL)
2030 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
2031 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2035 return; /* nobody ready */
2037 GNUNET_STATISTICS_update (stats,
2038 gettext_noop ("# message delivery deferred (no address)"),
2041 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2042 GNUNET_SCHEDULER_cancel (n->retry_task);
2043 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
2044 &retry_transmission_task,
2047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2048 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
2049 mq->message_buf_size,
2050 GNUNET_i2s (&mq->neighbour_id),
2053 /* FIXME: might want to trigger peerinfo lookup here
2054 (unless that's already pending...) */
2057 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2060 if (mq->specific_address->connected == GNUNET_NO)
2061 mq->specific_address->connect_attempts++;
2062 rl = mq->specific_address->ready_list;
2063 mq->plugin = rl->plugin;
2064 if (!mq->internal_msg)
2065 mq->specific_address->in_transmit = GNUNET_YES;
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2068 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
2069 mq->message_buf_size,
2070 GNUNET_i2s (&n->id),
2071 (mq->specific_address->addr != NULL)
2072 ? a2s (mq->plugin->short_name,
2073 mq->specific_address->addr,
2074 mq->specific_address->addrlen)
2076 rl->plugin->short_name);
2078 GNUNET_STATISTICS_update (stats,
2079 gettext_noop ("# bytes in message queue for other peers"),
2080 - (int64_t) mq->message_buf_size,
2082 GNUNET_STATISTICS_update (stats,
2083 gettext_noop ("# bytes pending with plugins"),
2084 mq->message_buf_size,
2086 ret = rl->plugin->api->send (rl->plugin->api->cls,
2089 mq->message_buf_size,
2091 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2092 mq->specific_address->session,
2093 mq->specific_address->addr,
2094 mq->specific_address->addrlen,
2096 &transmit_send_continuation, mq);
2099 /* failure, but 'send' would not call continuation in this case,
2100 so we need to do it here! */
2101 transmit_send_continuation (mq,
2109 * Send the specified message to the specified peer.
2111 * @param client source of the transmission request (can be NULL)
2112 * @param peer_address ForeignAddressList where we should send this message
2113 * @param priority how important is the message
2114 * @param timeout how long do we have to transmit?
2115 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
2116 * @param message_buf_size total size of all messages in message_buf
2117 * @param is_internal is this an internal message; these are pre-pended and
2118 * also do not count for plugins being "ready" to transmit
2119 * @param neighbour handle to the neighbour for transmission
2122 transmit_to_peer (struct TransportClient *client,
2123 struct ForeignAddressList *peer_address,
2124 unsigned int priority,
2125 struct GNUNET_TIME_Relative timeout,
2126 const char *message_buf,
2127 size_t message_buf_size,
2128 int is_internal, struct NeighbourList *neighbour)
2130 struct MessageQueue *mq;
2135 /* check for duplicate submission */
2136 mq = neighbour->messages_head;
2139 if (mq->client == client)
2141 /* client transmitted to same peer twice
2142 before getting SEND_OK! */
2150 GNUNET_STATISTICS_update (stats,
2151 gettext_noop ("# bytes in message queue for other peers"),
2154 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2155 mq->specific_address = peer_address;
2156 mq->client = client;
2157 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2158 memcpy (&mq[1], message_buf, message_buf_size);
2159 mq->message_buf = (const char*) &mq[1];
2160 mq->message_buf_size = message_buf_size;
2161 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2162 mq->internal_msg = is_internal;
2163 mq->priority = priority;
2164 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2166 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2167 neighbour->messages_tail,
2170 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2171 neighbour->messages_tail,
2172 neighbour->messages_tail,
2174 try_transmission_to_peer (neighbour);
2181 struct GeneratorContext
2183 struct TransportPlugin *plug_pos;
2184 struct OwnAddressList *addr_pos;
2185 struct GNUNET_TIME_Absolute expiration;
2193 address_generator (void *cls, size_t max, void *buf)
2195 struct GeneratorContext *gc = cls;
2198 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2200 gc->plug_pos = gc->plug_pos->next;
2201 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2203 if (NULL == gc->plug_pos)
2208 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2211 gc->addr_pos->addrlen, buf, max);
2212 gc->addr_pos = gc->addr_pos->next;
2218 * Construct our HELLO message from all of the addresses of
2219 * all of the transports.
2224 struct GNUNET_HELLO_Message *hello;
2225 struct TransportClient *cpos;
2226 struct NeighbourList *npos;
2227 struct GeneratorContext gc;
2229 gc.plug_pos = plugins;
2230 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2231 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2232 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2235 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2237 GNUNET_STATISTICS_update (stats,
2238 gettext_noop ("# refreshed my HELLO"),
2242 while (cpos != NULL)
2244 transmit_to_client (cpos,
2245 (const struct GNUNET_MessageHeader *) hello,
2250 GNUNET_free_non_null (our_hello);
2252 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2254 while (npos != NULL)
2257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2258 "Transmitting updated `%s' to neighbour `%4s'\n",
2259 "HELLO", GNUNET_i2s (&npos->id));
2261 GNUNET_STATISTICS_update (stats,
2262 gettext_noop ("# transmitted my HELLO to other peers"),
2265 transmit_to_peer (NULL, NULL, 0,
2266 HELLO_ADDRESS_EXPIRATION,
2267 (const char *) our_hello,
2268 GNUNET_HELLO_size(our_hello),
2276 * Task used to clean up expired addresses for a plugin.
2278 * @param cls closure
2282 expire_address_task (void *cls,
2283 const struct GNUNET_SCHEDULER_TaskContext *tc);
2287 * Update the list of addresses for this plugin,
2288 * expiring those that are past their expiration date.
2290 * @param plugin addresses of which plugin should be recomputed?
2291 * @param fresh set to GNUNET_YES if a new address was added
2292 * and we need to regenerate the HELLO even if nobody
2296 update_addresses (struct TransportPlugin *plugin,
2299 static struct GNUNET_TIME_Absolute last_update;
2300 struct GNUNET_TIME_Relative min_remaining;
2301 struct GNUNET_TIME_Relative remaining;
2302 struct GNUNET_TIME_Absolute now;
2303 struct OwnAddressList *pos;
2304 struct OwnAddressList *prev;
2305 struct OwnAddressList *next;
2308 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2309 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2310 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2311 now = GNUNET_TIME_absolute_get ();
2312 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2313 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2315 pos = plugin->addresses;
2319 if (pos->expires.abs_value < now.abs_value)
2321 expired = GNUNET_YES;
2323 plugin->addresses = pos->next;
2325 prev->next = pos->next;
2330 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2331 if (remaining.rel_value < min_remaining.rel_value)
2332 min_remaining = remaining;
2338 if (expired || fresh)
2343 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2344 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2346 plugin->address_update_task
2347 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2348 &expire_address_task, plugin);
2353 * Task used to clean up expired addresses for a plugin.
2355 * @param cls closure
2359 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2361 struct TransportPlugin *plugin = cls;
2363 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2364 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2365 update_addresses (plugin, GNUNET_NO);
2370 * Iterator over hash map entries that NULLs the session of validation
2371 * entries that match the given session.
2373 * @param cls closure (the 'struct Session*' to match against)
2374 * @param key current key code (peer ID, not used)
2375 * @param value value in the hash map ('struct ValidationEntry*')
2376 * @return GNUNET_YES (we should continue to iterate)
2379 remove_session_validations (void *cls,
2380 const GNUNET_HashCode * key,
2383 struct Session *session = cls;
2384 struct ValidationEntry *ve = value;
2386 if (session == ve->session)
2393 * We've been disconnected from the other peer (for some
2394 * connection-oriented transport). Either quickly
2395 * re-establish the connection or signal the disconnect
2398 * Only signal CORE level disconnect if ALL addresses
2399 * for the peer are exhausted.
2401 * @param p overall plugin context
2402 * @param nl neighbour that was disconnected
2405 try_fast_reconnect (struct TransportPlugin *p,
2406 struct NeighbourList *nl)
2408 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2409 /* Note: the idea here is to hide problems with transports (or
2410 switching between plugins) from the core to eliminate the need to
2411 re-negotiate session keys and the like; OTOH, we should tell core
2412 quickly (much faster than timeout) `if a connection was lost and
2413 could not be re-established (i.e. other peer went down or is
2414 unable / refuses to communicate);
2416 So we should consider:
2417 1) ideally: our own willingness / need to connect
2418 2) prior failures to connect to this peer (by plugin)
2419 3) ideally: reasons why other peer terminated (as far as knowable)
2421 Most importantly, it must be POSSIBLE for another peer to terminate
2422 a connection for a while (without us instantly re-establishing it).
2423 Similarly, if another peer is gone we should quickly notify CORE.
2424 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2425 on the other end), we should reconnect in such a way that BOTH CORE
2426 services never even notice.
2427 Furthermore, the same mechanism (or small variation) could be used
2428 to switch to a better-performing plugin (ATS).
2430 Finally, this needs to be tested throughly... */
2433 * GNUNET_NO in the call below makes transport disconnect the peer,
2434 * even if only a single address (out of say, six) went away. This
2435 * function must be careful to ONLY disconnect if the peer is gone,
2436 * not just a specifi address.
2438 * More specifically, half the places it was used had it WRONG.
2441 /* No reconnect, signal disconnect instead! */
2442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2443 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2444 "try_fast_reconnect");
2445 disconnect_neighbour (nl, GNUNET_YES);
2450 * Function that will be called whenever the plugin internally
2451 * cleans up a session pointer and hence the service needs to
2452 * discard all of those sessions as well. Plugins that do not
2453 * use sessions can simply omit calling this function and always
2454 * use NULL wherever a session pointer is needed.
2456 * @param cls closure
2457 * @param peer which peer was the session for
2458 * @param session which session is being destoyed
2461 plugin_env_session_end (void *cls,
2462 const struct GNUNET_PeerIdentity *peer,
2463 struct Session *session)
2465 struct TransportPlugin *p = cls;
2466 struct NeighbourList *nl;
2467 struct ReadyList *rl;
2468 struct ForeignAddressList *pos;
2469 struct ForeignAddressList *prev;
2471 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2472 &remove_session_validations,
2474 nl = find_neighbour (peer);
2476 return; /* was never marked as connected */
2480 if (rl->plugin == p)
2485 return; /* was never marked as connected */
2487 pos = rl->addresses;
2488 while ( (pos != NULL) &&
2489 (pos->session != session) )
2495 return; /* was never marked as connected */
2496 pos->session = NULL;
2497 if (pos->addrlen != 0)
2499 if (nl->received_pong != GNUNET_NO)
2500 try_fast_reconnect (p, nl);
2503 /* was inbound connection, free 'pos' */
2505 rl->addresses = pos->next;
2507 prev->next = pos->next;
2508 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2510 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2511 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2514 if (nl->received_pong == GNUNET_NO)
2515 return; /* nothing to do, never connected... */
2516 /* check if we have any validated addresses left */
2517 pos = rl->addresses;
2522 try_fast_reconnect (p, nl);
2527 /* no valid addresses left, signal disconnect! */
2529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2530 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2531 "plugin_env_session_end");
2532 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2533 * it means there aren't any left for this PLUGIN/PEER combination! So
2534 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2535 * when it isn't necessary. Using GNUNET_YES at least checks to see
2536 * if there are any addresses that work first, so as not to overdo it.
2539 disconnect_neighbour (nl, GNUNET_YES);
2544 * Function that must be called by each plugin to notify the
2545 * transport service about the addresses under which the transport
2546 * provided by the plugin can be reached.
2548 * @param cls closure
2549 * @param name name of the transport that generated the address
2550 * @param addr one of the addresses of the host, NULL for the last address
2551 * the specific address format depends on the transport
2552 * @param addrlen length of the address
2553 * @param expires when should this address automatically expire?
2556 plugin_env_notify_address (void *cls,
2560 struct GNUNET_TIME_Relative expires)
2562 struct TransportPlugin *p = cls;
2563 struct OwnAddressList *al;
2564 struct GNUNET_TIME_Absolute abex;
2566 GNUNET_assert (addr != NULL);
2567 abex = GNUNET_TIME_relative_to_absolute (expires);
2568 GNUNET_assert (p == find_transport (name));
2572 if ( (addrlen == al->addrlen) &&
2573 (0 == memcmp (addr, &al[1], addrlen)) )
2576 update_addresses (p, GNUNET_NO);
2581 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2582 al->next = p->addresses;
2585 al->addrlen = addrlen;
2586 memcpy (&al[1], addr, addrlen);
2587 update_addresses (p, GNUNET_YES);
2592 * Notify all of our clients about a peer connecting.
2595 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2596 struct GNUNET_TIME_Relative latency,
2599 struct ConnectInfoMessage * cim;
2600 struct TransportClient *cpos;
2605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606 "Notifying clients about connection from `%s'\n",
2609 GNUNET_STATISTICS_update (stats,
2610 gettext_noop ("# peers connected"),
2615 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2616 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2620 cim = GNUNET_malloc (size);
2622 cim->header.size = htons (size);
2623 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2624 cim->ats_count = htonl(2);
2625 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2626 (&(cim->ats))[0].value = htonl (distance);
2627 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2628 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2629 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2630 (&(cim->ats))[2].value = htonl (0);
2631 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2633 /* notify ats about connecting peer */
2634 ats_notify_peer_connect (peer, &(cim->ats), 2);
2637 while (cpos != NULL)
2639 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2648 * Notify all of our clients about a peer disconnecting.
2651 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2653 struct DisconnectInfoMessage dim;
2654 struct TransportClient *cpos;
2657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2658 "Notifying clients about lost connection to `%s'\n",
2661 GNUNET_STATISTICS_update (stats,
2662 gettext_noop ("# peers connected"),
2665 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2666 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2667 dim.reserved = htonl (0);
2668 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2670 /* notify ats about connecting peer */
2671 ats_notify_peer_disconnect (peer);
2674 while (cpos != NULL)
2676 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2683 * Find a ForeignAddressList entry for the given neighbour
2684 * that matches the given address and transport.
2686 * @param neighbour which peer we care about
2687 * @param tname name of the transport plugin
2688 * @param session session to look for, NULL for 'any'; otherwise
2689 * can be used for the service to "learn" this session ID
2691 * @param addr binary address
2692 * @param addrlen length of addr
2693 * @return NULL if no such entry exists
2695 static struct ForeignAddressList *
2696 find_peer_address(struct NeighbourList *neighbour,
2698 struct Session *session,
2702 struct ReadyList *head;
2703 struct ForeignAddressList *pos;
2705 head = neighbour->plugins;
2706 while (head != NULL)
2708 if (0 == strcmp (tname, head->plugin->short_name))
2714 pos = head->addresses;
2715 while ( (pos != NULL) &&
2716 ( (pos->addrlen != addrlen) ||
2717 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2719 if ( (session != NULL) &&
2720 (pos->session == session) )
2724 if ( (session != NULL) && (pos != NULL) )
2725 pos->session = session; /* learn it! */
2731 * Get the peer address struct for the given neighbour and
2732 * address. If it doesn't yet exist, create it.
2734 * @param neighbour which peer we care about
2735 * @param tname name of the transport plugin
2736 * @param session session of the plugin, or NULL for none
2737 * @param addr binary address
2738 * @param addrlen length of addr
2739 * @return NULL if we do not have a transport plugin for 'tname'
2741 static struct ForeignAddressList *
2742 add_peer_address (struct NeighbourList *neighbour,
2744 struct Session *session,
2748 struct ReadyList *head;
2749 struct ForeignAddressList *ret;
2752 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2755 head = neighbour->plugins;
2757 while (head != NULL)
2759 if (0 == strcmp (tname, head->plugin->short_name))
2765 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2766 ret->session = session;
2767 if ((addrlen > 0) && (addr != NULL))
2769 ret->addr = (const char*) &ret[1];
2770 memcpy (&ret[1], addr, addrlen);
2777 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2779 for (c=0; c<available_ressources; c++)
2781 struct ATS_ressource_entry *r = ret->ressources;
2783 r[c].atis_index = ressources[c].atis_index;
2784 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2786 r[c].c = ressources[c].c_unix;
2789 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2791 r[c].c = ressources[c].c_udp;
2794 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2796 r[c].c = ressources[c].c_tcp;
2799 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2801 r[c].c = ressources[c].c_http;
2804 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2806 r[c].c = ressources[c].c_https;
2809 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2811 r[c].c = ressources[c].c_wlan;
2817 r[c].c = ressources[c].c_default;
2818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2819 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2823 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2824 ret->addrlen = addrlen;
2825 ret->expires = GNUNET_TIME_relative_to_absolute
2826 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2827 ret->latency = GNUNET_TIME_relative_get_forever();
2829 ret->timeout = GNUNET_TIME_relative_to_absolute
2830 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2831 ret->ready_list = head;
2832 ret->next = head->addresses;
2833 head->addresses = ret;
2839 * Closure for 'add_validated_address'.
2841 struct AddValidatedAddressContext
2844 * Entry that has been validated.
2846 const struct ValidationEntry *ve;
2849 * Flag set after we have added the address so
2850 * that we terminate the iteration next time.
2857 * Callback function used to fill a buffer of max bytes with a list of
2858 * addresses in the format used by HELLOs. Should use
2859 * "GNUNET_HELLO_add_address" as a helper function.
2861 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2862 * @param max maximum number of bytes that can be written to buf
2863 * @param buf where to write the address information
2864 * @return number of bytes written, 0 to signal the
2865 * end of the iteration.
2868 add_validated_address (void *cls,
2869 size_t max, void *buf)
2871 struct AddValidatedAddressContext *avac = cls;
2872 const struct ValidationEntry *ve = avac->ve;
2874 if (GNUNET_YES == avac->done)
2876 avac->done = GNUNET_YES;
2877 return GNUNET_HELLO_add_address (ve->transport_name,
2878 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2888 * Closure for 'check_address_exists'.
2890 struct CheckAddressExistsClosure
2893 * Address to check for.
2898 * Name of the transport.
2905 struct Session *session;
2908 * Set to GNUNET_YES if the address exists.
2921 * Iterator over hash map entries. Checks if the given
2922 * validation entry is for the same address as what is given
2925 * @param cls the 'struct CheckAddressExistsClosure*'
2926 * @param key current key code (ignored)
2927 * @param value value in the hash map ('struct ValidationEntry')
2928 * @return GNUNET_YES if we should continue to
2929 * iterate (mismatch), GNUNET_NO if not (entry matched)
2932 check_address_exists (void *cls,
2933 const GNUNET_HashCode * key,
2936 struct CheckAddressExistsClosure *caec = cls;
2937 struct ValidationEntry *ve = value;
2939 if ( (0 == strcmp (caec->tname,
2940 ve->transport_name)) &&
2941 (caec->addrlen == ve->addrlen) &&
2942 (0 == memcmp (caec->addr,
2946 caec->exists = GNUNET_YES;
2949 if ( (ve->session != NULL) &&
2950 (caec->session == ve->session) )
2952 caec->exists = GNUNET_YES;
2961 * Iterator to free entries in the validation_map.
2963 * @param cls closure (unused)
2964 * @param key current key code
2965 * @param value value in the hash map (validation to abort)
2966 * @return GNUNET_YES (always)
2969 abort_validation (void *cls,
2970 const GNUNET_HashCode * key,
2973 struct ValidationEntry *va = value;
2975 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2976 GNUNET_SCHEDULER_cancel (va->timeout_task);
2977 GNUNET_free (va->transport_name);
2978 if (va->chvc != NULL)
2980 va->chvc->ve_count--;
2981 if (va->chvc->ve_count == 0)
2983 GNUNET_CONTAINER_DLL_remove (chvc_head,
2986 GNUNET_free (va->chvc);
2996 * HELLO validation cleanup task (validation failed).
2998 * @param cls the 'struct ValidationEntry' that failed
2999 * @param tc scheduler context (unused)
3002 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3004 struct ValidationEntry *va = cls;
3005 struct GNUNET_PeerIdentity pid;
3007 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3008 GNUNET_STATISTICS_update (stats,
3009 gettext_noop ("# address validation timeouts"),
3012 GNUNET_CRYPTO_hash (&va->publicKey,
3014 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3016 GNUNET_break (GNUNET_OK ==
3017 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3020 abort_validation (NULL, NULL, va);
3025 neighbour_timeout_task (void *cls,
3026 const struct GNUNET_SCHEDULER_TaskContext *tc)
3028 struct NeighbourList *n = cls;
3031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3032 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3034 GNUNET_STATISTICS_update (stats,
3035 gettext_noop ("# disconnects due to timeout"),
3038 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3039 disconnect_neighbour (n, GNUNET_NO);
3044 * Schedule the job that will cause us to send a PING to the
3045 * foreign address to evaluate its validity and latency.
3047 * @param fal address to PING
3050 schedule_next_ping (struct ForeignAddressList *fal);
3054 * Add the given address to the list of foreign addresses
3055 * available for the given peer (check for duplicates).
3057 * @param cls the respective 'struct NeighbourList' to update
3058 * @param tname name of the transport
3059 * @param expiration expiration time
3060 * @param addr the address
3061 * @param addrlen length of the address
3062 * @return GNUNET_OK (always)
3065 add_to_foreign_address_list (void *cls,
3067 struct GNUNET_TIME_Absolute expiration,
3071 struct NeighbourList *n = cls;
3072 struct ForeignAddressList *fal;
3075 GNUNET_STATISTICS_update (stats,
3076 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3080 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3083 #if DEBUG_TRANSPORT_HELLO
3084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3085 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3086 a2s (tname, addr, addrlen),
3088 GNUNET_i2s (&n->id),
3089 expiration.abs_value);
3091 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3094 GNUNET_STATISTICS_update (stats,
3095 gettext_noop ("# previously validated addresses lacking transport"),
3101 fal->expires = GNUNET_TIME_absolute_max (expiration,
3103 schedule_next_ping (fal);
3109 fal->expires = GNUNET_TIME_absolute_max (expiration,
3114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3115 "Failed to add new address for `%4s'\n",
3116 GNUNET_i2s (&n->id));
3119 if (fal->validated == GNUNET_NO)
3121 fal->validated = GNUNET_YES;
3122 GNUNET_STATISTICS_update (stats,
3123 gettext_noop ("# peer addresses considered valid"),
3127 if (try == GNUNET_YES)
3129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3130 "Have new addresses, will try to trigger transmissions.\n");
3131 try_transmission_to_peer (n);
3138 * Add addresses in validated HELLO "h" to the set of addresses
3139 * we have for this peer.
3141 * @param cls closure ('struct NeighbourList*')
3142 * @param peer id of the peer, NULL for last call
3143 * @param h hello message for the peer (can be NULL)
3144 * @param err_msg NULL if successful, otherwise contains error message
3147 add_hello_for_peer (void *cls,
3148 const struct GNUNET_PeerIdentity *peer,
3149 const struct GNUNET_HELLO_Message *h,
3150 const char *err_msg)
3152 struct NeighbourList *n = cls;
3154 if (err_msg != NULL)
3156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3157 _("Error in communication with PEERINFO service\n"));
3162 GNUNET_STATISTICS_update (stats,
3163 gettext_noop ("# outstanding peerinfo iterate requests"),
3170 return; /* no HELLO available */
3172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3177 if (GNUNET_YES != n->public_key_valid)
3179 GNUNET_HELLO_get_key (h, &n->publicKey);
3180 n->public_key_valid = GNUNET_YES;
3182 GNUNET_HELLO_iterate_addresses (h,
3184 &add_to_foreign_address_list,
3190 * Create a fresh entry in our neighbour list for the given peer.
3191 * Will try to transmit our current HELLO to the new neighbour.
3192 * Do not call this function directly, use 'setup_peer_check_blacklist.
3194 * @param peer the peer for which we create the entry
3195 * @param do_hello should we schedule transmitting a HELLO
3196 * @return the new neighbour list entry
3198 static struct NeighbourList *
3199 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3202 struct NeighbourList *n;
3203 struct TransportPlugin *tp;
3204 struct ReadyList *rl;
3207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3208 "Setting up state for neighbour `%4s'\n",
3211 GNUNET_assert (our_hello != NULL);
3212 GNUNET_STATISTICS_update (stats,
3213 gettext_noop ("# active neighbours"),
3216 n = GNUNET_malloc (sizeof (struct NeighbourList));
3217 n->next = neighbours;
3221 GNUNET_TIME_relative_to_absolute
3222 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3223 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3224 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3225 MAX_BANDWIDTH_CARRY_S);
3229 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3231 rl = GNUNET_malloc (sizeof (struct ReadyList));
3233 rl->next = n->plugins;
3236 rl->addresses = NULL;
3240 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3242 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3243 &neighbour_timeout_task, n);
3246 GNUNET_STATISTICS_update (stats,
3247 gettext_noop ("# peerinfo new neighbor iterate requests"),
3250 GNUNET_STATISTICS_update (stats,
3251 gettext_noop ("# outstanding peerinfo iterate requests"),
3254 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3255 GNUNET_TIME_UNIT_FOREVER_REL,
3256 &add_hello_for_peer, n);
3258 GNUNET_STATISTICS_update (stats,
3259 gettext_noop ("# HELLO's sent to new neighbors"),
3262 transmit_to_peer (NULL, NULL, 0,
3263 HELLO_ADDRESS_EXPIRATION,
3264 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3272 * Function called after we have checked if communicating
3273 * with a given peer is acceptable.
3275 * @param cls closure
3276 * @param n NULL if communication is not acceptable
3278 typedef void (*SetupContinuation)(void *cls,
3279 struct NeighbourList *n);
3283 * Information kept for each client registered to perform
3289 * This is a linked list.
3291 struct Blacklisters *next;
3294 * This is a linked list.
3296 struct Blacklisters *prev;
3299 * Client responsible for this entry.
3301 struct GNUNET_SERVER_Client *client;
3304 * Blacklist check that we're currently performing.
3306 struct BlacklistCheck *bc;
3312 * Head of DLL of blacklisting clients.
3314 static struct Blacklisters *bl_head;
3317 * Tail of DLL of blacklisting clients.
3319 static struct Blacklisters *bl_tail;
3323 * Context we use when performing a blacklist check.
3325 struct BlacklistCheck
3329 * This is a linked list.
3331 struct BlacklistCheck *next;
3334 * This is a linked list.
3336 struct BlacklistCheck *prev;
3339 * Peer being checked.
3341 struct GNUNET_PeerIdentity peer;
3344 * Option for setup neighbour afterwards.
3349 * Continuation to call with the result.
3351 SetupContinuation cont;
3359 * Current transmission request handle for this client, or NULL if no
3360 * request is pending.
3362 struct GNUNET_CONNECTION_TransmitHandle *th;
3365 * Our current position in the blacklisters list.
3367 struct Blacklisters *bl_pos;
3370 * Current task performing the check.
3372 GNUNET_SCHEDULER_TaskIdentifier task;
3377 * Head of DLL of active blacklisting queries.
3379 static struct BlacklistCheck *bc_head;
3382 * Tail of DLL of active blacklisting queries.
3384 static struct BlacklistCheck *bc_tail;
3388 * Perform next action in the blacklist check.
3390 * @param cls the 'struct BlacklistCheck*'
3394 do_blacklist_check (void *cls,
3395 const struct GNUNET_SCHEDULER_TaskContext *tc);
3398 * Transmit blacklist query to the client.
3400 * @param cls the 'struct BlacklistCheck'
3401 * @param size number of bytes allowed
3402 * @param buf where to copy the message
3403 * @return number of bytes copied to buf
3406 transmit_blacklist_message (void *cls,
3410 struct BlacklistCheck *bc = cls;
3411 struct Blacklisters *bl;
3412 struct BlacklistMessage bm;
3417 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3418 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3423 bm.header.size = htons (sizeof (struct BlacklistMessage));
3424 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3425 bm.is_allowed = htonl (0);
3427 memcpy (buf, &bm, sizeof (bm));
3428 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3434 * Perform next action in the blacklist check.
3436 * @param cls the 'struct BlacklistCheck*'
3440 do_blacklist_check (void *cls,
3441 const struct GNUNET_SCHEDULER_TaskContext *tc)
3443 struct BlacklistCheck *bc = cls;
3444 struct Blacklisters *bl;
3446 bc->task = GNUNET_SCHEDULER_NO_TASK;
3450 bc->cont (bc->cont_cls,
3451 setup_new_neighbour (&bc->peer, bc->do_hello));
3458 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3459 sizeof (struct BlacklistMessage),
3460 GNUNET_TIME_UNIT_FOREVER_REL,
3461 &transmit_blacklist_message,
3468 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3469 * does not yet exist, check the blacklist. If the blacklist says creating
3470 * one is acceptable, create one and call the continuation; otherwise
3471 * call the continuation with NULL.
3473 * @param peer peer to setup or look up a struct NeighbourList for
3474 * @param do_hello should we also schedule sending our HELLO to the peer
3475 * if this is a new record
3476 * @param cont function to call with the 'struct NeigbhbourList*'
3477 * @param cont_cls closure for cont
3480 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3482 SetupContinuation cont,
3485 struct NeighbourList *n;
3486 struct BlacklistCheck *bc;
3488 n = find_neighbour(peer);
3495 if (bl_head == NULL)
3498 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3500 setup_new_neighbour(peer, do_hello);
3503 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3504 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3506 bc->do_hello = do_hello;
3508 bc->cont_cls = cont_cls;
3509 bc->bl_pos = bl_head;
3510 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3516 * Function called with the result of querying a new blacklister about
3517 * it being allowed (or not) to continue to talk to an existing neighbour.
3519 * @param cls the original 'struct NeighbourList'
3520 * @param n NULL if we need to disconnect
3523 confirm_or_drop_neighbour (void *cls,
3524 struct NeighbourList *n)
3526 struct NeighbourList * orig = cls;
3530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3531 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3532 "confirm_or_drop_neighboUr");
3533 disconnect_neighbour (orig, GNUNET_NO);
3539 * Handle a request to start a blacklist.
3541 * @param cls closure (always NULL)
3542 * @param client identification of the client
3543 * @param message the actual message
3546 handle_blacklist_init (void *cls,
3547 struct GNUNET_SERVER_Client *client,
3548 const struct GNUNET_MessageHeader *message)
3550 struct Blacklisters *bl;
3551 struct BlacklistCheck *bc;
3552 struct NeighbourList *n;
3557 if (bl->client == client)
3560 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3565 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3566 bl->client = client;
3567 GNUNET_SERVER_client_keep (client);
3568 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3569 /* confirm that all existing connections are OK! */
3573 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3574 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3576 bc->do_hello = GNUNET_NO;
3577 bc->cont = &confirm_or_drop_neighbour;
3580 if (n == neighbours) /* all would wait for the same client, no need to
3581 create more than just the first task right now */
3582 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3590 * Handle a request to blacklist a peer.
3592 * @param cls closure (always NULL)
3593 * @param client identification of the client
3594 * @param message the actual message
3597 handle_blacklist_reply (void *cls,
3598 struct GNUNET_SERVER_Client *client,
3599 const struct GNUNET_MessageHeader *message)
3601 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3602 struct Blacklisters *bl;
3603 struct BlacklistCheck *bc;
3606 while ( (bl != NULL) &&
3607 (bl->client != client) )
3611 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3616 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3618 bc->cont (bc->cont_cls, NULL);
3619 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3624 bc->bl_pos = bc->bl_pos->next;
3625 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3628 /* check if any other bc's are waiting for this blacklister */
3632 if ( (bc->bl_pos == bl) &&
3633 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3634 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3642 * Send periodic PING messages to a given foreign address.
3644 * @param cls our 'struct PeriodicValidationContext*'
3645 * @param tc task context
3648 send_periodic_ping (void *cls,
3649 const struct GNUNET_SCHEDULER_TaskContext *tc)
3651 struct ForeignAddressList *peer_address = cls;
3652 struct TransportPlugin *tp;
3653 struct ValidationEntry *va;
3654 struct NeighbourList *neighbour;
3655 struct TransportPingMessage ping;
3656 struct CheckAddressExistsClosure caec;
3658 uint16_t hello_size;
3662 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3663 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3665 tp = peer_address->ready_list->plugin;
3666 neighbour = peer_address->ready_list->neighbour;
3667 if (GNUNET_YES != neighbour->public_key_valid)
3669 /* no public key yet, try again later */
3670 schedule_next_ping (peer_address);
3673 caec.addr = peer_address->addr;
3674 caec.addrlen = peer_address->addrlen;
3675 caec.tname = tp->short_name;
3676 caec.session = peer_address->session;
3677 caec.exists = GNUNET_NO;
3678 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3679 &check_address_exists,
3681 if (caec.exists == GNUNET_YES)
3683 /* During validation attempts we will likely trigger the other
3684 peer trying to validate our address which in turn will cause
3685 it to send us its HELLO, so we expect to hit this case rather
3686 frequently. Only print something if we are very verbose. */
3687 #if DEBUG_TRANSPORT > 1
3688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3689 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3690 (peer_address->addr != NULL)
3691 ? a2s (tp->short_name,
3693 peer_address->addrlen)
3696 GNUNET_i2s (&neighbour->id));
3698 schedule_next_ping (peer_address);
3701 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3702 va->transport_name = GNUNET_strdup (tp->short_name);
3703 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3705 va->send_time = GNUNET_TIME_absolute_get();
3706 va->session = peer_address->session;
3707 if (peer_address->addr != NULL)
3709 va->addr = (const void*) &va[1];
3710 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3711 va->addrlen = peer_address->addrlen;
3713 memcpy(&va->publicKey,
3714 &neighbour->publicKey,
3715 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3717 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3718 &timeout_hello_validation,
3720 GNUNET_CONTAINER_multihashmap_put (validation_map,
3721 &neighbour->id.hashPubKey,
3723 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3725 if (peer_address->validated != GNUNET_YES)
3726 hello_size = GNUNET_HELLO_size(our_hello);
3730 tsize = sizeof(struct TransportPingMessage) + hello_size;
3732 if (peer_address->addr != NULL)
3734 slen = strlen (tp->short_name) + 1;
3735 tsize += slen + peer_address->addrlen;
3739 slen = 0; /* make gcc happy */
3741 message_buf = GNUNET_malloc(tsize);
3742 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3743 ping.challenge = htonl(va->challenge);
3744 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3745 if (peer_address->validated != GNUNET_YES)
3747 memcpy(message_buf, our_hello, hello_size);
3750 if (peer_address->addr != NULL)
3752 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3753 peer_address->addrlen +
3755 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3758 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3760 peer_address->addrlen);
3764 ping.header.size = htons(sizeof(struct TransportPingMessage));
3767 memcpy(&message_buf[hello_size],
3769 sizeof(struct TransportPingMessage));
3771 #if DEBUG_TRANSPORT_REVALIDATION
3772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3773 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3774 (peer_address->addr != NULL)
3775 ? a2s (peer_address->plugin->short_name,
3777 peer_address->addrlen)
3780 GNUNET_i2s (&neighbour->id),
3781 "HELLO", hello_size,
3784 if (peer_address->validated != GNUNET_YES)
3785 GNUNET_STATISTICS_update (stats,
3786 gettext_noop ("# PING with HELLO messages sent"),
3790 GNUNET_STATISTICS_update (stats,
3791 gettext_noop ("# PING without HELLO messages sent"),
3794 GNUNET_STATISTICS_update (stats,
3795 gettext_noop ("# PING messages sent for re-validation"),
3798 transmit_to_peer (NULL, peer_address,
3799 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3800 HELLO_VERIFICATION_TIMEOUT,
3802 GNUNET_YES, neighbour);
3803 GNUNET_free(message_buf);
3804 schedule_next_ping (peer_address);
3809 * Schedule the job that will cause us to send a PING to the
3810 * foreign address to evaluate its validity and latency.
3812 * @param fal address to PING
3815 schedule_next_ping (struct ForeignAddressList *fal)
3817 struct GNUNET_TIME_Relative delay;
3819 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3821 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3822 delay.rel_value /= 2; /* do before expiration */
3823 delay = GNUNET_TIME_relative_min (delay,
3824 LATENCY_EVALUATION_MAX_DELAY);
3825 if (GNUNET_YES != fal->estimated)
3827 delay = GNUNET_TIME_UNIT_ZERO;
3828 fal->estimated = GNUNET_YES;
3830 if (GNUNET_YES == fal->connected)
3832 delay = GNUNET_TIME_relative_min (delay,
3833 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3835 /* FIXME: also adjust delay based on how close the last
3836 observed latency is to the latency of the best alternative */
3837 /* bound how fast we can go */
3838 delay = GNUNET_TIME_relative_max (delay,
3839 GNUNET_TIME_UNIT_SECONDS);
3840 /* randomize a bit (to avoid doing all at the same time) */
3841 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3842 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3843 &send_periodic_ping,
3851 * Function that will be called if we receive some payload
3852 * from another peer.
3854 * @param message the payload
3855 * @param n peer who claimed to be the sender
3858 handle_payload_message (const struct GNUNET_MessageHeader *message,
3859 struct NeighbourList *n)
3861 struct InboundMessage *im;
3862 struct TransportClient *cpos;
3865 msize = ntohs (message->size);
3866 if (n->received_pong == GNUNET_NO)
3868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3869 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3870 ntohs (message->type),
3871 ntohs (message->size),
3872 GNUNET_i2s (&n->id));
3873 GNUNET_free_non_null (n->pre_connect_message_buffer);
3874 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3875 memcpy (n->pre_connect_message_buffer, message, msize);
3880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3881 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3882 ntohs (message->type),
3883 ntohs (message->size),
3884 GNUNET_i2s (&n->id));
3886 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3889 n->quota_violation_count++;
3891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3892 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3893 n->in_tracker.available_bytes_per_s__,
3894 n->quota_violation_count);
3896 /* Discount 32k per violation */
3897 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3902 if (n->quota_violation_count > 0)
3904 /* try to add 32k back */
3905 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3907 n->quota_violation_count--;
3910 GNUNET_STATISTICS_update (stats,
3911 gettext_noop ("# payload received from other peers"),
3914 /* transmit message to all clients */
3915 uint32_t ats_count = 2;
3916 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3917 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3920 im = GNUNET_malloc (size);
3921 im->header.size = htons (size);
3922 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3924 im->ats_count = htonl(ats_count);
3925 /* Setting ATS data */
3926 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3927 (&(im->ats))[0].value = htonl (n->distance);
3928 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3929 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3930 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3931 (&(im->ats))[ats_count].value = htonl (0);
3933 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3935 while (cpos != NULL)
3937 transmit_to_client (cpos, &im->header, GNUNET_YES);
3945 * Iterator over hash map entries. Checks if the given validation
3946 * entry is for the same challenge as what is given in the PONG.
3948 * @param cls the 'struct TransportPongMessage*'
3949 * @param key peer identity
3950 * @param value value in the hash map ('struct ValidationEntry')
3951 * @return GNUNET_YES if we should continue to
3952 * iterate (mismatch), GNUNET_NO if not (entry matched)
3955 check_pending_validation (void *cls,
3956 const GNUNET_HashCode * key,
3959 const struct TransportPongMessage *pong = cls;
3960 struct ValidationEntry *ve = value;
3961 struct AddValidatedAddressContext avac;
3962 unsigned int challenge = ntohl(pong->challenge);
3963 struct GNUNET_HELLO_Message *hello;
3964 struct GNUNET_PeerIdentity target;
3965 struct NeighbourList *n;
3966 struct ForeignAddressList *fal;
3967 struct OwnAddressList *oal;
3968 struct TransportPlugin *tp;
3969 struct GNUNET_MessageHeader *prem;
3975 ps = ntohs (pong->header.size);
3976 if (ps < sizeof (struct TransportPongMessage))
3978 GNUNET_break_op (0);
3981 addr = (const char*) &pong[1];
3982 slen = strlen (ve->transport_name) + 1;
3983 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3984 (ve->challenge != challenge) ||
3985 (addr[slen-1] != '\0') ||
3986 (0 != strcmp (addr, ve->transport_name)) ||
3987 (ntohl (pong->purpose.size)
3988 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3990 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3991 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3996 alen = ps - sizeof (struct TransportPongMessage) - slen;
3997 switch (ntohl (pong->purpose.purpose))
3999 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4000 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4001 (0 != memcmp (&addr[slen],
4005 return GNUNET_YES; /* different entry, keep trying! */
4007 if (0 != memcmp (&pong->pid,
4009 sizeof (struct GNUNET_PeerIdentity)))
4011 GNUNET_break_op (0);
4015 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4020 GNUNET_break_op (0);
4025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4026 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4028 a2s (ve->transport_name,
4029 (const struct sockaddr *) ve->addr,
4031 ve->transport_name);
4034 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4035 if (0 != memcmp (&pong->pid,
4037 sizeof (struct GNUNET_PeerIdentity)))
4039 GNUNET_break_op (0);
4042 if (ve->addrlen != 0)
4044 /* must have been for a different validation entry */
4047 tp = find_transport (ve->transport_name);
4053 oal = tp->addresses;
4056 if ( (oal->addrlen == alen) &&
4057 (0 == memcmp (&oal[1],
4065 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4066 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
4067 a2s (ve->transport_name,
4073 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4078 GNUNET_break_op (0);
4083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4084 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4086 a2s (ve->transport_name,
4089 ve->transport_name);
4093 GNUNET_break_op (0);
4096 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4098 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4099 _("Received expired signature. Check system time.\n"));
4102 GNUNET_STATISTICS_update (stats,
4103 gettext_noop ("# address validation successes"),
4106 /* create the updated HELLO */
4107 GNUNET_CRYPTO_hash (&ve->publicKey,
4108 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4109 &target.hashPubKey);
4110 if (ve->addr != NULL)
4112 avac.done = GNUNET_NO;
4114 hello = GNUNET_HELLO_create (&ve->publicKey,
4115 &add_validated_address,
4117 GNUNET_PEERINFO_add_peer (peerinfo,
4119 GNUNET_free (hello);
4121 n = find_neighbour (&target);
4124 n->publicKey = ve->publicKey;
4125 n->public_key_valid = GNUNET_YES;
4126 fal = add_peer_address (n,
4131 GNUNET_assert (fal != NULL);
4132 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4133 fal->validated = GNUNET_YES;
4134 mark_address_connected (fal);
4135 GNUNET_STATISTICS_update (stats,
4136 gettext_noop ("# peer addresses considered valid"),
4139 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4140 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4142 schedule_next_ping (fal);
4143 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4144 n->latency = fal->latency;
4146 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4148 n->distance = fal->distance;
4149 if (GNUNET_NO == n->received_pong)
4151 n->received_pong = GNUNET_YES;
4153 notify_clients_connect (&target, n->latency, n->distance);
4154 if (NULL != (prem = n->pre_connect_message_buffer))
4156 n->pre_connect_message_buffer = NULL;
4157 handle_payload_message (prem, n);
4161 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4163 GNUNET_SCHEDULER_cancel (n->retry_task);
4164 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4165 try_transmission_to_peer (n);
4169 /* clean up validation entry */
4170 GNUNET_assert (GNUNET_YES ==
4171 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4174 abort_validation (NULL, NULL, ve);
4180 * Function that will be called if we receive a validation
4181 * of an address challenge that we transmitted to another
4182 * peer. Note that the validation should only be considered
4183 * acceptable if the challenge matches AND if the sender
4184 * address is at least a plausible address for this peer
4185 * (otherwise we may be seeing a MiM attack).
4187 * @param cls closure
4188 * @param message the pong message
4189 * @param peer who responded to our challenge
4190 * @param sender_address string describing our sender address (as observed
4191 * by the other peer in binary format)
4192 * @param sender_address_len number of bytes in 'sender_address'
4195 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4196 const struct GNUNET_PeerIdentity *peer,
4197 const char *sender_address,
4198 size_t sender_address_len)
4200 #if DEBUG_TRANSPORT > 1
4201 /* we get tons of these that just get discarded, only log
4202 if we are quite verbose */
4203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4204 "Receiving `%s' message from `%4s'.\n", "PONG",
4207 GNUNET_STATISTICS_update (stats,
4208 gettext_noop ("# PONG messages received"),
4211 if (GNUNET_SYSERR !=
4212 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4214 &check_pending_validation,
4217 /* This is *expected* to happen a lot since we send
4218 PONGs to *all* known addresses of the sender of
4219 the PING, so most likely we get multiple PONGs
4220 per PING, and all but the first PONG will end up
4221 here. So really we should not print anything here
4222 unless we want to be very, very verbose... */
4223 #if DEBUG_TRANSPORT > 2
4224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4225 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4237 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4239 * @param cls the 'struct ValidationEntry*'
4240 * @param neighbour neighbour to validate, NULL if validation failed
4243 transmit_hello_and_ping (void *cls,
4244 struct NeighbourList *neighbour)
4246 struct ValidationEntry *va = cls;
4247 struct ForeignAddressList *peer_address;
4248 struct TransportPingMessage ping;
4249 uint16_t hello_size;
4252 struct GNUNET_PeerIdentity id;
4255 GNUNET_CRYPTO_hash (&va->publicKey,
4256 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4258 if (neighbour == NULL)
4260 /* FIXME: stats... */
4261 GNUNET_break (GNUNET_OK ==
4262 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4265 abort_validation (NULL, NULL, va);
4268 neighbour->publicKey = va->publicKey;
4269 neighbour->public_key_valid = GNUNET_YES;
4270 peer_address = add_peer_address (neighbour,
4271 va->transport_name, NULL,
4272 (const void*) &va[1],
4274 if (peer_address == NULL)
4276 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4277 "Failed to add peer `%4s' for plugin `%s'\n",
4278 GNUNET_i2s (&neighbour->id),
4279 va->transport_name);
4280 GNUNET_break (GNUNET_OK ==
4281 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4284 abort_validation (NULL, NULL, va);
4287 hello_size = GNUNET_HELLO_size(our_hello);
4288 slen = strlen(va->transport_name) + 1;
4289 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4290 message_buf = GNUNET_malloc(tsize);
4291 ping.challenge = htonl(va->challenge);
4292 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4293 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4294 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4295 memcpy(message_buf, our_hello, hello_size);
4296 memcpy(&message_buf[hello_size],
4298 sizeof(struct TransportPingMessage));
4299 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4302 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4307 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4310 : a2s (va->transport_name,
4311 (const void*) &va[1], va->addrlen),
4313 GNUNET_i2s (&neighbour->id),
4314 "HELLO", hello_size,
4315 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4318 GNUNET_STATISTICS_update (stats,
4319 gettext_noop ("# PING messages sent for initial validation"),
4322 transmit_to_peer (NULL, peer_address,
4323 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4324 HELLO_VERIFICATION_TIMEOUT,
4326 GNUNET_YES, neighbour);
4327 GNUNET_free(message_buf);
4332 * Check if the given address is already being validated; if not,
4333 * append the given address to the list of entries that are being be
4334 * validated and initiate validation.
4336 * @param cls closure ('struct CheckHelloValidatedContext *')
4337 * @param tname name of the transport
4338 * @param expiration expiration time
4339 * @param addr the address
4340 * @param addrlen length of the address
4341 * @return GNUNET_OK (always)
4344 run_validation (void *cls,
4346 struct GNUNET_TIME_Absolute expiration,
4350 struct CheckHelloValidatedContext *chvc = cls;
4351 struct GNUNET_PeerIdentity id;
4352 struct TransportPlugin *tp;
4353 struct ValidationEntry *va;
4354 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4355 struct CheckAddressExistsClosure caec;
4356 struct OwnAddressList *oal;
4358 GNUNET_assert (addr != NULL);
4360 GNUNET_STATISTICS_update (stats,
4361 gettext_noop ("# peer addresses scheduled for validation"),
4364 tp = find_transport (tname);
4367 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4368 GNUNET_ERROR_TYPE_BULK,
4370 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4372 GNUNET_STATISTICS_update (stats,
4373 gettext_noop ("# peer addresses not validated (plugin not available)"),
4378 /* check if this is one of our own addresses */
4379 oal = tp->addresses;
4382 if ( (oal->addrlen == addrlen) &&
4383 (0 == memcmp (&oal[1],
4387 /* not plausible, this address is equivalent to our own address! */
4388 GNUNET_STATISTICS_update (stats,
4389 gettext_noop ("# peer addresses not validated (loopback)"),
4396 GNUNET_HELLO_get_key (chvc->hello, &pk);
4397 GNUNET_CRYPTO_hash (&pk,
4399 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4402 if (is_blacklisted(&id, tp))
4405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4406 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4414 caec.addrlen = addrlen;
4415 caec.session = NULL;
4417 caec.exists = GNUNET_NO;
4418 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4419 &check_address_exists,
4421 if (caec.exists == GNUNET_YES)
4423 /* During validation attempts we will likely trigger the other
4424 peer trying to validate our address which in turn will cause
4425 it to send us its HELLO, so we expect to hit this case rather
4426 frequently. Only print something if we are very verbose. */
4427 #if DEBUG_TRANSPORT > 1
4428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4429 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4430 a2s (tname, addr, addrlen),
4434 GNUNET_STATISTICS_update (stats,
4435 gettext_noop ("# peer addresses not validated (in progress)"),
4440 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4443 va->transport_name = GNUNET_strdup (tname);
4444 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4446 va->send_time = GNUNET_TIME_absolute_get();
4447 va->addr = (const void*) &va[1];
4448 memcpy (&va[1], addr, addrlen);
4449 va->addrlen = addrlen;
4450 GNUNET_HELLO_get_key (chvc->hello,
4452 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4453 &timeout_hello_validation,
4455 GNUNET_CONTAINER_multihashmap_put (validation_map,
4458 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4459 setup_peer_check_blacklist (&id, GNUNET_NO,
4460 &transmit_hello_and_ping,
4467 * Check if addresses in validated hello "h" overlap with
4468 * those in "chvc->hello" and validate the rest.
4470 * @param cls closure
4471 * @param peer id of the peer, NULL for last call
4472 * @param h hello message for the peer (can be NULL)
4473 * @param err_msg NULL if successful, otherwise contains error message
4476 check_hello_validated (void *cls,
4477 const struct GNUNET_PeerIdentity *peer,
4478 const struct GNUNET_HELLO_Message *h,
4479 const char *err_msg)
4481 struct CheckHelloValidatedContext *chvc = cls;
4482 struct GNUNET_HELLO_Message *plain_hello;
4483 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4484 struct GNUNET_PeerIdentity target;
4485 struct NeighbourList *n;
4487 if (err_msg != NULL)
4489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4490 _("Error in communication with PEERINFO service\n"));
4496 GNUNET_STATISTICS_update (stats,
4497 gettext_noop ("# outstanding peerinfo iterate requests"),
4501 if (GNUNET_NO == chvc->hello_known)
4503 /* notify PEERINFO about the peer now, so that we at least
4504 have the public key if some other component needs it */
4505 GNUNET_HELLO_get_key (chvc->hello, &pk);
4506 GNUNET_CRYPTO_hash (&pk,
4507 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4508 &target.hashPubKey);
4509 plain_hello = GNUNET_HELLO_create (&pk,
4512 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4513 GNUNET_free (plain_hello);
4514 #if DEBUG_TRANSPORT_HELLO
4515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4516 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4518 GNUNET_i2s (&target));
4520 GNUNET_STATISTICS_update (stats,
4521 gettext_noop ("# new HELLOs requiring full validation"),
4524 GNUNET_HELLO_iterate_addresses (chvc->hello,
4531 GNUNET_STATISTICS_update (stats,
4532 gettext_noop ("# duplicate HELLO (peer known)"),
4537 if (chvc->ve_count == 0)
4539 GNUNET_CONTAINER_DLL_remove (chvc_head,
4548 #if DEBUG_TRANSPORT_HELLO
4549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4550 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4554 chvc->hello_known = GNUNET_YES;
4555 n = find_neighbour (peer);
4558 #if DEBUG_TRANSPORT_HELLO
4559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4560 "Calling hello_iterate_addresses for %s!\n",
4563 GNUNET_HELLO_iterate_addresses (h,
4565 &add_to_foreign_address_list,
4567 try_transmission_to_peer (n);
4571 #if DEBUG_TRANSPORT_HELLO
4572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4573 "No existing neighbor record for %s!\n",
4576 GNUNET_STATISTICS_update (stats,
4577 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4581 GNUNET_STATISTICS_update (stats,
4582 gettext_noop ("# HELLO validations (update case)"),
4585 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4587 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4594 * Process HELLO-message.
4596 * @param plugin transport involved, may be NULL
4597 * @param message the actual message
4598 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4601 process_hello (struct TransportPlugin *plugin,
4602 const struct GNUNET_MessageHeader *message)
4605 struct GNUNET_PeerIdentity target;
4606 const struct GNUNET_HELLO_Message *hello;
4607 struct CheckHelloValidatedContext *chvc;
4608 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4609 #if DEBUG_TRANSPORT_HELLO > 2
4612 hsize = ntohs (message->size);
4613 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4614 (hsize < sizeof (struct GNUNET_MessageHeader)))
4617 return GNUNET_SYSERR;
4619 GNUNET_STATISTICS_update (stats,
4620 gettext_noop ("# HELLOs received for validation"),
4624 /* first, check if load is too high */
4625 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4627 GNUNET_STATISTICS_update (stats,
4628 gettext_noop ("# HELLOs ignored due to high load"),
4631 #if DEBUG_TRANSPORT_HELLO
4632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4633 "Ignoring `%s' for `%4s', load too high.\n",
4635 GNUNET_i2s (&target));
4639 hello = (const struct GNUNET_HELLO_Message *) message;
4640 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4642 #if DEBUG_TRANSPORT_HELLO
4643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4644 "Unable to get public key from `%s' for `%4s'!\n",
4646 GNUNET_i2s (&target));
4648 GNUNET_break_op (0);
4649 return GNUNET_SYSERR;
4652 GNUNET_CRYPTO_hash (&publicKey,
4653 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4654 &target.hashPubKey);
4656 #if DEBUG_TRANSPORT_HELLO
4657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4658 "Received `%s' message for `%4s'\n",
4660 GNUNET_i2s (&target));
4663 if (0 == memcmp (&my_identity,
4665 sizeof (struct GNUNET_PeerIdentity)))
4667 GNUNET_STATISTICS_update (stats,
4668 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4674 while (NULL != chvc)
4676 if (GNUNET_HELLO_equals (hello,
4678 GNUNET_TIME_absolute_get ()).abs_value > 0)
4680 #if DEBUG_TRANSPORT_HELLO > 2
4681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4682 "Received duplicate `%s' message for `%4s'; ignored\n",
4684 GNUNET_i2s (&target));
4686 return GNUNET_OK; /* validation already pending */
4688 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4689 GNUNET_break (0 != memcmp (hello, chvc->hello,
4690 GNUNET_HELLO_size(hello)));
4695 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4696 if ((NULL != temp_neighbor))
4698 fprintf(stderr, "Already know peer, ignoring hello\n");
4703 #if DEBUG_TRANSPORT_HELLO > 2
4706 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4708 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4711 GNUNET_i2s (&target),
4713 GNUNET_HELLO_size(hello));
4717 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4719 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4720 memcpy (&chvc[1], hello, hsize);
4721 GNUNET_CONTAINER_DLL_insert (chvc_head,
4724 /* finally, check if HELLO was previously validated
4725 (continuation will then schedule actual validation) */
4726 GNUNET_STATISTICS_update (stats,
4727 gettext_noop ("# peerinfo process hello iterate requests"),
4730 GNUNET_STATISTICS_update (stats,
4731 gettext_noop ("# outstanding peerinfo iterate requests"),
4734 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4736 HELLO_VERIFICATION_TIMEOUT,
4737 &check_hello_validated, chvc);
4743 * The peer specified by the given neighbour has timed-out or a plugin
4744 * has disconnected. We may either need to do nothing (other plugins
4745 * still up), or trigger a full disconnect and clean up. This
4746 * function updates our state and does the necessary notifications.
4747 * Also notifies our clients that the neighbour is now officially
4750 * @param n the neighbour list entry for the peer
4751 * @param check GNUNET_YES to check if ALL addresses for this peer
4752 * are gone, GNUNET_NO to force a disconnect of the peer
4753 * regardless of whether other addresses exist.
4756 disconnect_neighbour (struct NeighbourList *n, int check)
4758 struct ReadyList *rpos;
4759 struct NeighbourList *npos;
4760 struct NeighbourList *nprev;
4761 struct MessageQueue *mq;
4762 struct ForeignAddressList *peer_addresses;
4763 struct ForeignAddressList *peer_pos;
4765 if (GNUNET_YES == check)
4768 while (NULL != rpos)
4770 peer_addresses = rpos->addresses;
4771 while (peer_addresses != NULL)
4773 if (GNUNET_YES == peer_addresses->connected)
4775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4776 "NOT Disconnecting from `%4s', still have live addresses!\n",
4777 GNUNET_i2s (&n->id));
4778 return; /* still connected */
4780 peer_addresses = peer_addresses->next;
4786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4787 "Disconnecting from `%4s'\n",
4788 GNUNET_i2s (&n->id));
4790 /* remove n from neighbours list */
4793 while ((npos != NULL) && (npos != n))
4798 GNUNET_assert (npos != NULL);
4800 neighbours = n->next;
4802 nprev->next = n->next;
4804 /* notify all clients about disconnect */
4805 if (GNUNET_YES == n->received_pong)
4806 notify_clients_disconnect (&n->id);
4808 /* clean up all plugins, cancel connections and pending transmissions */
4809 while (NULL != (rpos = n->plugins))
4811 n->plugins = rpos->next;
4812 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4813 while (rpos->addresses != NULL)
4815 peer_pos = rpos->addresses;
4816 rpos->addresses = peer_pos->next;
4817 if (peer_pos->connected == GNUNET_YES)
4818 GNUNET_STATISTICS_update (stats,
4819 gettext_noop ("# connected addresses"),
4822 if (GNUNET_YES == peer_pos->validated)
4823 GNUNET_STATISTICS_update (stats,
4824 gettext_noop ("# peer addresses considered valid"),
4827 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4829 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4830 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4832 GNUNET_free(peer_pos->ressources);
4833 GNUNET_free(peer_pos->quality);
4834 GNUNET_free(peer_pos);
4839 /* free all messages on the queue */
4840 while (NULL != (mq = n->messages_head))
4842 GNUNET_STATISTICS_update (stats,
4843 gettext_noop ("# bytes in message queue for other peers"),
4844 - (int64_t) mq->message_buf_size,
4846 GNUNET_STATISTICS_update (stats,
4847 gettext_noop ("# bytes discarded due to disconnect"),
4848 mq->message_buf_size,
4850 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4853 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4855 sizeof(struct GNUNET_PeerIdentity)));
4858 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4860 GNUNET_SCHEDULER_cancel (n->timeout_task);
4861 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4863 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4865 GNUNET_SCHEDULER_cancel (n->retry_task);
4866 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4868 if (n->piter != NULL)
4870 GNUNET_PEERINFO_iterate_cancel (n->piter);
4871 GNUNET_STATISTICS_update (stats,
4872 gettext_noop ("# outstanding peerinfo iterate requests"),
4877 /* finally, free n itself */
4878 GNUNET_STATISTICS_update (stats,
4879 gettext_noop ("# active neighbours"),
4882 GNUNET_free_non_null (n->pre_connect_message_buffer);
4888 * We have received a PING message from someone. Need to send a PONG message
4889 * in response to the peer by any means necessary.
4892 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4893 const struct GNUNET_PeerIdentity *peer,
4894 struct Session *session,
4895 const char *sender_address,
4896 uint16_t sender_address_len)
4898 struct TransportPlugin *plugin = cls;
4899 struct SessionHeader *session_header = (struct SessionHeader*) session;
4900 struct TransportPingMessage *ping;
4901 struct TransportPongMessage *pong;
4902 struct NeighbourList *n;
4903 struct ReadyList *rl;
4904 struct ForeignAddressList *fal;
4905 struct OwnAddressList *oal;
4910 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4912 GNUNET_break_op (0);
4913 return GNUNET_SYSERR;
4916 ping = (struct TransportPingMessage *) message;
4917 if (0 != memcmp (&ping->target,
4918 plugin->env.my_identity,
4919 sizeof (struct GNUNET_PeerIdentity)))
4921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4922 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4924 (sender_address != NULL)
4925 ? a2s (plugin->short_name,
4926 (const struct sockaddr *)sender_address,
4929 GNUNET_i2s (&ping->target));
4930 return GNUNET_SYSERR;
4933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4934 "Processing `%s' from `%s'\n",
4936 (sender_address != NULL)
4937 ? a2s (plugin->short_name,
4938 (const struct sockaddr *)sender_address,
4942 GNUNET_STATISTICS_update (stats,
4943 gettext_noop ("# PING messages received"),
4946 addr = (const char*) &ping[1];
4947 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4948 slen = strlen (plugin->short_name) + 1;
4951 /* peer wants to confirm that we have an outbound connection to him */
4952 if (session == NULL)
4954 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4955 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4957 return GNUNET_SYSERR;
4959 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4960 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4961 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4962 pong->purpose.size =
4963 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4965 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4966 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4967 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4968 pong->challenge = ping->challenge;
4969 pong->addrlen = htonl(sender_address_len + slen);
4972 sizeof(struct GNUNET_PeerIdentity));
4976 if ((sender_address!=NULL) && (sender_address_len > 0))
4977 memcpy (&((char*)&pong[1])[slen],
4979 sender_address_len);
4980 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4982 /* create / update cached sig */
4984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4985 "Creating PONG signature to indicate active connection.\n");
4987 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4988 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4989 GNUNET_assert (GNUNET_OK ==
4990 GNUNET_CRYPTO_rsa_sign (my_private_key,
4992 &session_header->pong_signature));
4996 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4998 memcpy (&pong->signature,
4999 &session_header->pong_signature,
5000 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5006 /* peer wants to confirm that this is one of our addresses */
5010 plugin->api->check_address (plugin->api->cls,
5014 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5015 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5016 a2s (plugin->short_name,
5021 oal = plugin->addresses;
5024 if ( (oal->addrlen == alen) &&
5031 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5032 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5033 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5034 pong->purpose.size =
5035 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5037 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5038 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5039 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5040 pong->challenge = ping->challenge;
5041 pong->addrlen = htonl(alen + slen);
5044 sizeof(struct GNUNET_PeerIdentity));
5045 memcpy (&pong[1], plugin->short_name, slen);
5046 memcpy (&((char*)&pong[1])[slen], addr, alen);
5047 if ( (oal != NULL) &&
5048 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5050 /* create / update cached sig */
5052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5053 "Creating PONG signature to indicate ownership.\n");
5055 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
5056 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5057 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5058 GNUNET_assert (GNUNET_OK ==
5059 GNUNET_CRYPTO_rsa_sign (my_private_key,
5061 &oal->pong_signature));
5062 memcpy (&pong->signature,
5063 &oal->pong_signature,
5064 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5066 else if (oal == NULL)
5068 /* not using cache (typically DV-only) */
5069 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5070 GNUNET_assert (GNUNET_OK ==
5071 GNUNET_CRYPTO_rsa_sign (my_private_key,
5077 /* can used cached version */
5078 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5079 memcpy (&pong->signature,
5080 &oal->pong_signature,
5081 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5084 n = find_neighbour(peer);
5085 GNUNET_assert (n != NULL);
5086 /* first try reliable response transmission */
5090 fal = rl->addresses;
5093 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5096 ntohs (pong->header.size),
5097 TRANSPORT_PONG_PRIORITY,
5098 HELLO_VERIFICATION_TIMEOUT,
5106 GNUNET_STATISTICS_update (stats,
5107 gettext_noop ("# PONGs unicast via reliable transport"),
5117 /* no reliable method found, do multicast */
5118 GNUNET_STATISTICS_update (stats,
5119 gettext_noop ("# PONGs multicast to all available addresses"),
5125 fal = rl->addresses;
5128 transmit_to_peer(NULL, fal,
5129 TRANSPORT_PONG_PRIORITY,
5130 HELLO_VERIFICATION_TIMEOUT,
5132 ntohs(pong->header.size),
5148 * Function called by the plugin for each received message.
5149 * Update data volumes, possibly notify plugins about
5150 * reducing the rate at which they read from the socket
5151 * and generally forward to our receive callback.
5153 * @param cls the "struct TransportPlugin *" we gave to the plugin
5154 * @param peer (claimed) identity of the other peer
5155 * @param message the message, NULL if we only care about
5156 * learning about the delay until we should receive again
5157 * @param ats_data information for automatic transport selection
5158 * @param ats_count number of elements in ats not including 0-terminator
5159 * @param session identifier used for this session (can be NULL)
5160 * @param sender_address binary address of the sender (if observed)
5161 * @param sender_address_len number of bytes in sender_address
5162 * @return how long in ms the plugin should wait until receiving more data
5163 * (plugins that do not support this, can ignore the return value)
5165 static struct GNUNET_TIME_Relative
5166 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5167 const struct GNUNET_MessageHeader *message,
5168 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5170 struct Session *session,
5171 const char *sender_address,
5172 uint16_t sender_address_len)
5174 struct TransportPlugin *plugin = cls;
5175 struct ReadyList *service_context;
5176 struct ForeignAddressList *peer_address;
5178 struct NeighbourList *n;
5179 struct GNUNET_TIME_Relative ret;
5180 if (is_blacklisted (peer, plugin))
5181 return GNUNET_TIME_UNIT_FOREVER_REL;
5185 n = find_neighbour (peer);
5187 n = setup_new_neighbour (peer, GNUNET_YES);
5188 service_context = n->plugins;
5189 while ((service_context != NULL) && (plugin != service_context->plugin))
5190 service_context = service_context->next;
5191 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5192 peer_address = NULL;
5195 for (c=0; c<ats_count; c++)
5197 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5199 distance = ntohl(ats_data[c].value);
5203 /* notify ATS about incoming data */
5204 //ats_notify_ats_data(peer, ats_data);
5207 if (message != NULL)
5209 if ( (session != NULL) ||
5210 (sender_address != NULL) )
5211 peer_address = add_peer_address (n,
5215 sender_address_len);
5216 if (peer_address != NULL)
5219 update_addr_ats(peer_address, ats_data, ats_count);
5220 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5222 peer_address->distance = distance;
5223 if (GNUNET_YES == peer_address->validated)
5224 mark_address_connected (peer_address);
5225 peer_address->timeout
5227 GNUNET_TIME_relative_to_absolute
5228 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5229 schedule_next_ping (peer_address);
5231 /* update traffic received amount ... */
5232 msize = ntohs (message->size);
5234 GNUNET_STATISTICS_update (stats,
5235 gettext_noop ("# bytes received from other peers"),
5238 n->distance = distance;
5240 GNUNET_TIME_relative_to_absolute
5241 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5242 GNUNET_SCHEDULER_cancel (n->timeout_task);
5244 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5245 &neighbour_timeout_task, n);
5246 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5248 /* dropping message due to frequent inbound volume violations! */
5249 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5250 GNUNET_ERROR_TYPE_BULK,
5252 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5253 n->in_tracker.available_bytes_per_s__,
5254 n->quota_violation_count);
5255 GNUNET_STATISTICS_update (stats,
5256 gettext_noop ("# bandwidth quota violations by other peers"),
5259 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5261 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5262 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5264 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5265 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5266 /* Force ressource and quality update */
5269 ats->modified_resources = GNUNET_YES;
5270 ats->modified_quality = GNUNET_YES;
5272 /* Force cost update */
5274 ats->modified_resources = GNUNET_YES;
5275 /* Force quality update */
5277 ats->modified_quality = GNUNET_YES;
5278 /* Force full rebuild */
5280 ats->modified_addr = GNUNET_YES;
5284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5285 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5286 ntohs (message->type),
5287 ntohs (message->size),
5290 switch (ntohs (message->type))
5292 case GNUNET_MESSAGE_TYPE_HELLO:
5293 GNUNET_STATISTICS_update (stats,
5294 gettext_noop ("# HELLO messages received from other peers"),
5297 process_hello (plugin, message);
5299 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5300 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5302 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5303 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5305 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5308 handle_payload_message (message, n);
5312 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5313 if (ret.rel_value > 0)
5315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5316 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5317 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5318 (unsigned int) n->in_tracker.available_bytes_per_s__,
5319 (unsigned long long) ret.rel_value);
5320 GNUNET_STATISTICS_update (stats,
5321 gettext_noop ("# ms throttling suggested"),
5322 (int64_t) ret.rel_value,
5329 * Handle START-message. This is the first message sent to us
5330 * by any client which causes us to add it to our list.
5332 * @param cls closure (always NULL)
5333 * @param client identification of the client
5334 * @param message the actual message
5337 handle_start (void *cls,
5338 struct GNUNET_SERVER_Client *client,
5339 const struct GNUNET_MessageHeader *message)
5341 const struct StartMessage *start;
5342 struct TransportClient *c;
5343 struct ConnectInfoMessage * cim;
5344 struct NeighbourList *n;
5348 start = (const struct StartMessage*) message;
5350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5351 "Received `%s' request from client\n", "START");
5356 if (c->client == client)
5358 /* client already on our list! */
5360 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5365 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5366 (0 != memcmp (&start->self,
5368 sizeof (struct GNUNET_PeerIdentity))) )
5370 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5371 _("Rejecting control connection from peer `%s', which is not me!\n"),
5372 GNUNET_i2s (&start->self));
5373 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5376 c = GNUNET_malloc (sizeof (struct TransportClient));
5380 if (our_hello != NULL)
5383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5384 "Sending our own `%s' to new client\n", "HELLO");
5386 transmit_to_client (c,
5387 (const struct GNUNET_MessageHeader *) our_hello,
5389 /* tell new client about all existing connections */
5391 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5392 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5396 cim = GNUNET_malloc (size);
5397 cim->header.size = htons (size);
5398 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5399 cim->ats_count = htonl(ats_count);
5400 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5401 (&(cim->ats))[2].value = htonl (0);
5405 if (GNUNET_YES == n->received_pong)
5407 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5408 (&(cim->ats))[0].value = htonl (n->distance);
5409 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5410 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5412 transmit_to_client (c, &cim->header, GNUNET_NO);
5418 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5423 * Handle HELLO-message.
5425 * @param cls closure (always NULL)
5426 * @param client identification of the client
5427 * @param message the actual message
5430 handle_hello (void *cls,
5431 struct GNUNET_SERVER_Client *client,
5432 const struct GNUNET_MessageHeader *message)
5436 GNUNET_STATISTICS_update (stats,
5437 gettext_noop ("# HELLOs received from clients"),
5440 ret = process_hello (NULL, message);
5441 GNUNET_SERVER_receive_done (client, ret);
5446 * Closure for 'transmit_client_message'; followed by
5447 * 'msize' bytes of the actual message.
5449 struct TransmitClientMessageContext
5452 * Client on whom's behalf we are sending.
5454 struct GNUNET_SERVER_Client *client;
5457 * Timeout for the transmission.
5459 struct GNUNET_TIME_Absolute timeout;
5467 * Size of the message in bytes.
5474 * Schedule transmission of a message we got from a client to a peer.
5476 * @param cls the 'struct TransmitClientMessageContext*'
5477 * @param n destination, or NULL on error (in that case, drop the message)
5480 transmit_client_message (void *cls,
5481 struct NeighbourList *n)
5483 struct TransmitClientMessageContext *tcmc = cls;
5484 struct TransportClient *tc;
5487 while ((tc != NULL) && (tc->client != tcmc->client))
5492 transmit_to_peer (tc, NULL, tcmc->priority,
5493 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5495 tcmc->msize, GNUNET_NO, n);
5497 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5498 GNUNET_SERVER_client_drop (tcmc->client);
5504 * Handle SEND-message.
5506 * @param cls closure (always NULL)
5507 * @param client identification of the client
5508 * @param message the actual message
5511 handle_send (void *cls,
5512 struct GNUNET_SERVER_Client *client,
5513 const struct GNUNET_MessageHeader *message)
5515 const struct OutboundMessage *obm;
5516 const struct GNUNET_MessageHeader *obmm;
5517 struct TransmitClientMessageContext *tcmc;
5521 size = ntohs (message->size);
5523 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5526 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5529 GNUNET_STATISTICS_update (stats,
5530 gettext_noop ("# payload received for other peers"),
5533 obm = (const struct OutboundMessage *) message;
5534 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5535 msize = size - sizeof (struct OutboundMessage);
5537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5538 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5539 "SEND", GNUNET_i2s (&obm->peer),
5543 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5544 tcmc->client = client;
5545 tcmc->priority = ntohl (obm->priority);
5546 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5547 tcmc->msize = msize;
5548 /* FIXME: this memcpy can be up to 7% of our total runtime */
5549 memcpy (&tcmc[1], obmm, msize);
5550 GNUNET_SERVER_client_keep (client);
5551 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5552 &transmit_client_message,
5558 * Handle request connect message
5560 * @param cls closure (always NULL)
5561 * @param client identification of the client
5562 * @param message the actual message
5565 handle_request_connect (void *cls,
5566 struct GNUNET_SERVER_Client *client,
5567 const struct GNUNET_MessageHeader *message)
5569 const struct TransportRequestConnectMessage *trcm =
5570 (const struct TransportRequestConnectMessage *) message;
5572 GNUNET_STATISTICS_update (stats,
5573 gettext_noop ("# REQUEST CONNECT messages received"),
5576 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5577 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5579 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5583 * Handle SET_QUOTA-message.
5585 * @param cls closure (always NULL)
5586 * @param client identification of the client
5587 * @param message the actual message
5590 handle_set_quota (void *cls,
5591 struct GNUNET_SERVER_Client *client,
5592 const struct GNUNET_MessageHeader *message)
5594 const struct QuotaSetMessage *qsm =
5595 (const struct QuotaSetMessage *) message;
5596 struct NeighbourList *n;
5598 GNUNET_STATISTICS_update (stats,
5599 gettext_noop ("# SET QUOTA messages received"),
5602 n = find_neighbour (&qsm->peer);
5605 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5606 GNUNET_STATISTICS_update (stats,
5607 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5614 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5616 (unsigned int) ntohl (qsm->quota.value__),
5617 (unsigned int) n->in_tracker.available_bytes_per_s__,
5618 GNUNET_i2s (&qsm->peer));
5620 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5622 if (0 == ntohl (qsm->quota.value__))
5624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5625 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5627 disconnect_neighbour (n, GNUNET_NO);
5629 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5634 * Take the given address and append it to the set of results sent back to
5637 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5638 * @param address the resolved name, NULL to indicate the last response
5641 transmit_address_to_client (void *cls, const char *address)
5643 struct GNUNET_SERVER_TransmitContext *tc = cls;
5646 if (NULL == address)
5649 slen = strlen (address) + 1;
5651 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5652 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5653 if (NULL == address)
5654 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5659 * Handle AddressLookup-message.
5661 * @param cls closure (always NULL)
5662 * @param client identification of the client
5663 * @param message the actual message
5666 handle_address_lookup (void *cls,
5667 struct GNUNET_SERVER_Client *client,
5668 const struct GNUNET_MessageHeader *message)
5670 const struct AddressLookupMessage *alum;
5671 struct TransportPlugin *lsPlugin;
5672 const char *nameTransport;
5673 const char *address;
5675 struct GNUNET_SERVER_TransmitContext *tc;
5676 struct GNUNET_TIME_Absolute timeout;
5677 struct GNUNET_TIME_Relative rtimeout;
5680 size = ntohs (message->size);
5681 if (size < sizeof (struct AddressLookupMessage))
5683 GNUNET_break_op (0);
5684 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5687 alum = (const struct AddressLookupMessage *) message;
5688 uint32_t addressLen = ntohl (alum->addrlen);
5689 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5691 GNUNET_break_op (0);
5692 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5695 address = (const char *) &alum[1];
5696 nameTransport = (const char *) &address[addressLen];
5698 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5700 GNUNET_break_op (0);
5701 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5704 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5705 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5706 numeric = ntohl (alum->numeric_only);
5707 lsPlugin = find_transport (nameTransport);
5708 if (NULL == lsPlugin)
5710 tc = GNUNET_SERVER_transmit_context_create (client);
5711 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5712 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5713 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5716 tc = GNUNET_SERVER_transmit_context_create (client);
5717 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5719 address, addressLen,
5722 &transmit_address_to_client, tc);
5727 * Setup the environment for this plugin.
5730 create_environment (struct TransportPlugin *plug)
5732 plug->env.cfg = cfg;
5733 plug->env.my_identity = &my_identity;
5734 plug->env.our_hello = &our_hello;
5735 plug->env.cls = plug;
5736 plug->env.receive = &plugin_env_receive;
5737 plug->env.notify_address = &plugin_env_notify_address;
5738 plug->env.session_end = &plugin_env_session_end;
5739 plug->env.max_connections = max_connect_per_transport;
5740 plug->env.stats = stats;
5745 * Start the specified transport (load the plugin).
5748 start_transport (struct GNUNET_SERVER_Handle *server,
5751 struct TransportPlugin *plug;
5754 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5755 _("Loading `%s' transport plugin\n"), name);
5756 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5757 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5758 create_environment (plug);
5759 plug->short_name = GNUNET_strdup (name);
5760 plug->lib_name = libname;
5761 plug->next = plugins;
5763 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5764 if (plug->api == NULL)
5766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5767 _("Failed to load transport plugin for `%s'\n"), name);
5768 GNUNET_free (plug->short_name);
5769 plugins = plug->next;
5770 GNUNET_free (libname);
5777 * Called whenever a client is disconnected. Frees our
5778 * resources associated with that client.
5780 * @param cls closure
5781 * @param client identification of the client
5784 client_disconnect_notification (void *cls,
5785 struct GNUNET_SERVER_Client *client)
5787 struct TransportClient *pos;
5788 struct TransportClient *prev;
5789 struct ClientMessageQueueEntry *mqe;
5790 struct Blacklisters *bl;
5791 struct BlacklistCheck *bc;
5796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5797 "Client disconnected, cleaning up.\n");
5799 /* clean up blacklister */
5803 if (bl->client == client)
5808 if (bc->bl_pos == bl)
5810 bc->bl_pos = bl->next;
5813 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5816 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5817 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5823 GNUNET_CONTAINER_DLL_remove (bl_head,
5826 GNUNET_SERVER_client_drop (bl->client);
5832 /* clean up 'normal' clients */
5835 while ((pos != NULL) && (pos->client != client))
5842 while (NULL != (mqe = pos->message_queue_head))
5844 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5845 pos->message_queue_tail,
5847 pos->message_count--;
5851 clients = pos->next;
5853 prev->next = pos->next;
5854 if (GNUNET_YES == pos->tcs_pending)
5859 if (pos->th != NULL)
5861 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5864 GNUNET_break (0 == pos->message_count);
5870 * Function called when the service shuts down. Unloads our plugins
5871 * and cancels pending validations.
5873 * @param cls closure, unused
5874 * @param tc task context (unused)
5877 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5879 struct TransportPlugin *plug;
5880 struct OwnAddressList *al;
5881 struct CheckHelloValidatedContext *chvc;
5883 while (neighbours != NULL)
5885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5886 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5888 disconnect_neighbour (neighbours, GNUNET_NO);
5891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5892 "Transport service is unloading plugins...\n");
5894 while (NULL != (plug = plugins))
5896 plugins = plug->next;
5897 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5899 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5900 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5902 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5903 GNUNET_free (plug->lib_name);
5904 GNUNET_free (plug->short_name);
5905 while (NULL != (al = plug->addresses))
5907 plug->addresses = al->next;
5912 if (my_private_key != NULL)
5913 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5914 GNUNET_free_non_null (our_hello);
5916 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5919 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5920 validation_map = NULL;
5924 /* free 'chvc' data structure */
5925 while (NULL != (chvc = chvc_head))
5927 chvc_head = chvc->next;
5928 if (chvc->piter != NULL)
5930 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5931 GNUNET_STATISTICS_update (stats,
5932 gettext_noop ("# outstanding peerinfo iterate requests"),
5938 GNUNET_assert (chvc->ve_count == 0);
5945 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5948 if (peerinfo != NULL)
5950 GNUNET_PEERINFO_disconnect (peerinfo);
5953 /* Can we assume those are gone by now, or do we need to clean up
5955 GNUNET_break (bl_head == NULL);
5956 GNUNET_break (bc_head == NULL);
5960 static int ats_evaluate_results (int result, int solution, char * problem)
5962 int cont = GNUNET_NO;
5963 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5965 error_kind = GNUNET_ERROR_TYPE_ERROR;
5969 case GLP_ESTOP : /* search terminated by application */
5970 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5972 case GLP_EITLIM : /* iteration limit exceeded */
5973 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5976 case GLP_ETMLIM : /* time limit exceeded */
5977 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5979 case GLP_ENOPFS : /* no primal feasible solution */
5980 case GLP_ENODFS : /* no dual feasible solution */
5981 GNUNET_log (error_kind, "%s No feasible solution", problem);
5984 case GLP_EBADB : /* invalid basis */
5985 case GLP_ESING : /* singular matrix */
5986 case GLP_ECOND : /* ill-conditioned matrix */
5987 case GLP_EBOUND : /* invalid bounds */
5988 case GLP_EFAIL : /* solver failed */
5989 case GLP_EOBJLL : /* objective lower limit reached */
5990 case GLP_EOBJUL : /* objective upper limit reached */
5991 case GLP_EROOT : /* root LP optimum not provided */
5992 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5996 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
6002 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
6005 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
6009 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"));
6013 GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem, (0==strcmp(problem,"LP")?"":"integer "));
6016 GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
6019 GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
6027 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)
6033 if (ats->builtin_mlp_presolver == GNUNET_NO)
6036 glp_init_smcp(&opt_lp);
6038 opt_lp.msg_lev = GLP_MSG_ALL;
6040 opt_lp.msg_lev = GLP_MSG_OFF;
6042 result = glp_simplex(ats->prob, &opt_lp);
6043 solution = glp_get_status (ats->prob);
6045 if (((ats->builtin_mlp_presolver == GNUNET_NO) && (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))) || (ats->builtin_mlp_presolver == GNUNET_YES))
6049 glp_init_iocp(&opt_mlp);
6050 /* maximum duration */
6051 if (ats->builtin_mlp_presolver == GNUNET_YES)
6052 opt_mlp.presolve = GLP_ON;
6053 opt_mlp.tm_lim = max_dur;
6056 opt_mlp.msg_lev = GLP_MSG_ALL;
6058 opt_mlp.msg_lev = GLP_MSG_OFF;
6060 result = glp_intopt (ats->prob, &opt_mlp);
6061 solution = glp_mip_status (ats->prob);
6062 stat->solution = solution;
6063 stat->valid = GNUNET_NO;
6064 if (ats_evaluate_results(result, solution, "MLP") == GNUNET_YES)
6065 stat->valid = GNUNET_YES;
6070 int error = GNUNET_NO;
6072 struct ATS_mechanism *t = NULL;
6073 for (c=1; c<= (c_peers); c++ )
6076 t = peers[c].m_head;
6079 bw = glp_get_col_prim(prob, t->col_index);
6083 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);
6085 if (check ==GNUNET_YES)
6087 glp_write_sol(prob, "invalid_solution.mlp");
6088 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6089 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6092 if (check ==GNUNET_NO)
6100 if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
6103 for (c=1; c<= available_quality_metrics; c++ )
6105 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));
6107 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));
6108 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));
6109 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));
6110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value: %f\n", glp_mip_obj_val(ats->prob));
6115 static void ats_delete_problem ()
6119 for (c=0; c< (ats->stat).c_mechs; c++)
6120 GNUNET_free_non_null (ats->mechanisms[c].rc);
6122 if (ats->mechanisms!=NULL)
6124 GNUNET_free(ats->mechanisms);
6125 ats->mechanisms = NULL;
6127 if (ats->peers!=NULL)
6129 GNUNET_free(ats->peers);
6133 if (ats->prob != NULL)
6135 glp_delete_prob(ats->prob);
6139 ats->stat.begin_cr = GNUNET_SYSERR;
6140 ats->stat.begin_qm = GNUNET_SYSERR;
6141 ats->stat.c_mechs = 0;
6142 ats->stat.c_peers = 0;
6143 ats->stat.end_cr = GNUNET_SYSERR;
6144 ats->stat.end_qm = GNUNET_SYSERR;
6145 ats->stat.solution = GNUNET_SYSERR;
6146 ats->stat.valid = GNUNET_SYSERR;
6149 static void ats_update_problem_qm ()
6154 int c_q_metrics = available_quality_metrics;
6156 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6157 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6161 row_index = ats->stat.begin_qm;
6163 for (c=1; c <= c_q_metrics; c++)
6168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6171 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6172 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6174 ja[array_index] = c2;
6176 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6179 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6180 if (v1 < 1) v0 = 0.1;
6181 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6182 if (v1 < 1) v0 = 0.1;
6183 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6184 if (v1 < 1) v0 = 0.1;
6185 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6188 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6191 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6193 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6195 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6197 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6199 value = (double) 10 / value;
6203 ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6205 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]);
6209 ja[array_index] = ats->stat.col_qm + c - 1;
6210 ar[array_index] = -1;
6213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6215 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6221 GNUNET_free_non_null (ja);
6222 GNUNET_free_non_null (ar);
6227 static void ats_update_problem_cr ()
6233 double ct_max, ct_min;
6235 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6236 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6238 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6239 row_index = ats->stat.begin_cr;
6241 for (c=0; c<available_ressources; c++)
6243 ct_max = ressources[c].c_max;
6244 ct_min = ressources[c].c_min;
6246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6248 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6250 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6253 ja[array_index] = c2;
6254 value = ats->mechanisms[c2].addr->ressources[c].c;
6255 ar[array_index] = value;
6257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6261 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6267 GNUNET_free_non_null (ja);
6268 GNUNET_free_non_null (ar);
6271 static void ats_update_problem_qm_TEST ()
6276 int old_ja[ats->stat.c_mechs + 2];
6277 double old_ar[ats->stat.c_mechs + 2];
6281 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6282 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
6286 row_index = ats->stat.begin_qm;
6288 for (c=0; c<available_quality_metrics; c++)
6291 c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
6293 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6295 for (c2=1; c2<=c_old; c2++)
6297 ja[c2] = old_ja[c2];
6298 if ((changed < 3) && (c2>2))
6300 ar[c2] = old_ar[c2] + 500 - changed;
6304 ar[c2] = old_ar[c2];
6306 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]);
6309 glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
6315 GNUNET_free_non_null (ja);
6316 GNUNET_free_non_null (ar);
6319 /** solve the bandwidth distribution problem
6320 * @param max_it maximum iterations
6321 * @param max_dur maximum duration in ms
6322 * @param D weight for diversity
6323 * @param U weight for utility
6324 * @param R weight for relativity
6325 * @param v_b_min minimal bandwidth per peer
6326 * @param v_n_min minimum number of connections
6327 * @param stat result struct
6328 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6330 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
6332 if (ats->prob != NULL)
6333 glp_delete_prob(ats->prob);
6335 ats->prob = glp_create_prob();
6341 int c_c_ressources = available_ressources;
6342 int c_q_metrics = available_quality_metrics;
6344 double M = VERY_BIG_DOUBLE_VALUE;
6345 double Q[c_q_metrics+1];
6346 for (c=1; c<=c_q_metrics; c++)
6351 struct NeighbourList *next = neighbours;
6354 struct ReadyList *r_next = next->plugins;
6355 while (r_next != NULL)
6357 struct ForeignAddressList * a_next = r_next->addresses;
6358 while (a_next != NULL)
6361 a_next = a_next->next;
6363 r_next = r_next->next;
6372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6374 stat->valid = GNUNET_NO;
6377 return GNUNET_SYSERR;
6380 ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6381 ats->peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6383 struct ATS_mechanism * mechanisms = ats->mechanisms;
6384 struct ATS_peer * peers = ats->peers;
6391 peers[c_peers].peer = next->id;
6392 peers[c_peers].m_head = NULL;
6393 peers[c_peers].m_tail = NULL;
6395 peers[c_peers].f = 1.0 / c_mechs;
6397 struct ReadyList *r_next = next->plugins;
6398 while (r_next != NULL)
6400 struct ForeignAddressList * a_next = r_next->addresses;
6401 while (a_next != NULL)
6403 mechanisms[c_mechs].addr = a_next;
6404 mechanisms[c_mechs].col_index = c_mechs;
6405 mechanisms[c_mechs].peer = &peers[c_peers];
6406 mechanisms[c_mechs].next = NULL;
6407 mechanisms[c_mechs].plugin = r_next->plugin;
6409 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6411 a_next = a_next->next;
6413 r_next = r_next->next;
6421 if (v_n_min > c_peers)
6425 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);
6428 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6431 int * ia = GNUNET_malloc (size * sizeof (int));
6432 int * ja = GNUNET_malloc (size * sizeof (int));
6433 double * ar = GNUNET_malloc(size* sizeof (double));
6435 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6436 glp_set_obj_dir(ats->prob, GLP_MAX);
6438 /* adding columns */
6440 glp_add_cols(ats->prob, 2 * c_mechs);
6441 /* adding b_t cols */
6442 for (c=1; c <= c_mechs; c++)
6445 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6446 glp_set_col_name(ats->prob, c, name);
6448 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6449 glp_set_obj_coef(ats->prob, c, 0);
6452 /* adding n_t cols */
6453 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6455 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6456 glp_set_col_name(ats->prob, c, name);
6458 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6459 glp_set_col_kind(ats->prob, c, GLP_IV);
6460 glp_set_obj_coef(ats->prob, c, 0);
6463 /* feasibility constraints */
6464 /* Constraint 1: one address per peer*/
6466 glp_add_rows(ats->prob, c_peers);
6467 for (c=1; c<=c_peers; c++)
6469 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6471 struct ATS_mechanism *m = peers[c].m_head;
6474 ia[array_index] = row_index;
6475 ja[array_index] = (c_mechs + m->col_index);
6476 ar[array_index] = 1;
6478 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6486 /* Constraint 2: only active mechanism gets bandwidth assigned */
6487 glp_add_rows(ats->prob, c_mechs);
6488 for (c=1; c<=c_mechs; c++)
6490 /* b_t - n_t * M <= 0 */
6492 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6494 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6496 ia[array_index] = row_index;
6497 ja[array_index] = mechanisms[c].col_index;
6498 ar[array_index] = 1;
6500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6503 ia[array_index] = row_index;
6504 ja[array_index] = c_mechs + mechanisms[c].col_index;
6505 ar[array_index] = -M;
6507 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6513 /* Constraint 3: minimum bandwidth*/
6514 glp_add_rows(ats->prob, c_mechs);
6515 for (c=1; c<=c_mechs; c++)
6517 /* b_t - n_t * b_min <= 0 */
6519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6521 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6523 ia[array_index] = row_index;
6524 ja[array_index] = mechanisms[c].col_index;
6525 ar[array_index] = 1;
6527 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6530 ia[array_index] = row_index;
6531 ja[array_index] = c_mechs + mechanisms[c].col_index;
6532 ar[array_index] = -v_b_min;
6534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6540 /* Constraint 4: max ressource capacity */
6541 /* V cr: bt * ct_r <= cr_max
6543 glp_add_rows(ats->prob, available_ressources);
6544 double ct_max = VERY_BIG_DOUBLE_VALUE;
6545 double ct_min = 0.0;
6547 stat->begin_cr = array_index;
6549 for (c=0; c<available_ressources; c++)
6551 ct_max = ressources[c].c_max;
6552 ct_min = ressources[c].c_min;
6554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6556 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6558 for (c2=1; c2<=c_mechs; c2++)
6561 ia[array_index] = row_index;
6562 ja[array_index] = c2;
6563 value = mechanisms[c2].addr->ressources[c].c;
6564 ar[array_index] = value;
6566 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6572 stat->end_cr = array_index--;
6574 /* Constraint 5: min number of connections*/
6575 glp_add_rows(ats->prob, 1);
6576 for (c=1; c<=c_mechs; c++)
6578 // b_t - n_t * b_min >= 0
6580 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6582 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6584 ia[array_index] = row_index;
6585 ja[array_index] = c_mechs + mechanisms[c].col_index;
6586 ar[array_index] = 1;
6588 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6594 // optimisation constraints
6598 // Constraint 6: optimize for diversity
6600 col_d = glp_add_cols(ats->prob, 1);
6601 stat->col_d = col_d;
6602 //GNUNET_assert (col_d == (2*c_mechs) + 1);
6603 glp_set_col_name(ats->prob, col_d, "d");
6604 glp_set_obj_coef(ats->prob, col_d, D);
6605 glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
6606 glp_add_rows(ats->prob, 1);
6608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6610 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6611 for (c=1; c<=c_mechs; c++)
6613 // b_t - n_t * b_min >= 0
6614 ia[array_index] = row_index;
6615 ja[array_index] = c_mechs + mechanisms[c].col_index;
6616 ar[array_index] = 1;
6618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6622 ia[array_index] = row_index;
6623 ja[array_index] = col_d;
6624 ar[array_index] = -1;
6626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6632 // Constraint 7: optimize for quality
6634 col_qm = glp_add_cols(ats->prob, c_q_metrics);
6635 stat->col_qm = col_qm;
6636 //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
6637 for (c=0; c< c_q_metrics; c++)
6639 GNUNET_asprintf(&name, "Q_%s",qm[c].name);
6640 glp_set_col_name(ats->prob, col_qm + c, name);
6641 glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
6643 glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
6645 glp_add_rows(ats->prob, available_quality_metrics);
6646 stat->begin_qm = row_index;
6647 for (c=1; c <= c_q_metrics; c++)
6650 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6653 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6654 for (c2=1; c2<=c_mechs; c2++)
6657 ia[array_index] = row_index;
6658 ja[array_index] = c2;
6659 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6662 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6663 if (v1 < 1) v0 = 0.1;
6664 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6665 if (v1 < 1) v0 = 0.1;
6666 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6667 if (v1 < 1) v0 = 0.1;
6668 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6671 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6674 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6676 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6678 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6680 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6682 value = (double) 10 / value;
6686 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6688 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]);
6693 ia[array_index] = row_index;
6694 ja[array_index] = col_qm + c - 1;
6695 ar[array_index] = -1;
6697 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6702 stat->end_qm = row_index-1;
6704 // Constraint 8: optimize bandwidth utility
6706 col_u = glp_add_cols(ats->prob, 1);
6707 stat->col_u = col_u;
6708 //GNUNET_assert (col_u == (2*c_mechs) + 2);
6709 glp_set_col_name(ats->prob, col_u, "u");
6710 glp_set_obj_coef(ats->prob, col_u, U);
6711 glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
6712 glp_add_rows(ats->prob, 1);
6714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6716 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6717 for (c=1; c<=c_mechs; c++)
6719 ia[array_index] = row_index;
6720 ja[array_index] = c;
6721 ar[array_index] = mechanisms[c].peer->f;
6723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6727 ia[array_index] = row_index;
6728 ja[array_index] = col_u;
6729 ar[array_index] = -1;
6731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6737 // Constraint 9: optimize relativity
6739 col_r = glp_add_cols(ats->prob, 1);
6740 stat->col_r = col_r;
6741 //GNUNET_assert (col_r == (2*c_mechs) + 3);
6742 glp_set_col_name(ats->prob, col_r, "r");
6743 glp_set_obj_coef(ats->prob, col_r, R);
6744 glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
6745 glp_add_rows(ats->prob, c_peers);
6746 for (c=1; c<=c_peers; c++)
6748 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6750 struct ATS_mechanism *m = peers[c].m_head;
6753 ia[array_index] = row_index;
6754 ja[array_index] = m->col_index;
6755 ar[array_index] = 1 / mechanisms[c].peer->f;
6757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6762 ia[array_index] = row_index;
6763 ja[array_index] = col_r;
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]);
6773 /* Loading the matrix */
6774 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6776 stat->c_mechs = c_mechs;
6777 stat->c_peers = c_peers;
6779 stat->valid = GNUNET_YES;
6791 void ats_notify_ats_data (
6792 const struct GNUNET_PeerIdentity *peer,
6793 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6796 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6798 ats_calculate_bandwidth_distribution(ats);
6804 ats_calculate_bandwidth_distribution ()
6807 struct GNUNET_TIME_Absolute start;
6808 struct GNUNET_TIME_Relative creation;
6809 struct GNUNET_TIME_Relative solving;
6810 char *text = "unmodified";
6812 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6813 if (delta.rel_value < ats->min_delta.rel_value)
6816 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6822 if (INT_MAX < ats->max_exec_duration.rel_value)
6825 dur = (int) ats->max_exec_duration.rel_value;
6827 start = GNUNET_TIME_absolute_get();
6828 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6831 ats_delete_problem ();
6832 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
6834 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);
6837 else if ((ats->modified_addr == GNUNET_NO) && (ats->modified_resources == GNUNET_YES))
6839 ats_update_problem_cr();
6840 text = "modified resources";
6842 else if ((ats->modified_addr == GNUNET_NO) && (ats->modified_quality == GNUNET_YES))
6844 ats_update_problem_qm();
6845 ats_update_problem_qm_TEST ();
6846 text = "modified quality";
6849 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6852 creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6853 start = GNUNET_TIME_absolute_get();
6855 if (ats->stat.valid == GNUNET_YES)
6857 ats->stat.solution = GNUNET_SYSERR;
6858 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
6859 //if (ats->stat.solution != 5)
6860 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem solution is not optimal: %i\n", ats->stat.solution);
6863 solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6865 if (ats->stat.valid == GNUNET_YES)
6869 //if (ats->stat.c_peers > 1)
6871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP %s: creation time in [ms] %llu execution time in [ms] %llu for %i mechanisms\n", text, creation.rel_value, solving.rel_value, ats->stat.c_mechs);
6874 GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
6875 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
6876 GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
6877 GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
6878 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6879 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6880 GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
6881 else if ((ats->modified_resources == GNUNET_YES) && (ats->modified_quality == GNUNET_NO))
6882 GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
6883 else if ((ats->modified_resources == GNUNET_NO) && (ats->modified_quality == GNUNET_YES))
6884 GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
6885 else if ((ats->modified_resources == GNUNET_YES) && (ats->modified_quality == GNUNET_YES))
6886 GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
6888 GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
6892 else if (ats->stat.valid == GNUNET_NO)
6894 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6898 if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_peers > 1))
6901 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);
6902 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6903 glp_write_lp (ats->prob, NULL, filename);
6904 GNUNET_free (filename);
6906 if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_peers > 1))
6909 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol", ats->stat.c_peers, ats->stat.c_mechs, GNUNET_TIME_absolute_get().abs_value);
6910 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6911 glp_print_sol (ats->prob, filename);
6912 GNUNET_free (filename);
6915 ats->last = GNUNET_TIME_absolute_get();
6917 ats->modified_addr = GNUNET_NO;
6918 ats->modified_resources = GNUNET_NO;
6919 ats->modified_quality = GNUNET_NO;
6926 ats_schedule_calculation (void *cls,
6927 const struct GNUNET_SCHEDULER_TaskContext *tc)
6929 struct ATS_info *ats = (struct ATS_info *) cls;
6933 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6934 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6938 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6941 ats_calculate_bandwidth_distribution (ats);
6943 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6944 &ats_schedule_calculation, ats);
6950 unsigned long long value;
6953 ats = GNUNET_malloc(sizeof (struct ATS_info));
6955 ats->min_delta = ATS_MIN_INTERVAL;
6956 ats->exec_intervall = ATS_EXEC_INTERVAL;
6957 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6958 ats->max_iterations = ATS_MAX_ITERATIONS;
6959 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active\n");
6969 ats->v_b_min = 64000;
6975 /* loading cost ressources */
6976 for (c=0; c<available_ressources; c++)
6978 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6979 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6981 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6986 ressources[c].c_max = value;
6989 GNUNET_free (section);
6990 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6991 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6993 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6996 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6998 ressources[c].c_min = value;
7001 GNUNET_free (section);
7004 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
7005 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
7007 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
7008 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
7010 ats->builtin_mlp_presolver = GNUNET_NO;
7011 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "BUILTIN_PRESOLVER"))
7013 ats->builtin_mlp_presolver = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","BUILTIN_PRESOLVER");
7016 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
7020 static void ats_shutdown ()
7023 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
7025 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
7026 GNUNET_SCHEDULER_cancel(ats->ats_task);
7027 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7029 ats_delete_problem ();
7035 void ats_notify_peer_connect (
7036 const struct GNUNET_PeerIdentity *peer,
7037 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
7040 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
7043 //update_addr_ats();
7044 ats->modified_addr = GNUNET_YES;
7046 ats_calculate_bandwidth_distribution(ats);
7049 void ats_notify_peer_disconnect (
7050 const struct GNUNET_PeerIdentity *peer)
7053 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
7056 ats->modified_addr = GNUNET_YES;
7058 ats_calculate_bandwidth_distribution (ats);
7061 struct ForeignAddressList * ats_get_preferred_address (
7062 struct NeighbourList *n)
7065 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
7067 struct ReadyList *next = n->plugins;
7068 while (next != NULL)
7071 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
7075 return find_ready_address(n);
7079 * Initiate transport service.
7081 * @param cls closure
7082 * @param server the initialized server
7083 * @param c configuration to use
7087 struct GNUNET_SERVER_Handle *server,
7088 const struct GNUNET_CONFIGURATION_Handle *c)
7090 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
7091 {&handle_start, NULL,
7092 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
7093 {&handle_hello, NULL,
7094 GNUNET_MESSAGE_TYPE_HELLO, 0},
7095 {&handle_send, NULL,
7096 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
7097 {&handle_request_connect, NULL,
7098 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
7099 {&handle_set_quota, NULL,
7100 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
7101 {&handle_address_lookup, NULL,
7102 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
7104 {&handle_blacklist_init, NULL,
7105 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
7106 {&handle_blacklist_reply, NULL,
7107 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
7113 unsigned long long tneigh;
7117 stats = GNUNET_STATISTICS_create ("transport", cfg);
7118 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
7119 /* parse configuration */
7121 GNUNET_CONFIGURATION_get_value_number (c,
7126 GNUNET_CONFIGURATION_get_value_filename (c,
7128 "HOSTKEY", &keyfile)))
7130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7132 ("Transport service is lacking key configuration settings. Exiting.\n"));
7133 GNUNET_SCHEDULER_shutdown ();
7136 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7139 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7140 validation_map = NULL;
7144 max_connect_per_transport = (uint32_t) tneigh;
7145 peerinfo = GNUNET_PEERINFO_connect (cfg);
7146 if (peerinfo == NULL)
7148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7149 _("Could not access PEERINFO service. Exiting.\n"));
7150 GNUNET_SCHEDULER_shutdown ();
7153 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7156 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7157 validation_map = NULL;
7158 GNUNET_free (keyfile);
7161 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
7162 GNUNET_free (keyfile);
7163 if (my_private_key == NULL)
7165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7167 ("Transport service could not access hostkey. Exiting.\n"));
7168 GNUNET_SCHEDULER_shutdown ();
7171 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7174 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7175 validation_map = NULL;
7178 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
7179 GNUNET_CRYPTO_hash (&my_public_key,
7180 sizeof (my_public_key), &my_identity.hashPubKey);
7181 /* setup notification */
7182 GNUNET_SERVER_disconnect_notify (server,
7183 &client_disconnect_notification, NULL);
7184 /* load plugins... */
7187 GNUNET_CONFIGURATION_get_value_string (c,
7188 "TRANSPORT", "PLUGINS", &plugs))
7190 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7191 _("Starting transport plugins `%s'\n"), plugs);
7192 pos = strtok (plugs, " ");
7195 start_transport (server, pos);
7197 pos = strtok (NULL, " ");
7199 GNUNET_free (plugs);
7201 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
7202 &shutdown_task, NULL);
7209 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7211 /* If we have a blacklist file, read from it */
7212 read_blacklist_file(cfg);
7213 /* process client requests */
7214 GNUNET_SERVER_add_handlers (server, handlers);
7219 * The main function for the transport service.
7221 * @param argc number of arguments from the command line
7222 * @param argv command line arguments
7223 * @return 0 ok, 1 on error
7226 main (int argc, char *const *argv)
7228 a2s (NULL, NULL, 0); /* make compiler happy */
7229 return (GNUNET_OK ==
7230 GNUNET_SERVICE_run (argc,
7233 GNUNET_SERVICE_OPTION_NONE,
7234 &run, NULL)) ? 0 : 1;
7237 /* end of gnunet-service-transport.c */