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 * Maximum number of LP iterations per calculation
1041 * Dump problem to a file?
1046 * Dump solution to a file
1051 * Ressource costs or quality metrics changed
1052 * update problem before solving
1054 int modified_resources;
1057 * Ressource costs or quality metrics changed, update matrix
1058 * update problem before solving
1060 int modified_quality;
1063 * Peers have connected or disconnected
1064 * problem has to be recreated
1084 * Minimum bandwidth per peer
1089 * Minimum number of connections per peer
1096 * Our HELLO message.
1098 static struct GNUNET_HELLO_Message *our_hello;
1103 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1108 static struct GNUNET_PeerIdentity my_identity;
1113 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1116 * Our configuration.
1118 const struct GNUNET_CONFIGURATION_Handle *cfg;
1121 * Linked list of all clients to this service.
1123 static struct TransportClient *clients;
1126 * All loaded plugins.
1128 static struct TransportPlugin *plugins;
1131 * Handle to peerinfo service.
1133 static struct GNUNET_PEERINFO_Handle *peerinfo;
1136 * All known neighbours and their HELLOs.
1138 static struct NeighbourList *neighbours;
1141 * Number of neighbours we'd like to have.
1143 static uint32_t max_connect_per_transport;
1146 * Head of linked list.
1148 static struct CheckHelloValidatedContext *chvc_head;
1151 * Tail of linked list.
1153 static struct CheckHelloValidatedContext *chvc_tail;
1156 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1157 * of the given peer that we are currently validating).
1159 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1162 * Handle for reporting statistics.
1164 static struct GNUNET_STATISTICS_Handle *stats;
1167 * Handle for ats information
1169 static struct ATS_info *ats;
1171 struct ATS_quality_entry
1179 static struct ATS_quality_metric qm[] =
1181 {1, 1028, "QUALITY_NET_DISTANCE"},
1182 {2, 1034, "QUALITY_NET_DELAY"},
1184 static int available_quality_metrics = 2;
1188 * The peer specified by the given neighbour has timed-out or a plugin
1189 * has disconnected. We may either need to do nothing (other plugins
1190 * still up), or trigger a full disconnect and clean up. This
1191 * function updates our state and do the necessary notifications.
1192 * Also notifies our clients that the neighbour is now officially
1195 * @param n the neighbour list entry for the peer
1196 * @param check should we just check if all plugins
1197 * disconnected or must we ask all plugins to
1200 static void disconnect_neighbour (struct NeighbourList *n, int check);
1203 * Check the ready list for the given neighbour and if a plugin is
1204 * ready for transmission (and if we have a message), do so!
1206 * @param nexi target peer for which to transmit
1208 static void try_transmission_to_peer (struct NeighbourList *n);
1210 static void ats_shutdown ( );
1212 static void ats_notify_peer_connect (
1213 const struct GNUNET_PeerIdentity *peer,
1214 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
1216 static void ats_notify_peer_disconnect (
1217 const struct GNUNET_PeerIdentity *peer);
1220 static void ats_notify_ats_data (
1221 const struct GNUNET_PeerIdentity *peer,
1222 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1225 struct ForeignAddressList * ats_get_preferred_address (
1226 struct NeighbourList *n);
1229 ats_calculate_bandwidth_distribution ();
1232 * Find an entry in the neighbour list for a particular peer.
1234 * @return NULL if not found.
1236 static struct NeighbourList *
1237 find_neighbour (const struct GNUNET_PeerIdentity *key)
1239 struct NeighbourList *head = neighbours;
1241 while ((head != NULL) &&
1242 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1247 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1250 int set = GNUNET_NO;
1251 for (c=0; c<available_quality_metrics; c++)
1253 if (ats_index == qm[c].atis_index)
1255 fal->quality[c].values[0] = fal->quality[c].values[1];
1256 fal->quality[c].values[1] = fal->quality[c].values[2];
1257 fal->quality[c].values[2] = value;
1259 ats->modified_quality = GNUNET_YES;
1262 if (set == GNUNET_NO)
1264 for (c=0; c<available_ressources; c++)
1266 if (ats_index == ressources[c].atis_index)
1268 fal->ressources[c].c = value;
1270 ats->modified_resources = GNUNET_YES;
1278 static int update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1282 for (c1=0; c1<ats_count; c1++)
1284 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1290 * Find an entry in the transport list for a particular transport.
1292 * @return NULL if not found.
1294 static struct TransportPlugin *
1295 find_transport (const char *short_name)
1297 struct TransportPlugin *head = plugins;
1298 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1304 * Is a particular peer blacklisted for a particular transport?
1306 * @param peer the peer to check for
1307 * @param plugin the plugin used to connect to the peer
1309 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1312 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1315 if (plugin->blacklist != NULL)
1317 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "Peer `%s:%s' is blacklisted!\n",
1322 plugin->short_name, GNUNET_i2s (peer));
1325 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1335 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1337 struct TransportPlugin *plugin;
1339 plugin = find_transport(transport_name);
1340 if (plugin == NULL) /* Nothing to do */
1342 if (plugin->blacklist == NULL)
1343 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1344 GNUNET_assert(plugin->blacklist != NULL);
1345 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1347 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1352 * Read the blacklist file, containing transport:peer entries.
1353 * Provided the transport is loaded, set up hashmap with these
1354 * entries to blacklist peers by transport.
1358 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1365 struct GNUNET_PeerIdentity pid;
1367 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1368 unsigned int entries_found;
1369 char *transport_name;
1372 GNUNET_CONFIGURATION_get_value_filename (cfg,
1378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379 "Option `%s' in section `%s' not specified!\n",
1385 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1386 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1387 | GNUNET_DISK_PERM_USER_WRITE);
1388 if (0 != STAT (fn, &frstat))
1390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1391 _("Could not read blacklist file `%s'\n"), fn);
1395 if (frstat.st_size == 0)
1398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1399 _("Blacklist file `%s' is empty.\n"),
1405 /* FIXME: use mmap */
1406 data = GNUNET_malloc_large (frstat.st_size);
1407 GNUNET_assert(data != NULL);
1408 if (frstat.st_size !=
1409 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412 _("Failed to read blacklist from `%s'\n"), fn);
1419 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1421 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1422 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1425 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1428 if (colon_pos >= frstat.st_size)
1430 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1431 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1432 (unsigned long long) colon_pos);
1438 if (isspace( (unsigned char) data[colon_pos]))
1440 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1441 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1442 (unsigned long long) colon_pos);
1444 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1448 tsize = colon_pos - pos;
1449 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1451 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1452 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1453 (unsigned long long) colon_pos);
1462 transport_name = GNUNET_malloc(tsize + 1);
1463 memcpy(transport_name, &data[pos], tsize);
1464 pos = colon_pos + 1;
1466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1467 "Read transport name %s in blacklist file.\n",
1470 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1471 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1473 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1474 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1475 (unsigned long long) pos);
1477 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1479 GNUNET_free_non_null(transport_name);
1482 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1483 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1485 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1486 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1487 (unsigned long long) pos,
1492 if (0 != memcmp (&pid,
1494 sizeof (struct GNUNET_PeerIdentity)))
1497 add_peer_to_blacklist (&pid,
1502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1503 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1507 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1508 GNUNET_free_non_null(transport_name);
1509 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1512 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1519 * Function called to notify a client about the socket being ready to
1520 * queue more data. "buf" will be NULL and "size" zero if the socket
1521 * was closed for writing in the meantime.
1523 * @param cls closure
1524 * @param size number of bytes available in buf
1525 * @param buf where the callee should write the message
1526 * @return number of bytes written to buf
1529 transmit_to_client_callback (void *cls, size_t size, void *buf)
1531 struct TransportClient *client = cls;
1532 struct ClientMessageQueueEntry *q;
1535 const struct GNUNET_MessageHeader *msg;
1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543 "Transmission to client failed, closing connection.\n");
1545 /* fatal error with client, free message queue! */
1546 while (NULL != (q = client->message_queue_head))
1548 GNUNET_STATISTICS_update (stats,
1549 gettext_noop ("# bytes discarded (could not transmit to client)"),
1550 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1552 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1553 client->message_queue_tail,
1557 client->message_count = 0;
1562 while (NULL != (q = client->message_queue_head))
1564 msg = (const struct GNUNET_MessageHeader *) &q[1];
1565 msize = ntohs (msg->size);
1566 if (msize + tsize > size)
1569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570 "Transmitting message of type %u to client.\n",
1573 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1574 client->message_queue_tail,
1576 memcpy (&cbuf[tsize], msg, msize);
1579 client->message_count--;
1583 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1584 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1586 GNUNET_TIME_UNIT_FOREVER_REL,
1587 &transmit_to_client_callback,
1589 GNUNET_assert (client->th != NULL);
1596 * Convert an address to a string.
1598 * @param plugin name of the plugin responsible for the address
1599 * @param addr binary address
1600 * @param addr_len number of bytes in addr
1601 * @return NULL on error, otherwise address string
1604 a2s (const char *plugin,
1608 struct TransportPlugin *p;
1612 p = find_transport (plugin);
1615 return p->api->address_to_string (p->api->cls,
1622 * Mark the given FAL entry as 'connected' (and hence preferred for
1623 * sending); also mark all others for the same peer as 'not connected'
1624 * (since only one can be preferred).
1626 * @param fal address to set to 'connected'
1629 mark_address_connected (struct ForeignAddressList *fal)
1631 struct ForeignAddressList *pos;
1634 GNUNET_assert (GNUNET_YES == fal->validated);
1635 if (fal->connected == GNUNET_YES)
1636 return; /* nothing to do */
1638 pos = fal->ready_list->addresses;
1641 if (GNUNET_YES == pos->connected)
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1646 a2s (pos->ready_list->plugin->short_name,
1650 GNUNET_break (cnt == GNUNET_YES);
1652 pos->connected = GNUNET_NO;
1653 GNUNET_STATISTICS_update (stats,
1654 gettext_noop ("# connected addresses"),
1660 fal->connected = GNUNET_YES;
1661 if (GNUNET_YES == cnt)
1663 GNUNET_STATISTICS_update (stats,
1664 gettext_noop ("# connected addresses"),
1672 * Send the specified message to the specified client. Since multiple
1673 * messages may be pending for the same client at a time, this code
1674 * makes sure that no message is lost.
1676 * @param client client to transmit the message to
1677 * @param msg the message to send
1678 * @param may_drop can this message be dropped if the
1679 * message queue for this client is getting far too large?
1682 transmit_to_client (struct TransportClient *client,
1683 const struct GNUNET_MessageHeader *msg, int may_drop)
1685 struct ClientMessageQueueEntry *q;
1688 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1690 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1692 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1695 client->message_count,
1697 GNUNET_STATISTICS_update (stats,
1698 gettext_noop ("# messages dropped due to slow client"),
1703 msize = ntohs (msg->size);
1704 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1705 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1706 memcpy (&q[1], msg, msize);
1707 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1708 client->message_queue_tail,
1709 client->message_queue_tail,
1711 client->message_count++;
1712 if (client->th == NULL)
1714 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1716 GNUNET_TIME_UNIT_FOREVER_REL,
1717 &transmit_to_client_callback,
1719 GNUNET_assert (client->th != NULL);
1725 * Transmit a 'SEND_OK' notification to the given client for the
1728 * @param client who to notify
1729 * @param n neighbour to notify about, can be NULL (on failure)
1730 * @param target target of the transmission
1731 * @param result status code for the transmission request
1734 transmit_send_ok (struct TransportClient *client,
1735 struct NeighbourList *n,
1736 const struct GNUNET_PeerIdentity *target,
1739 struct SendOkMessage send_ok_msg;
1741 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1742 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1743 send_ok_msg.success = htonl (result);
1745 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1747 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1748 send_ok_msg.peer = *target;
1749 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1754 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1755 * upon "completion" of a send request. This tells the API
1756 * that it is now legal to send another message to the given
1759 * @param cls closure, identifies the entry on the
1760 * message queue that was transmitted and the
1761 * client responsible for queuing the message
1762 * @param target the peer receiving the message
1763 * @param result GNUNET_OK on success, if the transmission
1764 * failed, we should not tell the client to transmit
1768 transmit_send_continuation (void *cls,
1769 const struct GNUNET_PeerIdentity *target,
1772 struct MessageQueue *mq = cls;
1773 struct NeighbourList *n;
1775 GNUNET_STATISTICS_update (stats,
1776 gettext_noop ("# bytes pending with plugins"),
1777 - (int64_t) mq->message_buf_size,
1779 if (result == GNUNET_OK)
1781 GNUNET_STATISTICS_update (stats,
1782 gettext_noop ("# bytes successfully transmitted by plugins"),
1783 mq->message_buf_size,
1788 GNUNET_STATISTICS_update (stats,
1789 gettext_noop ("# bytes with transmission failure by plugins"),
1790 mq->message_buf_size,
1793 if (mq->specific_address != NULL)
1795 if (result == GNUNET_OK)
1797 mq->specific_address->timeout =
1798 GNUNET_TIME_relative_to_absolute
1799 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1800 if (mq->specific_address->validated == GNUNET_YES)
1801 mark_address_connected (mq->specific_address);
1805 if (mq->specific_address->connected != GNUNET_NO)
1808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1809 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1810 a2s (mq->specific_address->ready_list->plugin->short_name,
1811 mq->specific_address->addr,
1812 mq->specific_address->addrlen));
1814 GNUNET_STATISTICS_update (stats,
1815 gettext_noop ("# connected addresses"),
1818 mq->specific_address->connected = GNUNET_NO;
1821 if (! mq->internal_msg)
1822 mq->specific_address->in_transmit = GNUNET_NO;
1824 n = find_neighbour(&mq->neighbour_id);
1825 if (mq->client != NULL)
1826 transmit_send_ok (mq->client, n, target, result);
1829 try_transmission_to_peer (n);
1834 * Find an address in any of the available transports for
1835 * the given neighbour that would be good for message
1836 * transmission. This is essentially the transport selection
1839 * @param neighbour for whom to select an address
1840 * @return selected address, NULL if we have none
1842 struct ForeignAddressList *
1843 find_ready_address(struct NeighbourList *neighbour)
1845 struct ReadyList *head = neighbour->plugins;
1846 struct ForeignAddressList *addresses;
1847 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1848 struct ForeignAddressList *best_address;
1850 /* Hack to prefer unix domain sockets */
1851 struct ForeignAddressList *unix_address = NULL;
1853 best_address = NULL;
1854 while (head != NULL)
1856 addresses = head->addresses;
1857 while (addresses != NULL)
1859 if ( (addresses->timeout.abs_value < now.abs_value) &&
1860 (addresses->connected == GNUNET_YES) )
1863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1864 "Marking long-time inactive connection to `%4s' as down.\n",
1865 GNUNET_i2s (&neighbour->id));
1867 GNUNET_STATISTICS_update (stats,
1868 gettext_noop ("# connected addresses"),
1871 addresses->connected = GNUNET_NO;
1873 addresses = addresses->next;
1876 addresses = head->addresses;
1877 while (addresses != NULL)
1879 #if DEBUG_TRANSPORT > 1
1880 if (addresses->addr != NULL)
1881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1882 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1883 a2s (head->plugin->short_name,
1885 addresses->addrlen),
1886 GNUNET_i2s (&neighbour->id),
1887 addresses->connected,
1888 addresses->in_transmit,
1889 addresses->validated,
1890 addresses->connect_attempts,
1891 (unsigned long long) addresses->timeout.abs_value,
1892 (unsigned int) addresses->distance);
1894 if (0==strcmp(head->plugin->short_name,"unix"))
1896 if ((unix_address == NULL) || ((unix_address != NULL) &&
1897 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1898 unix_address = addresses;
1900 if ( ( (best_address == NULL) ||
1901 (addresses->connected == GNUNET_YES) ||
1902 (best_address->connected == GNUNET_NO) ) &&
1903 (addresses->in_transmit == GNUNET_NO) &&
1904 ( (best_address == NULL) ||
1905 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1906 best_address = addresses;
1907 /* FIXME: also give lower-latency addresses that are not
1908 connected a chance some times... */
1909 addresses = addresses->next;
1911 if (unix_address != NULL)
1915 if (unix_address != NULL)
1917 best_address = unix_address;
1919 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1922 if (best_address != NULL)
1926 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1927 "Best address found (`%s') has latency of %llu ms.\n",
1928 (best_address->addrlen > 0)
1929 ? a2s (best_address->ready_list->plugin->short_name,
1931 best_address->addrlen)
1933 best_address->latency.rel_value);
1938 GNUNET_STATISTICS_update (stats,
1939 gettext_noop ("# transmission attempts failed (no address)"),
1944 return best_address;
1950 * We should re-try transmitting to the given peer,
1951 * hopefully we've learned something in the meantime.
1954 retry_transmission_task (void *cls,
1955 const struct GNUNET_SCHEDULER_TaskContext *tc)
1957 struct NeighbourList *n = cls;
1959 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1960 try_transmission_to_peer (n);
1965 * Check the ready list for the given neighbour and if a plugin is
1966 * ready for transmission (and if we have a message), do so!
1968 * @param neighbour target peer for which to transmit
1971 try_transmission_to_peer (struct NeighbourList *n)
1973 struct ReadyList *rl;
1974 struct MessageQueue *mq;
1975 struct GNUNET_TIME_Relative timeout;
1979 if (n->messages_head == NULL)
1982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1983 "Transmission queue for `%4s' is empty\n",
1984 GNUNET_i2s (&n->id));
1986 return; /* nothing to do */
1989 mq = n->messages_head;
1990 force_address = GNUNET_YES;
1991 if (mq->specific_address == NULL)
1994 mq->specific_address = ats_get_preferred_address(n);
1995 GNUNET_STATISTICS_update (stats,
1996 gettext_noop ("# transport selected peer address freely"),
1999 force_address = GNUNET_NO;
2001 if (mq->specific_address == NULL)
2003 GNUNET_STATISTICS_update (stats,
2004 gettext_noop ("# transport failed to selected peer address"),
2007 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
2008 if (timeout.rel_value == 0)
2011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2012 "No destination address available to transmit message of size %u to peer `%4s'\n",
2013 mq->message_buf_size,
2014 GNUNET_i2s (&mq->neighbour_id));
2016 GNUNET_STATISTICS_update (stats,
2017 gettext_noop ("# bytes in message queue for other peers"),
2018 - (int64_t) mq->message_buf_size,
2020 GNUNET_STATISTICS_update (stats,
2021 gettext_noop ("# bytes discarded (no destination address available)"),
2022 mq->message_buf_size,
2024 if (mq->client != NULL)
2025 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
2026 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2030 return; /* nobody ready */
2032 GNUNET_STATISTICS_update (stats,
2033 gettext_noop ("# message delivery deferred (no address)"),
2036 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2037 GNUNET_SCHEDULER_cancel (n->retry_task);
2038 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
2039 &retry_transmission_task,
2042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2043 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
2044 mq->message_buf_size,
2045 GNUNET_i2s (&mq->neighbour_id),
2048 /* FIXME: might want to trigger peerinfo lookup here
2049 (unless that's already pending...) */
2052 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2055 if (mq->specific_address->connected == GNUNET_NO)
2056 mq->specific_address->connect_attempts++;
2057 rl = mq->specific_address->ready_list;
2058 mq->plugin = rl->plugin;
2059 if (!mq->internal_msg)
2060 mq->specific_address->in_transmit = GNUNET_YES;
2062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2063 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
2064 mq->message_buf_size,
2065 GNUNET_i2s (&n->id),
2066 (mq->specific_address->addr != NULL)
2067 ? a2s (mq->plugin->short_name,
2068 mq->specific_address->addr,
2069 mq->specific_address->addrlen)
2071 rl->plugin->short_name);
2073 GNUNET_STATISTICS_update (stats,
2074 gettext_noop ("# bytes in message queue for other peers"),
2075 - (int64_t) mq->message_buf_size,
2077 GNUNET_STATISTICS_update (stats,
2078 gettext_noop ("# bytes pending with plugins"),
2079 mq->message_buf_size,
2081 ret = rl->plugin->api->send (rl->plugin->api->cls,
2084 mq->message_buf_size,
2086 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2087 mq->specific_address->session,
2088 mq->specific_address->addr,
2089 mq->specific_address->addrlen,
2091 &transmit_send_continuation, mq);
2094 /* failure, but 'send' would not call continuation in this case,
2095 so we need to do it here! */
2096 transmit_send_continuation (mq,
2104 * Send the specified message to the specified peer.
2106 * @param client source of the transmission request (can be NULL)
2107 * @param peer_address ForeignAddressList where we should send this message
2108 * @param priority how important is the message
2109 * @param timeout how long do we have to transmit?
2110 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
2111 * @param message_buf_size total size of all messages in message_buf
2112 * @param is_internal is this an internal message; these are pre-pended and
2113 * also do not count for plugins being "ready" to transmit
2114 * @param neighbour handle to the neighbour for transmission
2117 transmit_to_peer (struct TransportClient *client,
2118 struct ForeignAddressList *peer_address,
2119 unsigned int priority,
2120 struct GNUNET_TIME_Relative timeout,
2121 const char *message_buf,
2122 size_t message_buf_size,
2123 int is_internal, struct NeighbourList *neighbour)
2125 struct MessageQueue *mq;
2130 /* check for duplicate submission */
2131 mq = neighbour->messages_head;
2134 if (mq->client == client)
2136 /* client transmitted to same peer twice
2137 before getting SEND_OK! */
2145 GNUNET_STATISTICS_update (stats,
2146 gettext_noop ("# bytes in message queue for other peers"),
2149 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2150 mq->specific_address = peer_address;
2151 mq->client = client;
2152 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2153 memcpy (&mq[1], message_buf, message_buf_size);
2154 mq->message_buf = (const char*) &mq[1];
2155 mq->message_buf_size = message_buf_size;
2156 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2157 mq->internal_msg = is_internal;
2158 mq->priority = priority;
2159 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2161 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2162 neighbour->messages_tail,
2165 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2166 neighbour->messages_tail,
2167 neighbour->messages_tail,
2169 try_transmission_to_peer (neighbour);
2176 struct GeneratorContext
2178 struct TransportPlugin *plug_pos;
2179 struct OwnAddressList *addr_pos;
2180 struct GNUNET_TIME_Absolute expiration;
2188 address_generator (void *cls, size_t max, void *buf)
2190 struct GeneratorContext *gc = cls;
2193 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2195 gc->plug_pos = gc->plug_pos->next;
2196 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2198 if (NULL == gc->plug_pos)
2203 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2206 gc->addr_pos->addrlen, buf, max);
2207 gc->addr_pos = gc->addr_pos->next;
2213 * Construct our HELLO message from all of the addresses of
2214 * all of the transports.
2219 struct GNUNET_HELLO_Message *hello;
2220 struct TransportClient *cpos;
2221 struct NeighbourList *npos;
2222 struct GeneratorContext gc;
2224 gc.plug_pos = plugins;
2225 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2226 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2227 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2230 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2232 GNUNET_STATISTICS_update (stats,
2233 gettext_noop ("# refreshed my HELLO"),
2237 while (cpos != NULL)
2239 transmit_to_client (cpos,
2240 (const struct GNUNET_MessageHeader *) hello,
2245 GNUNET_free_non_null (our_hello);
2247 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2249 while (npos != NULL)
2252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2253 "Transmitting updated `%s' to neighbour `%4s'\n",
2254 "HELLO", GNUNET_i2s (&npos->id));
2256 GNUNET_STATISTICS_update (stats,
2257 gettext_noop ("# transmitted my HELLO to other peers"),
2260 transmit_to_peer (NULL, NULL, 0,
2261 HELLO_ADDRESS_EXPIRATION,
2262 (const char *) our_hello,
2263 GNUNET_HELLO_size(our_hello),
2271 * Task used to clean up expired addresses for a plugin.
2273 * @param cls closure
2277 expire_address_task (void *cls,
2278 const struct GNUNET_SCHEDULER_TaskContext *tc);
2282 * Update the list of addresses for this plugin,
2283 * expiring those that are past their expiration date.
2285 * @param plugin addresses of which plugin should be recomputed?
2286 * @param fresh set to GNUNET_YES if a new address was added
2287 * and we need to regenerate the HELLO even if nobody
2291 update_addresses (struct TransportPlugin *plugin,
2294 static struct GNUNET_TIME_Absolute last_update;
2295 struct GNUNET_TIME_Relative min_remaining;
2296 struct GNUNET_TIME_Relative remaining;
2297 struct GNUNET_TIME_Absolute now;
2298 struct OwnAddressList *pos;
2299 struct OwnAddressList *prev;
2300 struct OwnAddressList *next;
2303 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2304 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2305 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2306 now = GNUNET_TIME_absolute_get ();
2307 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2308 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2310 pos = plugin->addresses;
2314 if (pos->expires.abs_value < now.abs_value)
2316 expired = GNUNET_YES;
2318 plugin->addresses = pos->next;
2320 prev->next = pos->next;
2325 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2326 if (remaining.rel_value < min_remaining.rel_value)
2327 min_remaining = remaining;
2333 if (expired || fresh)
2338 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2339 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2341 plugin->address_update_task
2342 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2343 &expire_address_task, plugin);
2348 * Task used to clean up expired addresses for a plugin.
2350 * @param cls closure
2354 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2356 struct TransportPlugin *plugin = cls;
2358 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2359 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2360 update_addresses (plugin, GNUNET_NO);
2365 * Iterator over hash map entries that NULLs the session of validation
2366 * entries that match the given session.
2368 * @param cls closure (the 'struct Session*' to match against)
2369 * @param key current key code (peer ID, not used)
2370 * @param value value in the hash map ('struct ValidationEntry*')
2371 * @return GNUNET_YES (we should continue to iterate)
2374 remove_session_validations (void *cls,
2375 const GNUNET_HashCode * key,
2378 struct Session *session = cls;
2379 struct ValidationEntry *ve = value;
2381 if (session == ve->session)
2388 * We've been disconnected from the other peer (for some
2389 * connection-oriented transport). Either quickly
2390 * re-establish the connection or signal the disconnect
2393 * Only signal CORE level disconnect if ALL addresses
2394 * for the peer are exhausted.
2396 * @param p overall plugin context
2397 * @param nl neighbour that was disconnected
2400 try_fast_reconnect (struct TransportPlugin *p,
2401 struct NeighbourList *nl)
2403 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2404 /* Note: the idea here is to hide problems with transports (or
2405 switching between plugins) from the core to eliminate the need to
2406 re-negotiate session keys and the like; OTOH, we should tell core
2407 quickly (much faster than timeout) `if a connection was lost and
2408 could not be re-established (i.e. other peer went down or is
2409 unable / refuses to communicate);
2411 So we should consider:
2412 1) ideally: our own willingness / need to connect
2413 2) prior failures to connect to this peer (by plugin)
2414 3) ideally: reasons why other peer terminated (as far as knowable)
2416 Most importantly, it must be POSSIBLE for another peer to terminate
2417 a connection for a while (without us instantly re-establishing it).
2418 Similarly, if another peer is gone we should quickly notify CORE.
2419 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2420 on the other end), we should reconnect in such a way that BOTH CORE
2421 services never even notice.
2422 Furthermore, the same mechanism (or small variation) could be used
2423 to switch to a better-performing plugin (ATS).
2425 Finally, this needs to be tested throughly... */
2428 * GNUNET_NO in the call below makes transport disconnect the peer,
2429 * even if only a single address (out of say, six) went away. This
2430 * function must be careful to ONLY disconnect if the peer is gone,
2431 * not just a specifi address.
2433 * More specifically, half the places it was used had it WRONG.
2436 /* No reconnect, signal disconnect instead! */
2437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2438 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2439 "try_fast_reconnect");
2440 disconnect_neighbour (nl, GNUNET_YES);
2445 * Function that will be called whenever the plugin internally
2446 * cleans up a session pointer and hence the service needs to
2447 * discard all of those sessions as well. Plugins that do not
2448 * use sessions can simply omit calling this function and always
2449 * use NULL wherever a session pointer is needed.
2451 * @param cls closure
2452 * @param peer which peer was the session for
2453 * @param session which session is being destoyed
2456 plugin_env_session_end (void *cls,
2457 const struct GNUNET_PeerIdentity *peer,
2458 struct Session *session)
2460 struct TransportPlugin *p = cls;
2461 struct NeighbourList *nl;
2462 struct ReadyList *rl;
2463 struct ForeignAddressList *pos;
2464 struct ForeignAddressList *prev;
2466 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2467 &remove_session_validations,
2469 nl = find_neighbour (peer);
2471 return; /* was never marked as connected */
2475 if (rl->plugin == p)
2480 return; /* was never marked as connected */
2482 pos = rl->addresses;
2483 while ( (pos != NULL) &&
2484 (pos->session != session) )
2490 return; /* was never marked as connected */
2491 pos->session = NULL;
2492 if (pos->addrlen != 0)
2494 if (nl->received_pong != GNUNET_NO)
2495 try_fast_reconnect (p, nl);
2498 /* was inbound connection, free 'pos' */
2500 rl->addresses = pos->next;
2502 prev->next = pos->next;
2503 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2505 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2506 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2509 if (nl->received_pong == GNUNET_NO)
2510 return; /* nothing to do, never connected... */
2511 /* check if we have any validated addresses left */
2512 pos = rl->addresses;
2517 try_fast_reconnect (p, nl);
2522 /* no valid addresses left, signal disconnect! */
2524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2525 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2526 "plugin_env_session_end");
2527 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2528 * it means there aren't any left for this PLUGIN/PEER combination! So
2529 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2530 * when it isn't necessary. Using GNUNET_YES at least checks to see
2531 * if there are any addresses that work first, so as not to overdo it.
2534 disconnect_neighbour (nl, GNUNET_YES);
2539 * Function that must be called by each plugin to notify the
2540 * transport service about the addresses under which the transport
2541 * provided by the plugin can be reached.
2543 * @param cls closure
2544 * @param name name of the transport that generated the address
2545 * @param addr one of the addresses of the host, NULL for the last address
2546 * the specific address format depends on the transport
2547 * @param addrlen length of the address
2548 * @param expires when should this address automatically expire?
2551 plugin_env_notify_address (void *cls,
2555 struct GNUNET_TIME_Relative expires)
2557 struct TransportPlugin *p = cls;
2558 struct OwnAddressList *al;
2559 struct GNUNET_TIME_Absolute abex;
2561 GNUNET_assert (addr != NULL);
2562 abex = GNUNET_TIME_relative_to_absolute (expires);
2563 GNUNET_assert (p == find_transport (name));
2567 if ( (addrlen == al->addrlen) &&
2568 (0 == memcmp (addr, &al[1], addrlen)) )
2571 update_addresses (p, GNUNET_NO);
2576 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2577 al->next = p->addresses;
2580 al->addrlen = addrlen;
2581 memcpy (&al[1], addr, addrlen);
2582 update_addresses (p, GNUNET_YES);
2587 * Notify all of our clients about a peer connecting.
2590 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2591 struct GNUNET_TIME_Relative latency,
2594 struct ConnectInfoMessage * cim;
2595 struct TransportClient *cpos;
2600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2601 "Notifying clients about connection from `%s'\n",
2604 GNUNET_STATISTICS_update (stats,
2605 gettext_noop ("# peers connected"),
2610 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2611 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2615 cim = GNUNET_malloc (size);
2617 cim->header.size = htons (size);
2618 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2619 cim->ats_count = htonl(2);
2620 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2621 (&(cim->ats))[0].value = htonl (distance);
2622 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2623 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2624 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2625 (&(cim->ats))[2].value = htonl (0);
2626 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2628 /* notify ats about connecting peer */
2629 ats_notify_peer_connect (peer, &(cim->ats), 2);
2632 while (cpos != NULL)
2634 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2643 * Notify all of our clients about a peer disconnecting.
2646 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2648 struct DisconnectInfoMessage dim;
2649 struct TransportClient *cpos;
2652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2653 "Notifying clients about lost connection to `%s'\n",
2656 GNUNET_STATISTICS_update (stats,
2657 gettext_noop ("# peers connected"),
2660 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2661 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2662 dim.reserved = htonl (0);
2663 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2665 /* notify ats about connecting peer */
2666 ats_notify_peer_disconnect (peer);
2669 while (cpos != NULL)
2671 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2678 * Find a ForeignAddressList entry for the given neighbour
2679 * that matches the given address and transport.
2681 * @param neighbour which peer we care about
2682 * @param tname name of the transport plugin
2683 * @param session session to look for, NULL for 'any'; otherwise
2684 * can be used for the service to "learn" this session ID
2686 * @param addr binary address
2687 * @param addrlen length of addr
2688 * @return NULL if no such entry exists
2690 static struct ForeignAddressList *
2691 find_peer_address(struct NeighbourList *neighbour,
2693 struct Session *session,
2697 struct ReadyList *head;
2698 struct ForeignAddressList *pos;
2700 head = neighbour->plugins;
2701 while (head != NULL)
2703 if (0 == strcmp (tname, head->plugin->short_name))
2709 pos = head->addresses;
2710 while ( (pos != NULL) &&
2711 ( (pos->addrlen != addrlen) ||
2712 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2714 if ( (session != NULL) &&
2715 (pos->session == session) )
2719 if ( (session != NULL) && (pos != NULL) )
2720 pos->session = session; /* learn it! */
2726 * Get the peer address struct for the given neighbour and
2727 * address. If it doesn't yet exist, create it.
2729 * @param neighbour which peer we care about
2730 * @param tname name of the transport plugin
2731 * @param session session of the plugin, or NULL for none
2732 * @param addr binary address
2733 * @param addrlen length of addr
2734 * @return NULL if we do not have a transport plugin for 'tname'
2736 static struct ForeignAddressList *
2737 add_peer_address (struct NeighbourList *neighbour,
2739 struct Session *session,
2743 struct ReadyList *head;
2744 struct ForeignAddressList *ret;
2747 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2750 head = neighbour->plugins;
2752 while (head != NULL)
2754 if (0 == strcmp (tname, head->plugin->short_name))
2760 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2761 ret->session = session;
2762 if ((addrlen > 0) && (addr != NULL))
2764 ret->addr = (const char*) &ret[1];
2765 memcpy (&ret[1], addr, addrlen);
2772 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2774 for (c=0; c<available_ressources; c++)
2776 struct ATS_ressource_entry *r = ret->ressources;
2778 r[c].atis_index = ressources[c].atis_index;
2779 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2781 r[c].c = ressources[c].c_unix;
2784 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2786 r[c].c = ressources[c].c_udp;
2789 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2791 r[c].c = ressources[c].c_tcp;
2794 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2796 r[c].c = ressources[c].c_http;
2799 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2801 r[c].c = ressources[c].c_https;
2804 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2806 r[c].c = ressources[c].c_wlan;
2812 r[c].c = ressources[c].c_default;
2813 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2814 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2818 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2819 ret->addrlen = addrlen;
2820 ret->expires = GNUNET_TIME_relative_to_absolute
2821 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2822 ret->latency = GNUNET_TIME_relative_get_forever();
2824 ret->timeout = GNUNET_TIME_relative_to_absolute
2825 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2826 ret->ready_list = head;
2827 ret->next = head->addresses;
2828 head->addresses = ret;
2834 * Closure for 'add_validated_address'.
2836 struct AddValidatedAddressContext
2839 * Entry that has been validated.
2841 const struct ValidationEntry *ve;
2844 * Flag set after we have added the address so
2845 * that we terminate the iteration next time.
2852 * Callback function used to fill a buffer of max bytes with a list of
2853 * addresses in the format used by HELLOs. Should use
2854 * "GNUNET_HELLO_add_address" as a helper function.
2856 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2857 * @param max maximum number of bytes that can be written to buf
2858 * @param buf where to write the address information
2859 * @return number of bytes written, 0 to signal the
2860 * end of the iteration.
2863 add_validated_address (void *cls,
2864 size_t max, void *buf)
2866 struct AddValidatedAddressContext *avac = cls;
2867 const struct ValidationEntry *ve = avac->ve;
2869 if (GNUNET_YES == avac->done)
2871 avac->done = GNUNET_YES;
2872 return GNUNET_HELLO_add_address (ve->transport_name,
2873 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2883 * Closure for 'check_address_exists'.
2885 struct CheckAddressExistsClosure
2888 * Address to check for.
2893 * Name of the transport.
2900 struct Session *session;
2903 * Set to GNUNET_YES if the address exists.
2916 * Iterator over hash map entries. Checks if the given
2917 * validation entry is for the same address as what is given
2920 * @param cls the 'struct CheckAddressExistsClosure*'
2921 * @param key current key code (ignored)
2922 * @param value value in the hash map ('struct ValidationEntry')
2923 * @return GNUNET_YES if we should continue to
2924 * iterate (mismatch), GNUNET_NO if not (entry matched)
2927 check_address_exists (void *cls,
2928 const GNUNET_HashCode * key,
2931 struct CheckAddressExistsClosure *caec = cls;
2932 struct ValidationEntry *ve = value;
2934 if ( (0 == strcmp (caec->tname,
2935 ve->transport_name)) &&
2936 (caec->addrlen == ve->addrlen) &&
2937 (0 == memcmp (caec->addr,
2941 caec->exists = GNUNET_YES;
2944 if ( (ve->session != NULL) &&
2945 (caec->session == ve->session) )
2947 caec->exists = GNUNET_YES;
2956 * Iterator to free entries in the validation_map.
2958 * @param cls closure (unused)
2959 * @param key current key code
2960 * @param value value in the hash map (validation to abort)
2961 * @return GNUNET_YES (always)
2964 abort_validation (void *cls,
2965 const GNUNET_HashCode * key,
2968 struct ValidationEntry *va = value;
2970 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2971 GNUNET_SCHEDULER_cancel (va->timeout_task);
2972 GNUNET_free (va->transport_name);
2973 if (va->chvc != NULL)
2975 va->chvc->ve_count--;
2976 if (va->chvc->ve_count == 0)
2978 GNUNET_CONTAINER_DLL_remove (chvc_head,
2981 GNUNET_free (va->chvc);
2991 * HELLO validation cleanup task (validation failed).
2993 * @param cls the 'struct ValidationEntry' that failed
2994 * @param tc scheduler context (unused)
2997 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2999 struct ValidationEntry *va = cls;
3000 struct GNUNET_PeerIdentity pid;
3002 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3003 GNUNET_STATISTICS_update (stats,
3004 gettext_noop ("# address validation timeouts"),
3007 GNUNET_CRYPTO_hash (&va->publicKey,
3009 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3011 GNUNET_break (GNUNET_OK ==
3012 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3015 abort_validation (NULL, NULL, va);
3020 neighbour_timeout_task (void *cls,
3021 const struct GNUNET_SCHEDULER_TaskContext *tc)
3023 struct NeighbourList *n = cls;
3026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3027 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3029 GNUNET_STATISTICS_update (stats,
3030 gettext_noop ("# disconnects due to timeout"),
3033 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3034 disconnect_neighbour (n, GNUNET_NO);
3039 * Schedule the job that will cause us to send a PING to the
3040 * foreign address to evaluate its validity and latency.
3042 * @param fal address to PING
3045 schedule_next_ping (struct ForeignAddressList *fal);
3049 * Add the given address to the list of foreign addresses
3050 * available for the given peer (check for duplicates).
3052 * @param cls the respective 'struct NeighbourList' to update
3053 * @param tname name of the transport
3054 * @param expiration expiration time
3055 * @param addr the address
3056 * @param addrlen length of the address
3057 * @return GNUNET_OK (always)
3060 add_to_foreign_address_list (void *cls,
3062 struct GNUNET_TIME_Absolute expiration,
3066 struct NeighbourList *n = cls;
3067 struct ForeignAddressList *fal;
3070 GNUNET_STATISTICS_update (stats,
3071 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3075 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3078 #if DEBUG_TRANSPORT_HELLO
3079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3080 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3081 a2s (tname, addr, addrlen),
3083 GNUNET_i2s (&n->id),
3084 expiration.abs_value);
3086 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3089 GNUNET_STATISTICS_update (stats,
3090 gettext_noop ("# previously validated addresses lacking transport"),
3096 fal->expires = GNUNET_TIME_absolute_max (expiration,
3098 schedule_next_ping (fal);
3104 fal->expires = GNUNET_TIME_absolute_max (expiration,
3109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3110 "Failed to add new address for `%4s'\n",
3111 GNUNET_i2s (&n->id));
3114 if (fal->validated == GNUNET_NO)
3116 fal->validated = GNUNET_YES;
3117 GNUNET_STATISTICS_update (stats,
3118 gettext_noop ("# peer addresses considered valid"),
3122 if (try == GNUNET_YES)
3124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3125 "Have new addresses, will try to trigger transmissions.\n");
3126 try_transmission_to_peer (n);
3133 * Add addresses in validated HELLO "h" to the set of addresses
3134 * we have for this peer.
3136 * @param cls closure ('struct NeighbourList*')
3137 * @param peer id of the peer, NULL for last call
3138 * @param h hello message for the peer (can be NULL)
3139 * @param err_msg NULL if successful, otherwise contains error message
3142 add_hello_for_peer (void *cls,
3143 const struct GNUNET_PeerIdentity *peer,
3144 const struct GNUNET_HELLO_Message *h,
3145 const char *err_msg)
3147 struct NeighbourList *n = cls;
3149 if (err_msg != NULL)
3151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3152 _("Error in communication with PEERINFO service\n"));
3157 GNUNET_STATISTICS_update (stats,
3158 gettext_noop ("# outstanding peerinfo iterate requests"),
3165 return; /* no HELLO available */
3167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3168 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3172 if (GNUNET_YES != n->public_key_valid)
3174 GNUNET_HELLO_get_key (h, &n->publicKey);
3175 n->public_key_valid = GNUNET_YES;
3177 GNUNET_HELLO_iterate_addresses (h,
3179 &add_to_foreign_address_list,
3185 * Create a fresh entry in our neighbour list for the given peer.
3186 * Will try to transmit our current HELLO to the new neighbour.
3187 * Do not call this function directly, use 'setup_peer_check_blacklist.
3189 * @param peer the peer for which we create the entry
3190 * @param do_hello should we schedule transmitting a HELLO
3191 * @return the new neighbour list entry
3193 static struct NeighbourList *
3194 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3197 struct NeighbourList *n;
3198 struct TransportPlugin *tp;
3199 struct ReadyList *rl;
3202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3203 "Setting up state for neighbour `%4s'\n",
3206 GNUNET_assert (our_hello != NULL);
3207 GNUNET_STATISTICS_update (stats,
3208 gettext_noop ("# active neighbours"),
3211 n = GNUNET_malloc (sizeof (struct NeighbourList));
3212 n->next = neighbours;
3216 GNUNET_TIME_relative_to_absolute
3217 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3218 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3219 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3220 MAX_BANDWIDTH_CARRY_S);
3224 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3226 rl = GNUNET_malloc (sizeof (struct ReadyList));
3228 rl->next = n->plugins;
3231 rl->addresses = NULL;
3235 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3237 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3238 &neighbour_timeout_task, n);
3241 GNUNET_STATISTICS_update (stats,
3242 gettext_noop ("# peerinfo new neighbor iterate requests"),
3245 GNUNET_STATISTICS_update (stats,
3246 gettext_noop ("# outstanding peerinfo iterate requests"),
3249 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3250 GNUNET_TIME_UNIT_FOREVER_REL,
3251 &add_hello_for_peer, n);
3253 GNUNET_STATISTICS_update (stats,
3254 gettext_noop ("# HELLO's sent to new neighbors"),
3257 transmit_to_peer (NULL, NULL, 0,
3258 HELLO_ADDRESS_EXPIRATION,
3259 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3267 * Function called after we have checked if communicating
3268 * with a given peer is acceptable.
3270 * @param cls closure
3271 * @param n NULL if communication is not acceptable
3273 typedef void (*SetupContinuation)(void *cls,
3274 struct NeighbourList *n);
3278 * Information kept for each client registered to perform
3284 * This is a linked list.
3286 struct Blacklisters *next;
3289 * This is a linked list.
3291 struct Blacklisters *prev;
3294 * Client responsible for this entry.
3296 struct GNUNET_SERVER_Client *client;
3299 * Blacklist check that we're currently performing.
3301 struct BlacklistCheck *bc;
3307 * Head of DLL of blacklisting clients.
3309 static struct Blacklisters *bl_head;
3312 * Tail of DLL of blacklisting clients.
3314 static struct Blacklisters *bl_tail;
3318 * Context we use when performing a blacklist check.
3320 struct BlacklistCheck
3324 * This is a linked list.
3326 struct BlacklistCheck *next;
3329 * This is a linked list.
3331 struct BlacklistCheck *prev;
3334 * Peer being checked.
3336 struct GNUNET_PeerIdentity peer;
3339 * Option for setup neighbour afterwards.
3344 * Continuation to call with the result.
3346 SetupContinuation cont;
3354 * Current transmission request handle for this client, or NULL if no
3355 * request is pending.
3357 struct GNUNET_CONNECTION_TransmitHandle *th;
3360 * Our current position in the blacklisters list.
3362 struct Blacklisters *bl_pos;
3365 * Current task performing the check.
3367 GNUNET_SCHEDULER_TaskIdentifier task;
3372 * Head of DLL of active blacklisting queries.
3374 static struct BlacklistCheck *bc_head;
3377 * Tail of DLL of active blacklisting queries.
3379 static struct BlacklistCheck *bc_tail;
3383 * Perform next action in the blacklist check.
3385 * @param cls the 'struct BlacklistCheck*'
3389 do_blacklist_check (void *cls,
3390 const struct GNUNET_SCHEDULER_TaskContext *tc);
3393 * Transmit blacklist query to the client.
3395 * @param cls the 'struct BlacklistCheck'
3396 * @param size number of bytes allowed
3397 * @param buf where to copy the message
3398 * @return number of bytes copied to buf
3401 transmit_blacklist_message (void *cls,
3405 struct BlacklistCheck *bc = cls;
3406 struct Blacklisters *bl;
3407 struct BlacklistMessage bm;
3412 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3413 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3418 bm.header.size = htons (sizeof (struct BlacklistMessage));
3419 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3420 bm.is_allowed = htonl (0);
3422 memcpy (buf, &bm, sizeof (bm));
3423 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3429 * Perform next action in the blacklist check.
3431 * @param cls the 'struct BlacklistCheck*'
3435 do_blacklist_check (void *cls,
3436 const struct GNUNET_SCHEDULER_TaskContext *tc)
3438 struct BlacklistCheck *bc = cls;
3439 struct Blacklisters *bl;
3441 bc->task = GNUNET_SCHEDULER_NO_TASK;
3445 bc->cont (bc->cont_cls,
3446 setup_new_neighbour (&bc->peer, bc->do_hello));
3453 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3454 sizeof (struct BlacklistMessage),
3455 GNUNET_TIME_UNIT_FOREVER_REL,
3456 &transmit_blacklist_message,
3463 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3464 * does not yet exist, check the blacklist. If the blacklist says creating
3465 * one is acceptable, create one and call the continuation; otherwise
3466 * call the continuation with NULL.
3468 * @param peer peer to setup or look up a struct NeighbourList for
3469 * @param do_hello should we also schedule sending our HELLO to the peer
3470 * if this is a new record
3471 * @param cont function to call with the 'struct NeigbhbourList*'
3472 * @param cont_cls closure for cont
3475 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3477 SetupContinuation cont,
3480 struct NeighbourList *n;
3481 struct BlacklistCheck *bc;
3483 n = find_neighbour(peer);
3490 if (bl_head == NULL)
3493 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3495 setup_new_neighbour(peer, do_hello);
3498 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3499 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3501 bc->do_hello = do_hello;
3503 bc->cont_cls = cont_cls;
3504 bc->bl_pos = bl_head;
3505 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3511 * Function called with the result of querying a new blacklister about
3512 * it being allowed (or not) to continue to talk to an existing neighbour.
3514 * @param cls the original 'struct NeighbourList'
3515 * @param n NULL if we need to disconnect
3518 confirm_or_drop_neighbour (void *cls,
3519 struct NeighbourList *n)
3521 struct NeighbourList * orig = cls;
3525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3526 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3527 "confirm_or_drop_neighboUr");
3528 disconnect_neighbour (orig, GNUNET_NO);
3534 * Handle a request to start a blacklist.
3536 * @param cls closure (always NULL)
3537 * @param client identification of the client
3538 * @param message the actual message
3541 handle_blacklist_init (void *cls,
3542 struct GNUNET_SERVER_Client *client,
3543 const struct GNUNET_MessageHeader *message)
3545 struct Blacklisters *bl;
3546 struct BlacklistCheck *bc;
3547 struct NeighbourList *n;
3552 if (bl->client == client)
3555 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3560 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3561 bl->client = client;
3562 GNUNET_SERVER_client_keep (client);
3563 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3564 /* confirm that all existing connections are OK! */
3568 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3569 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3571 bc->do_hello = GNUNET_NO;
3572 bc->cont = &confirm_or_drop_neighbour;
3575 if (n == neighbours) /* all would wait for the same client, no need to
3576 create more than just the first task right now */
3577 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3585 * Handle a request to blacklist a peer.
3587 * @param cls closure (always NULL)
3588 * @param client identification of the client
3589 * @param message the actual message
3592 handle_blacklist_reply (void *cls,
3593 struct GNUNET_SERVER_Client *client,
3594 const struct GNUNET_MessageHeader *message)
3596 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3597 struct Blacklisters *bl;
3598 struct BlacklistCheck *bc;
3601 while ( (bl != NULL) &&
3602 (bl->client != client) )
3606 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3611 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3613 bc->cont (bc->cont_cls, NULL);
3614 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3619 bc->bl_pos = bc->bl_pos->next;
3620 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3623 /* check if any other bc's are waiting for this blacklister */
3627 if ( (bc->bl_pos == bl) &&
3628 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3629 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3637 * Send periodic PING messages to a given foreign address.
3639 * @param cls our 'struct PeriodicValidationContext*'
3640 * @param tc task context
3643 send_periodic_ping (void *cls,
3644 const struct GNUNET_SCHEDULER_TaskContext *tc)
3646 struct ForeignAddressList *peer_address = cls;
3647 struct TransportPlugin *tp;
3648 struct ValidationEntry *va;
3649 struct NeighbourList *neighbour;
3650 struct TransportPingMessage ping;
3651 struct CheckAddressExistsClosure caec;
3653 uint16_t hello_size;
3657 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3658 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3660 tp = peer_address->ready_list->plugin;
3661 neighbour = peer_address->ready_list->neighbour;
3662 if (GNUNET_YES != neighbour->public_key_valid)
3664 /* no public key yet, try again later */
3665 schedule_next_ping (peer_address);
3668 caec.addr = peer_address->addr;
3669 caec.addrlen = peer_address->addrlen;
3670 caec.tname = tp->short_name;
3671 caec.session = peer_address->session;
3672 caec.exists = GNUNET_NO;
3673 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3674 &check_address_exists,
3676 if (caec.exists == GNUNET_YES)
3678 /* During validation attempts we will likely trigger the other
3679 peer trying to validate our address which in turn will cause
3680 it to send us its HELLO, so we expect to hit this case rather
3681 frequently. Only print something if we are very verbose. */
3682 #if DEBUG_TRANSPORT > 1
3683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3684 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3685 (peer_address->addr != NULL)
3686 ? a2s (tp->short_name,
3688 peer_address->addrlen)
3691 GNUNET_i2s (&neighbour->id));
3693 schedule_next_ping (peer_address);
3696 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3697 va->transport_name = GNUNET_strdup (tp->short_name);
3698 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3700 va->send_time = GNUNET_TIME_absolute_get();
3701 va->session = peer_address->session;
3702 if (peer_address->addr != NULL)
3704 va->addr = (const void*) &va[1];
3705 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3706 va->addrlen = peer_address->addrlen;
3708 memcpy(&va->publicKey,
3709 &neighbour->publicKey,
3710 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3712 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3713 &timeout_hello_validation,
3715 GNUNET_CONTAINER_multihashmap_put (validation_map,
3716 &neighbour->id.hashPubKey,
3718 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3720 if (peer_address->validated != GNUNET_YES)
3721 hello_size = GNUNET_HELLO_size(our_hello);
3725 tsize = sizeof(struct TransportPingMessage) + hello_size;
3727 if (peer_address->addr != NULL)
3729 slen = strlen (tp->short_name) + 1;
3730 tsize += slen + peer_address->addrlen;
3734 slen = 0; /* make gcc happy */
3736 message_buf = GNUNET_malloc(tsize);
3737 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3738 ping.challenge = htonl(va->challenge);
3739 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3740 if (peer_address->validated != GNUNET_YES)
3742 memcpy(message_buf, our_hello, hello_size);
3745 if (peer_address->addr != NULL)
3747 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3748 peer_address->addrlen +
3750 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3753 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3755 peer_address->addrlen);
3759 ping.header.size = htons(sizeof(struct TransportPingMessage));
3762 memcpy(&message_buf[hello_size],
3764 sizeof(struct TransportPingMessage));
3766 #if DEBUG_TRANSPORT_REVALIDATION
3767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3768 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3769 (peer_address->addr != NULL)
3770 ? a2s (peer_address->plugin->short_name,
3772 peer_address->addrlen)
3775 GNUNET_i2s (&neighbour->id),
3776 "HELLO", hello_size,
3779 if (peer_address->validated != GNUNET_YES)
3780 GNUNET_STATISTICS_update (stats,
3781 gettext_noop ("# PING with HELLO messages sent"),
3785 GNUNET_STATISTICS_update (stats,
3786 gettext_noop ("# PING without HELLO messages sent"),
3789 GNUNET_STATISTICS_update (stats,
3790 gettext_noop ("# PING messages sent for re-validation"),
3793 transmit_to_peer (NULL, peer_address,
3794 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3795 HELLO_VERIFICATION_TIMEOUT,
3797 GNUNET_YES, neighbour);
3798 GNUNET_free(message_buf);
3799 schedule_next_ping (peer_address);
3804 * Schedule the job that will cause us to send a PING to the
3805 * foreign address to evaluate its validity and latency.
3807 * @param fal address to PING
3810 schedule_next_ping (struct ForeignAddressList *fal)
3812 struct GNUNET_TIME_Relative delay;
3814 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3816 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3817 delay.rel_value /= 2; /* do before expiration */
3818 delay = GNUNET_TIME_relative_min (delay,
3819 LATENCY_EVALUATION_MAX_DELAY);
3820 if (GNUNET_YES != fal->estimated)
3822 delay = GNUNET_TIME_UNIT_ZERO;
3823 fal->estimated = GNUNET_YES;
3825 if (GNUNET_YES == fal->connected)
3827 delay = GNUNET_TIME_relative_min (delay,
3828 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3830 /* FIXME: also adjust delay based on how close the last
3831 observed latency is to the latency of the best alternative */
3832 /* bound how fast we can go */
3833 delay = GNUNET_TIME_relative_max (delay,
3834 GNUNET_TIME_UNIT_SECONDS);
3835 /* randomize a bit (to avoid doing all at the same time) */
3836 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3837 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3838 &send_periodic_ping,
3846 * Function that will be called if we receive some payload
3847 * from another peer.
3849 * @param message the payload
3850 * @param n peer who claimed to be the sender
3853 handle_payload_message (const struct GNUNET_MessageHeader *message,
3854 struct NeighbourList *n)
3856 struct InboundMessage *im;
3857 struct TransportClient *cpos;
3860 msize = ntohs (message->size);
3861 if (n->received_pong == GNUNET_NO)
3863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3864 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3865 ntohs (message->type),
3866 ntohs (message->size),
3867 GNUNET_i2s (&n->id));
3868 GNUNET_free_non_null (n->pre_connect_message_buffer);
3869 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3870 memcpy (n->pre_connect_message_buffer, message, msize);
3875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3876 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3877 ntohs (message->type),
3878 ntohs (message->size),
3879 GNUNET_i2s (&n->id));
3881 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3884 n->quota_violation_count++;
3886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3887 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3888 n->in_tracker.available_bytes_per_s__,
3889 n->quota_violation_count);
3891 /* Discount 32k per violation */
3892 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3897 if (n->quota_violation_count > 0)
3899 /* try to add 32k back */
3900 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3902 n->quota_violation_count--;
3905 GNUNET_STATISTICS_update (stats,
3906 gettext_noop ("# payload received from other peers"),
3909 /* transmit message to all clients */
3910 uint32_t ats_count = 2;
3911 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3912 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3915 im = GNUNET_malloc (size);
3916 im->header.size = htons (size);
3917 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3919 im->ats_count = htonl(ats_count);
3920 /* Setting ATS data */
3921 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3922 (&(im->ats))[0].value = htonl (n->distance);
3923 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3924 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3925 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3926 (&(im->ats))[ats_count].value = htonl (0);
3928 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3930 while (cpos != NULL)
3932 transmit_to_client (cpos, &im->header, GNUNET_YES);
3940 * Iterator over hash map entries. Checks if the given validation
3941 * entry is for the same challenge as what is given in the PONG.
3943 * @param cls the 'struct TransportPongMessage*'
3944 * @param key peer identity
3945 * @param value value in the hash map ('struct ValidationEntry')
3946 * @return GNUNET_YES if we should continue to
3947 * iterate (mismatch), GNUNET_NO if not (entry matched)
3950 check_pending_validation (void *cls,
3951 const GNUNET_HashCode * key,
3954 const struct TransportPongMessage *pong = cls;
3955 struct ValidationEntry *ve = value;
3956 struct AddValidatedAddressContext avac;
3957 unsigned int challenge = ntohl(pong->challenge);
3958 struct GNUNET_HELLO_Message *hello;
3959 struct GNUNET_PeerIdentity target;
3960 struct NeighbourList *n;
3961 struct ForeignAddressList *fal;
3962 struct OwnAddressList *oal;
3963 struct TransportPlugin *tp;
3964 struct GNUNET_MessageHeader *prem;
3970 ps = ntohs (pong->header.size);
3971 if (ps < sizeof (struct TransportPongMessage))
3973 GNUNET_break_op (0);
3976 addr = (const char*) &pong[1];
3977 slen = strlen (ve->transport_name) + 1;
3978 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3979 (ve->challenge != challenge) ||
3980 (addr[slen-1] != '\0') ||
3981 (0 != strcmp (addr, ve->transport_name)) ||
3982 (ntohl (pong->purpose.size)
3983 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3985 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3986 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3991 alen = ps - sizeof (struct TransportPongMessage) - slen;
3992 switch (ntohl (pong->purpose.purpose))
3994 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3995 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3996 (0 != memcmp (&addr[slen],
4000 return GNUNET_YES; /* different entry, keep trying! */
4002 if (0 != memcmp (&pong->pid,
4004 sizeof (struct GNUNET_PeerIdentity)))
4006 GNUNET_break_op (0);
4010 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4015 GNUNET_break_op (0);
4020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4021 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4023 a2s (ve->transport_name,
4024 (const struct sockaddr *) ve->addr,
4026 ve->transport_name);
4029 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4030 if (0 != memcmp (&pong->pid,
4032 sizeof (struct GNUNET_PeerIdentity)))
4034 GNUNET_break_op (0);
4037 if (ve->addrlen != 0)
4039 /* must have been for a different validation entry */
4042 tp = find_transport (ve->transport_name);
4048 oal = tp->addresses;
4051 if ( (oal->addrlen == alen) &&
4052 (0 == memcmp (&oal[1],
4060 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4061 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
4062 a2s (ve->transport_name,
4068 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4073 GNUNET_break_op (0);
4078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4079 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4081 a2s (ve->transport_name,
4084 ve->transport_name);
4088 GNUNET_break_op (0);
4091 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4093 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4094 _("Received expired signature. Check system time.\n"));
4097 GNUNET_STATISTICS_update (stats,
4098 gettext_noop ("# address validation successes"),
4101 /* create the updated HELLO */
4102 GNUNET_CRYPTO_hash (&ve->publicKey,
4103 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4104 &target.hashPubKey);
4105 if (ve->addr != NULL)
4107 avac.done = GNUNET_NO;
4109 hello = GNUNET_HELLO_create (&ve->publicKey,
4110 &add_validated_address,
4112 GNUNET_PEERINFO_add_peer (peerinfo,
4114 GNUNET_free (hello);
4116 n = find_neighbour (&target);
4119 n->publicKey = ve->publicKey;
4120 n->public_key_valid = GNUNET_YES;
4121 fal = add_peer_address (n,
4126 GNUNET_assert (fal != NULL);
4127 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4128 fal->validated = GNUNET_YES;
4129 mark_address_connected (fal);
4130 GNUNET_STATISTICS_update (stats,
4131 gettext_noop ("# peer addresses considered valid"),
4134 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4135 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4137 schedule_next_ping (fal);
4138 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4139 n->latency = fal->latency;
4141 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4143 n->distance = fal->distance;
4144 if (GNUNET_NO == n->received_pong)
4146 n->received_pong = GNUNET_YES;
4148 notify_clients_connect (&target, n->latency, n->distance);
4149 if (NULL != (prem = n->pre_connect_message_buffer))
4151 n->pre_connect_message_buffer = NULL;
4152 handle_payload_message (prem, n);
4156 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4158 GNUNET_SCHEDULER_cancel (n->retry_task);
4159 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4160 try_transmission_to_peer (n);
4164 /* clean up validation entry */
4165 GNUNET_assert (GNUNET_YES ==
4166 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4169 abort_validation (NULL, NULL, ve);
4175 * Function that will be called if we receive a validation
4176 * of an address challenge that we transmitted to another
4177 * peer. Note that the validation should only be considered
4178 * acceptable if the challenge matches AND if the sender
4179 * address is at least a plausible address for this peer
4180 * (otherwise we may be seeing a MiM attack).
4182 * @param cls closure
4183 * @param message the pong message
4184 * @param peer who responded to our challenge
4185 * @param sender_address string describing our sender address (as observed
4186 * by the other peer in binary format)
4187 * @param sender_address_len number of bytes in 'sender_address'
4190 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4191 const struct GNUNET_PeerIdentity *peer,
4192 const char *sender_address,
4193 size_t sender_address_len)
4195 #if DEBUG_TRANSPORT > 1
4196 /* we get tons of these that just get discarded, only log
4197 if we are quite verbose */
4198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4199 "Receiving `%s' message from `%4s'.\n", "PONG",
4202 GNUNET_STATISTICS_update (stats,
4203 gettext_noop ("# PONG messages received"),
4206 if (GNUNET_SYSERR !=
4207 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4209 &check_pending_validation,
4212 /* This is *expected* to happen a lot since we send
4213 PONGs to *all* known addresses of the sender of
4214 the PING, so most likely we get multiple PONGs
4215 per PING, and all but the first PONG will end up
4216 here. So really we should not print anything here
4217 unless we want to be very, very verbose... */
4218 #if DEBUG_TRANSPORT > 2
4219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4220 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4232 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4234 * @param cls the 'struct ValidationEntry*'
4235 * @param neighbour neighbour to validate, NULL if validation failed
4238 transmit_hello_and_ping (void *cls,
4239 struct NeighbourList *neighbour)
4241 struct ValidationEntry *va = cls;
4242 struct ForeignAddressList *peer_address;
4243 struct TransportPingMessage ping;
4244 uint16_t hello_size;
4247 struct GNUNET_PeerIdentity id;
4250 GNUNET_CRYPTO_hash (&va->publicKey,
4251 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4253 if (neighbour == NULL)
4255 /* FIXME: stats... */
4256 GNUNET_break (GNUNET_OK ==
4257 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4260 abort_validation (NULL, NULL, va);
4263 neighbour->publicKey = va->publicKey;
4264 neighbour->public_key_valid = GNUNET_YES;
4265 peer_address = add_peer_address (neighbour,
4266 va->transport_name, NULL,
4267 (const void*) &va[1],
4269 if (peer_address == NULL)
4271 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4272 "Failed to add peer `%4s' for plugin `%s'\n",
4273 GNUNET_i2s (&neighbour->id),
4274 va->transport_name);
4275 GNUNET_break (GNUNET_OK ==
4276 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4279 abort_validation (NULL, NULL, va);
4282 hello_size = GNUNET_HELLO_size(our_hello);
4283 slen = strlen(va->transport_name) + 1;
4284 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4285 message_buf = GNUNET_malloc(tsize);
4286 ping.challenge = htonl(va->challenge);
4287 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4288 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4289 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4290 memcpy(message_buf, our_hello, hello_size);
4291 memcpy(&message_buf[hello_size],
4293 sizeof(struct TransportPingMessage));
4294 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4297 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4302 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4305 : a2s (va->transport_name,
4306 (const void*) &va[1], va->addrlen),
4308 GNUNET_i2s (&neighbour->id),
4309 "HELLO", hello_size,
4310 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4313 GNUNET_STATISTICS_update (stats,
4314 gettext_noop ("# PING messages sent for initial validation"),
4317 transmit_to_peer (NULL, peer_address,
4318 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4319 HELLO_VERIFICATION_TIMEOUT,
4321 GNUNET_YES, neighbour);
4322 GNUNET_free(message_buf);
4327 * Check if the given address is already being validated; if not,
4328 * append the given address to the list of entries that are being be
4329 * validated and initiate validation.
4331 * @param cls closure ('struct CheckHelloValidatedContext *')
4332 * @param tname name of the transport
4333 * @param expiration expiration time
4334 * @param addr the address
4335 * @param addrlen length of the address
4336 * @return GNUNET_OK (always)
4339 run_validation (void *cls,
4341 struct GNUNET_TIME_Absolute expiration,
4345 struct CheckHelloValidatedContext *chvc = cls;
4346 struct GNUNET_PeerIdentity id;
4347 struct TransportPlugin *tp;
4348 struct ValidationEntry *va;
4349 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4350 struct CheckAddressExistsClosure caec;
4351 struct OwnAddressList *oal;
4353 GNUNET_assert (addr != NULL);
4355 GNUNET_STATISTICS_update (stats,
4356 gettext_noop ("# peer addresses scheduled for validation"),
4359 tp = find_transport (tname);
4362 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4363 GNUNET_ERROR_TYPE_BULK,
4365 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4367 GNUNET_STATISTICS_update (stats,
4368 gettext_noop ("# peer addresses not validated (plugin not available)"),
4373 /* check if this is one of our own addresses */
4374 oal = tp->addresses;
4377 if ( (oal->addrlen == addrlen) &&
4378 (0 == memcmp (&oal[1],
4382 /* not plausible, this address is equivalent to our own address! */
4383 GNUNET_STATISTICS_update (stats,
4384 gettext_noop ("# peer addresses not validated (loopback)"),
4391 GNUNET_HELLO_get_key (chvc->hello, &pk);
4392 GNUNET_CRYPTO_hash (&pk,
4394 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4397 if (is_blacklisted(&id, tp))
4400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4401 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4409 caec.addrlen = addrlen;
4410 caec.session = NULL;
4412 caec.exists = GNUNET_NO;
4413 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4414 &check_address_exists,
4416 if (caec.exists == GNUNET_YES)
4418 /* During validation attempts we will likely trigger the other
4419 peer trying to validate our address which in turn will cause
4420 it to send us its HELLO, so we expect to hit this case rather
4421 frequently. Only print something if we are very verbose. */
4422 #if DEBUG_TRANSPORT > 1
4423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4424 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4425 a2s (tname, addr, addrlen),
4429 GNUNET_STATISTICS_update (stats,
4430 gettext_noop ("# peer addresses not validated (in progress)"),
4435 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4438 va->transport_name = GNUNET_strdup (tname);
4439 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4441 va->send_time = GNUNET_TIME_absolute_get();
4442 va->addr = (const void*) &va[1];
4443 memcpy (&va[1], addr, addrlen);
4444 va->addrlen = addrlen;
4445 GNUNET_HELLO_get_key (chvc->hello,
4447 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4448 &timeout_hello_validation,
4450 GNUNET_CONTAINER_multihashmap_put (validation_map,
4453 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4454 setup_peer_check_blacklist (&id, GNUNET_NO,
4455 &transmit_hello_and_ping,
4462 * Check if addresses in validated hello "h" overlap with
4463 * those in "chvc->hello" and validate the rest.
4465 * @param cls closure
4466 * @param peer id of the peer, NULL for last call
4467 * @param h hello message for the peer (can be NULL)
4468 * @param err_msg NULL if successful, otherwise contains error message
4471 check_hello_validated (void *cls,
4472 const struct GNUNET_PeerIdentity *peer,
4473 const struct GNUNET_HELLO_Message *h,
4474 const char *err_msg)
4476 struct CheckHelloValidatedContext *chvc = cls;
4477 struct GNUNET_HELLO_Message *plain_hello;
4478 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4479 struct GNUNET_PeerIdentity target;
4480 struct NeighbourList *n;
4482 if (err_msg != NULL)
4484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4485 _("Error in communication with PEERINFO service\n"));
4491 GNUNET_STATISTICS_update (stats,
4492 gettext_noop ("# outstanding peerinfo iterate requests"),
4496 if (GNUNET_NO == chvc->hello_known)
4498 /* notify PEERINFO about the peer now, so that we at least
4499 have the public key if some other component needs it */
4500 GNUNET_HELLO_get_key (chvc->hello, &pk);
4501 GNUNET_CRYPTO_hash (&pk,
4502 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4503 &target.hashPubKey);
4504 plain_hello = GNUNET_HELLO_create (&pk,
4507 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4508 GNUNET_free (plain_hello);
4509 #if DEBUG_TRANSPORT_HELLO
4510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4511 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4513 GNUNET_i2s (&target));
4515 GNUNET_STATISTICS_update (stats,
4516 gettext_noop ("# new HELLOs requiring full validation"),
4519 GNUNET_HELLO_iterate_addresses (chvc->hello,
4526 GNUNET_STATISTICS_update (stats,
4527 gettext_noop ("# duplicate HELLO (peer known)"),
4532 if (chvc->ve_count == 0)
4534 GNUNET_CONTAINER_DLL_remove (chvc_head,
4543 #if DEBUG_TRANSPORT_HELLO
4544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4545 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4549 chvc->hello_known = GNUNET_YES;
4550 n = find_neighbour (peer);
4553 #if DEBUG_TRANSPORT_HELLO
4554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4555 "Calling hello_iterate_addresses for %s!\n",
4558 GNUNET_HELLO_iterate_addresses (h,
4560 &add_to_foreign_address_list,
4562 try_transmission_to_peer (n);
4566 #if DEBUG_TRANSPORT_HELLO
4567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4568 "No existing neighbor record for %s!\n",
4571 GNUNET_STATISTICS_update (stats,
4572 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4576 GNUNET_STATISTICS_update (stats,
4577 gettext_noop ("# HELLO validations (update case)"),
4580 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4582 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4589 * Process HELLO-message.
4591 * @param plugin transport involved, may be NULL
4592 * @param message the actual message
4593 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4596 process_hello (struct TransportPlugin *plugin,
4597 const struct GNUNET_MessageHeader *message)
4600 struct GNUNET_PeerIdentity target;
4601 const struct GNUNET_HELLO_Message *hello;
4602 struct CheckHelloValidatedContext *chvc;
4603 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4604 #if DEBUG_TRANSPORT_HELLO > 2
4607 hsize = ntohs (message->size);
4608 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4609 (hsize < sizeof (struct GNUNET_MessageHeader)))
4612 return GNUNET_SYSERR;
4614 GNUNET_STATISTICS_update (stats,
4615 gettext_noop ("# HELLOs received for validation"),
4619 /* first, check if load is too high */
4620 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4622 GNUNET_STATISTICS_update (stats,
4623 gettext_noop ("# HELLOs ignored due to high load"),
4626 #if DEBUG_TRANSPORT_HELLO
4627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4628 "Ignoring `%s' for `%4s', load too high.\n",
4630 GNUNET_i2s (&target));
4634 hello = (const struct GNUNET_HELLO_Message *) message;
4635 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4637 #if DEBUG_TRANSPORT_HELLO
4638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4639 "Unable to get public key from `%s' for `%4s'!\n",
4641 GNUNET_i2s (&target));
4643 GNUNET_break_op (0);
4644 return GNUNET_SYSERR;
4647 GNUNET_CRYPTO_hash (&publicKey,
4648 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4649 &target.hashPubKey);
4651 #if DEBUG_TRANSPORT_HELLO
4652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4653 "Received `%s' message for `%4s'\n",
4655 GNUNET_i2s (&target));
4658 if (0 == memcmp (&my_identity,
4660 sizeof (struct GNUNET_PeerIdentity)))
4662 GNUNET_STATISTICS_update (stats,
4663 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4669 while (NULL != chvc)
4671 if (GNUNET_HELLO_equals (hello,
4673 GNUNET_TIME_absolute_get ()).abs_value > 0)
4675 #if DEBUG_TRANSPORT_HELLO > 2
4676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4677 "Received duplicate `%s' message for `%4s'; ignored\n",
4679 GNUNET_i2s (&target));
4681 return GNUNET_OK; /* validation already pending */
4683 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4684 GNUNET_break (0 != memcmp (hello, chvc->hello,
4685 GNUNET_HELLO_size(hello)));
4690 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4691 if ((NULL != temp_neighbor))
4693 fprintf(stderr, "Already know peer, ignoring hello\n");
4698 #if DEBUG_TRANSPORT_HELLO > 2
4701 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4703 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4706 GNUNET_i2s (&target),
4708 GNUNET_HELLO_size(hello));
4712 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4714 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4715 memcpy (&chvc[1], hello, hsize);
4716 GNUNET_CONTAINER_DLL_insert (chvc_head,
4719 /* finally, check if HELLO was previously validated
4720 (continuation will then schedule actual validation) */
4721 GNUNET_STATISTICS_update (stats,
4722 gettext_noop ("# peerinfo process hello iterate requests"),
4725 GNUNET_STATISTICS_update (stats,
4726 gettext_noop ("# outstanding peerinfo iterate requests"),
4729 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4731 HELLO_VERIFICATION_TIMEOUT,
4732 &check_hello_validated, chvc);
4738 * The peer specified by the given neighbour has timed-out or a plugin
4739 * has disconnected. We may either need to do nothing (other plugins
4740 * still up), or trigger a full disconnect and clean up. This
4741 * function updates our state and does the necessary notifications.
4742 * Also notifies our clients that the neighbour is now officially
4745 * @param n the neighbour list entry for the peer
4746 * @param check GNUNET_YES to check if ALL addresses for this peer
4747 * are gone, GNUNET_NO to force a disconnect of the peer
4748 * regardless of whether other addresses exist.
4751 disconnect_neighbour (struct NeighbourList *n, int check)
4753 struct ReadyList *rpos;
4754 struct NeighbourList *npos;
4755 struct NeighbourList *nprev;
4756 struct MessageQueue *mq;
4757 struct ForeignAddressList *peer_addresses;
4758 struct ForeignAddressList *peer_pos;
4760 if (GNUNET_YES == check)
4763 while (NULL != rpos)
4765 peer_addresses = rpos->addresses;
4766 while (peer_addresses != NULL)
4768 if (GNUNET_YES == peer_addresses->connected)
4770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4771 "NOT Disconnecting from `%4s', still have live addresses!\n",
4772 GNUNET_i2s (&n->id));
4773 return; /* still connected */
4775 peer_addresses = peer_addresses->next;
4781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4782 "Disconnecting from `%4s'\n",
4783 GNUNET_i2s (&n->id));
4785 /* remove n from neighbours list */
4788 while ((npos != NULL) && (npos != n))
4793 GNUNET_assert (npos != NULL);
4795 neighbours = n->next;
4797 nprev->next = n->next;
4799 /* notify all clients about disconnect */
4800 if (GNUNET_YES == n->received_pong)
4801 notify_clients_disconnect (&n->id);
4803 /* clean up all plugins, cancel connections and pending transmissions */
4804 while (NULL != (rpos = n->plugins))
4806 n->plugins = rpos->next;
4807 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4808 while (rpos->addresses != NULL)
4810 peer_pos = rpos->addresses;
4811 rpos->addresses = peer_pos->next;
4812 if (peer_pos->connected == GNUNET_YES)
4813 GNUNET_STATISTICS_update (stats,
4814 gettext_noop ("# connected addresses"),
4817 if (GNUNET_YES == peer_pos->validated)
4818 GNUNET_STATISTICS_update (stats,
4819 gettext_noop ("# peer addresses considered valid"),
4822 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4824 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4825 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4827 GNUNET_free(peer_pos->ressources);
4828 GNUNET_free(peer_pos->quality);
4829 GNUNET_free(peer_pos);
4834 /* free all messages on the queue */
4835 while (NULL != (mq = n->messages_head))
4837 GNUNET_STATISTICS_update (stats,
4838 gettext_noop ("# bytes in message queue for other peers"),
4839 - (int64_t) mq->message_buf_size,
4841 GNUNET_STATISTICS_update (stats,
4842 gettext_noop ("# bytes discarded due to disconnect"),
4843 mq->message_buf_size,
4845 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4848 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4850 sizeof(struct GNUNET_PeerIdentity)));
4853 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4855 GNUNET_SCHEDULER_cancel (n->timeout_task);
4856 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4858 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4860 GNUNET_SCHEDULER_cancel (n->retry_task);
4861 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4863 if (n->piter != NULL)
4865 GNUNET_PEERINFO_iterate_cancel (n->piter);
4866 GNUNET_STATISTICS_update (stats,
4867 gettext_noop ("# outstanding peerinfo iterate requests"),
4872 /* finally, free n itself */
4873 GNUNET_STATISTICS_update (stats,
4874 gettext_noop ("# active neighbours"),
4877 GNUNET_free_non_null (n->pre_connect_message_buffer);
4883 * We have received a PING message from someone. Need to send a PONG message
4884 * in response to the peer by any means necessary.
4887 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4888 const struct GNUNET_PeerIdentity *peer,
4889 struct Session *session,
4890 const char *sender_address,
4891 uint16_t sender_address_len)
4893 struct TransportPlugin *plugin = cls;
4894 struct SessionHeader *session_header = (struct SessionHeader*) session;
4895 struct TransportPingMessage *ping;
4896 struct TransportPongMessage *pong;
4897 struct NeighbourList *n;
4898 struct ReadyList *rl;
4899 struct ForeignAddressList *fal;
4900 struct OwnAddressList *oal;
4905 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4907 GNUNET_break_op (0);
4908 return GNUNET_SYSERR;
4911 ping = (struct TransportPingMessage *) message;
4912 if (0 != memcmp (&ping->target,
4913 plugin->env.my_identity,
4914 sizeof (struct GNUNET_PeerIdentity)))
4916 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4917 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4919 (sender_address != NULL)
4920 ? a2s (plugin->short_name,
4921 (const struct sockaddr *)sender_address,
4924 GNUNET_i2s (&ping->target));
4925 return GNUNET_SYSERR;
4928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4929 "Processing `%s' from `%s'\n",
4931 (sender_address != NULL)
4932 ? a2s (plugin->short_name,
4933 (const struct sockaddr *)sender_address,
4937 GNUNET_STATISTICS_update (stats,
4938 gettext_noop ("# PING messages received"),
4941 addr = (const char*) &ping[1];
4942 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4943 slen = strlen (plugin->short_name) + 1;
4946 /* peer wants to confirm that we have an outbound connection to him */
4947 if (session == NULL)
4949 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4950 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4952 return GNUNET_SYSERR;
4954 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4955 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4956 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4957 pong->purpose.size =
4958 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4960 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4961 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4962 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4963 pong->challenge = ping->challenge;
4964 pong->addrlen = htonl(sender_address_len + slen);
4967 sizeof(struct GNUNET_PeerIdentity));
4971 if ((sender_address!=NULL) && (sender_address_len > 0))
4972 memcpy (&((char*)&pong[1])[slen],
4974 sender_address_len);
4975 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4977 /* create / update cached sig */
4979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4980 "Creating PONG signature to indicate active connection.\n");
4982 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4983 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4984 GNUNET_assert (GNUNET_OK ==
4985 GNUNET_CRYPTO_rsa_sign (my_private_key,
4987 &session_header->pong_signature));
4991 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4993 memcpy (&pong->signature,
4994 &session_header->pong_signature,
4995 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5001 /* peer wants to confirm that this is one of our addresses */
5005 plugin->api->check_address (plugin->api->cls,
5009 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5010 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5011 a2s (plugin->short_name,
5016 oal = plugin->addresses;
5019 if ( (oal->addrlen == alen) &&
5026 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5027 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5028 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5029 pong->purpose.size =
5030 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5032 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5033 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5034 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5035 pong->challenge = ping->challenge;
5036 pong->addrlen = htonl(alen + slen);
5039 sizeof(struct GNUNET_PeerIdentity));
5040 memcpy (&pong[1], plugin->short_name, slen);
5041 memcpy (&((char*)&pong[1])[slen], addr, alen);
5042 if ( (oal != NULL) &&
5043 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5045 /* create / update cached sig */
5047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5048 "Creating PONG signature to indicate ownership.\n");
5050 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
5051 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5052 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5053 GNUNET_assert (GNUNET_OK ==
5054 GNUNET_CRYPTO_rsa_sign (my_private_key,
5056 &oal->pong_signature));
5057 memcpy (&pong->signature,
5058 &oal->pong_signature,
5059 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5061 else if (oal == NULL)
5063 /* not using cache (typically DV-only) */
5064 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5065 GNUNET_assert (GNUNET_OK ==
5066 GNUNET_CRYPTO_rsa_sign (my_private_key,
5072 /* can used cached version */
5073 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5074 memcpy (&pong->signature,
5075 &oal->pong_signature,
5076 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5079 n = find_neighbour(peer);
5080 GNUNET_assert (n != NULL);
5081 /* first try reliable response transmission */
5085 fal = rl->addresses;
5088 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5091 ntohs (pong->header.size),
5092 TRANSPORT_PONG_PRIORITY,
5093 HELLO_VERIFICATION_TIMEOUT,
5101 GNUNET_STATISTICS_update (stats,
5102 gettext_noop ("# PONGs unicast via reliable transport"),
5112 /* no reliable method found, do multicast */
5113 GNUNET_STATISTICS_update (stats,
5114 gettext_noop ("# PONGs multicast to all available addresses"),
5120 fal = rl->addresses;
5123 transmit_to_peer(NULL, fal,
5124 TRANSPORT_PONG_PRIORITY,
5125 HELLO_VERIFICATION_TIMEOUT,
5127 ntohs(pong->header.size),
5143 * Function called by the plugin for each received message.
5144 * Update data volumes, possibly notify plugins about
5145 * reducing the rate at which they read from the socket
5146 * and generally forward to our receive callback.
5148 * @param cls the "struct TransportPlugin *" we gave to the plugin
5149 * @param peer (claimed) identity of the other peer
5150 * @param message the message, NULL if we only care about
5151 * learning about the delay until we should receive again
5152 * @param ats_data information for automatic transport selection
5153 * @param ats_count number of elements in ats not including 0-terminator
5154 * @param session identifier used for this session (can be NULL)
5155 * @param sender_address binary address of the sender (if observed)
5156 * @param sender_address_len number of bytes in sender_address
5157 * @return how long in ms the plugin should wait until receiving more data
5158 * (plugins that do not support this, can ignore the return value)
5160 static struct GNUNET_TIME_Relative
5161 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5162 const struct GNUNET_MessageHeader *message,
5163 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5165 struct Session *session,
5166 const char *sender_address,
5167 uint16_t sender_address_len)
5169 struct TransportPlugin *plugin = cls;
5170 struct ReadyList *service_context;
5171 struct ForeignAddressList *peer_address;
5173 struct NeighbourList *n;
5174 struct GNUNET_TIME_Relative ret;
5175 if (is_blacklisted (peer, plugin))
5176 return GNUNET_TIME_UNIT_FOREVER_REL;
5180 n = find_neighbour (peer);
5182 n = setup_new_neighbour (peer, GNUNET_YES);
5183 service_context = n->plugins;
5184 while ((service_context != NULL) && (plugin != service_context->plugin))
5185 service_context = service_context->next;
5186 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5187 peer_address = NULL;
5190 for (c=0; c<ats_count; c++)
5192 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5194 distance = ntohl(ats_data[c].value);
5198 /* notify ATS about incoming data */
5199 //ats_notify_ats_data(peer, ats_data);
5202 if (message != NULL)
5204 if ( (session != NULL) ||
5205 (sender_address != NULL) )
5206 peer_address = add_peer_address (n,
5210 sender_address_len);
5211 if (peer_address != NULL)
5214 update_addr_ats(peer_address, ats_data, ats_count);
5215 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5217 peer_address->distance = distance;
5218 if (GNUNET_YES == peer_address->validated)
5219 mark_address_connected (peer_address);
5220 peer_address->timeout
5222 GNUNET_TIME_relative_to_absolute
5223 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5224 schedule_next_ping (peer_address);
5226 /* update traffic received amount ... */
5227 msize = ntohs (message->size);
5229 GNUNET_STATISTICS_update (stats,
5230 gettext_noop ("# bytes received from other peers"),
5233 n->distance = distance;
5235 GNUNET_TIME_relative_to_absolute
5236 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5237 GNUNET_SCHEDULER_cancel (n->timeout_task);
5239 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5240 &neighbour_timeout_task, n);
5241 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5243 /* dropping message due to frequent inbound volume violations! */
5244 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5245 GNUNET_ERROR_TYPE_BULK,
5247 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5248 n->in_tracker.available_bytes_per_s__,
5249 n->quota_violation_count);
5250 GNUNET_STATISTICS_update (stats,
5251 gettext_noop ("# bandwidth quota violations by other peers"),
5254 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5256 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5257 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5259 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5260 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5261 /* Force ressource and quality update */
5264 ats->modified_resources = GNUNET_YES;
5265 ats->modified_quality = GNUNET_YES;
5267 /* Force cost update */
5269 ats->modified_resources = GNUNET_YES;
5270 /* Force quality update */
5272 ats->modified_quality = GNUNET_YES;
5273 /* Force full rebuild */
5275 ats->modified_addr = GNUNET_YES;
5279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5280 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5281 ntohs (message->type),
5282 ntohs (message->size),
5285 switch (ntohs (message->type))
5287 case GNUNET_MESSAGE_TYPE_HELLO:
5288 GNUNET_STATISTICS_update (stats,
5289 gettext_noop ("# HELLO messages received from other peers"),
5292 process_hello (plugin, message);
5294 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5295 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5297 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5298 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5300 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5303 handle_payload_message (message, n);
5307 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5308 if (ret.rel_value > 0)
5310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5311 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5312 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5313 (unsigned int) n->in_tracker.available_bytes_per_s__,
5314 (unsigned long long) ret.rel_value);
5315 GNUNET_STATISTICS_update (stats,
5316 gettext_noop ("# ms throttling suggested"),
5317 (int64_t) ret.rel_value,
5324 * Handle START-message. This is the first message sent to us
5325 * by any client which causes us to add it to our list.
5327 * @param cls closure (always NULL)
5328 * @param client identification of the client
5329 * @param message the actual message
5332 handle_start (void *cls,
5333 struct GNUNET_SERVER_Client *client,
5334 const struct GNUNET_MessageHeader *message)
5336 const struct StartMessage *start;
5337 struct TransportClient *c;
5338 struct ConnectInfoMessage * cim;
5339 struct NeighbourList *n;
5343 start = (const struct StartMessage*) message;
5345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5346 "Received `%s' request from client\n", "START");
5351 if (c->client == client)
5353 /* client already on our list! */
5355 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5360 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5361 (0 != memcmp (&start->self,
5363 sizeof (struct GNUNET_PeerIdentity))) )
5365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5366 _("Rejecting control connection from peer `%s', which is not me!\n"),
5367 GNUNET_i2s (&start->self));
5368 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5371 c = GNUNET_malloc (sizeof (struct TransportClient));
5375 if (our_hello != NULL)
5378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5379 "Sending our own `%s' to new client\n", "HELLO");
5381 transmit_to_client (c,
5382 (const struct GNUNET_MessageHeader *) our_hello,
5384 /* tell new client about all existing connections */
5386 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5387 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5391 cim = GNUNET_malloc (size);
5392 cim->header.size = htons (size);
5393 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5394 cim->ats_count = htonl(ats_count);
5395 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5396 (&(cim->ats))[2].value = htonl (0);
5400 if (GNUNET_YES == n->received_pong)
5402 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5403 (&(cim->ats))[0].value = htonl (n->distance);
5404 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5405 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5407 transmit_to_client (c, &cim->header, GNUNET_NO);
5413 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5418 * Handle HELLO-message.
5420 * @param cls closure (always NULL)
5421 * @param client identification of the client
5422 * @param message the actual message
5425 handle_hello (void *cls,
5426 struct GNUNET_SERVER_Client *client,
5427 const struct GNUNET_MessageHeader *message)
5431 GNUNET_STATISTICS_update (stats,
5432 gettext_noop ("# HELLOs received from clients"),
5435 ret = process_hello (NULL, message);
5436 GNUNET_SERVER_receive_done (client, ret);
5441 * Closure for 'transmit_client_message'; followed by
5442 * 'msize' bytes of the actual message.
5444 struct TransmitClientMessageContext
5447 * Client on whom's behalf we are sending.
5449 struct GNUNET_SERVER_Client *client;
5452 * Timeout for the transmission.
5454 struct GNUNET_TIME_Absolute timeout;
5462 * Size of the message in bytes.
5469 * Schedule transmission of a message we got from a client to a peer.
5471 * @param cls the 'struct TransmitClientMessageContext*'
5472 * @param n destination, or NULL on error (in that case, drop the message)
5475 transmit_client_message (void *cls,
5476 struct NeighbourList *n)
5478 struct TransmitClientMessageContext *tcmc = cls;
5479 struct TransportClient *tc;
5482 while ((tc != NULL) && (tc->client != tcmc->client))
5487 transmit_to_peer (tc, NULL, tcmc->priority,
5488 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5490 tcmc->msize, GNUNET_NO, n);
5492 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5493 GNUNET_SERVER_client_drop (tcmc->client);
5499 * Handle SEND-message.
5501 * @param cls closure (always NULL)
5502 * @param client identification of the client
5503 * @param message the actual message
5506 handle_send (void *cls,
5507 struct GNUNET_SERVER_Client *client,
5508 const struct GNUNET_MessageHeader *message)
5510 const struct OutboundMessage *obm;
5511 const struct GNUNET_MessageHeader *obmm;
5512 struct TransmitClientMessageContext *tcmc;
5516 size = ntohs (message->size);
5518 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5521 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5524 GNUNET_STATISTICS_update (stats,
5525 gettext_noop ("# payload received for other peers"),
5528 obm = (const struct OutboundMessage *) message;
5529 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5530 msize = size - sizeof (struct OutboundMessage);
5532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5533 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5534 "SEND", GNUNET_i2s (&obm->peer),
5538 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5539 tcmc->client = client;
5540 tcmc->priority = ntohl (obm->priority);
5541 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5542 tcmc->msize = msize;
5543 /* FIXME: this memcpy can be up to 7% of our total runtime */
5544 memcpy (&tcmc[1], obmm, msize);
5545 GNUNET_SERVER_client_keep (client);
5546 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5547 &transmit_client_message,
5553 * Handle request connect message
5555 * @param cls closure (always NULL)
5556 * @param client identification of the client
5557 * @param message the actual message
5560 handle_request_connect (void *cls,
5561 struct GNUNET_SERVER_Client *client,
5562 const struct GNUNET_MessageHeader *message)
5564 const struct TransportRequestConnectMessage *trcm =
5565 (const struct TransportRequestConnectMessage *) message;
5567 GNUNET_STATISTICS_update (stats,
5568 gettext_noop ("# REQUEST CONNECT messages received"),
5571 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5572 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5574 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5578 * Handle SET_QUOTA-message.
5580 * @param cls closure (always NULL)
5581 * @param client identification of the client
5582 * @param message the actual message
5585 handle_set_quota (void *cls,
5586 struct GNUNET_SERVER_Client *client,
5587 const struct GNUNET_MessageHeader *message)
5589 const struct QuotaSetMessage *qsm =
5590 (const struct QuotaSetMessage *) message;
5591 struct NeighbourList *n;
5593 GNUNET_STATISTICS_update (stats,
5594 gettext_noop ("# SET QUOTA messages received"),
5597 n = find_neighbour (&qsm->peer);
5600 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5601 GNUNET_STATISTICS_update (stats,
5602 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5609 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5611 (unsigned int) ntohl (qsm->quota.value__),
5612 (unsigned int) n->in_tracker.available_bytes_per_s__,
5613 GNUNET_i2s (&qsm->peer));
5615 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5617 if (0 == ntohl (qsm->quota.value__))
5619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5620 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5622 disconnect_neighbour (n, GNUNET_NO);
5624 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5629 * Take the given address and append it to the set of results sent back to
5632 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5633 * @param address the resolved name, NULL to indicate the last response
5636 transmit_address_to_client (void *cls, const char *address)
5638 struct GNUNET_SERVER_TransmitContext *tc = cls;
5641 if (NULL == address)
5644 slen = strlen (address) + 1;
5646 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5647 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5648 if (NULL == address)
5649 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5654 * Handle AddressLookup-message.
5656 * @param cls closure (always NULL)
5657 * @param client identification of the client
5658 * @param message the actual message
5661 handle_address_lookup (void *cls,
5662 struct GNUNET_SERVER_Client *client,
5663 const struct GNUNET_MessageHeader *message)
5665 const struct AddressLookupMessage *alum;
5666 struct TransportPlugin *lsPlugin;
5667 const char *nameTransport;
5668 const char *address;
5670 struct GNUNET_SERVER_TransmitContext *tc;
5671 struct GNUNET_TIME_Absolute timeout;
5672 struct GNUNET_TIME_Relative rtimeout;
5675 size = ntohs (message->size);
5676 if (size < sizeof (struct AddressLookupMessage))
5678 GNUNET_break_op (0);
5679 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5682 alum = (const struct AddressLookupMessage *) message;
5683 uint32_t addressLen = ntohl (alum->addrlen);
5684 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5686 GNUNET_break_op (0);
5687 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5690 address = (const char *) &alum[1];
5691 nameTransport = (const char *) &address[addressLen];
5693 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5695 GNUNET_break_op (0);
5696 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5699 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5700 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5701 numeric = ntohl (alum->numeric_only);
5702 lsPlugin = find_transport (nameTransport);
5703 if (NULL == lsPlugin)
5705 tc = GNUNET_SERVER_transmit_context_create (client);
5706 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5707 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5708 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5711 tc = GNUNET_SERVER_transmit_context_create (client);
5712 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5714 address, addressLen,
5717 &transmit_address_to_client, tc);
5722 * Setup the environment for this plugin.
5725 create_environment (struct TransportPlugin *plug)
5727 plug->env.cfg = cfg;
5728 plug->env.my_identity = &my_identity;
5729 plug->env.our_hello = &our_hello;
5730 plug->env.cls = plug;
5731 plug->env.receive = &plugin_env_receive;
5732 plug->env.notify_address = &plugin_env_notify_address;
5733 plug->env.session_end = &plugin_env_session_end;
5734 plug->env.max_connections = max_connect_per_transport;
5735 plug->env.stats = stats;
5740 * Start the specified transport (load the plugin).
5743 start_transport (struct GNUNET_SERVER_Handle *server,
5746 struct TransportPlugin *plug;
5749 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5750 _("Loading `%s' transport plugin\n"), name);
5751 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5752 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5753 create_environment (plug);
5754 plug->short_name = GNUNET_strdup (name);
5755 plug->lib_name = libname;
5756 plug->next = plugins;
5758 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5759 if (plug->api == NULL)
5761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5762 _("Failed to load transport plugin for `%s'\n"), name);
5763 GNUNET_free (plug->short_name);
5764 plugins = plug->next;
5765 GNUNET_free (libname);
5772 * Called whenever a client is disconnected. Frees our
5773 * resources associated with that client.
5775 * @param cls closure
5776 * @param client identification of the client
5779 client_disconnect_notification (void *cls,
5780 struct GNUNET_SERVER_Client *client)
5782 struct TransportClient *pos;
5783 struct TransportClient *prev;
5784 struct ClientMessageQueueEntry *mqe;
5785 struct Blacklisters *bl;
5786 struct BlacklistCheck *bc;
5791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5792 "Client disconnected, cleaning up.\n");
5794 /* clean up blacklister */
5798 if (bl->client == client)
5803 if (bc->bl_pos == bl)
5805 bc->bl_pos = bl->next;
5808 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5811 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5812 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5818 GNUNET_CONTAINER_DLL_remove (bl_head,
5821 GNUNET_SERVER_client_drop (bl->client);
5827 /* clean up 'normal' clients */
5830 while ((pos != NULL) && (pos->client != client))
5837 while (NULL != (mqe = pos->message_queue_head))
5839 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5840 pos->message_queue_tail,
5842 pos->message_count--;
5846 clients = pos->next;
5848 prev->next = pos->next;
5849 if (GNUNET_YES == pos->tcs_pending)
5854 if (pos->th != NULL)
5856 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5859 GNUNET_break (0 == pos->message_count);
5865 * Function called when the service shuts down. Unloads our plugins
5866 * and cancels pending validations.
5868 * @param cls closure, unused
5869 * @param tc task context (unused)
5872 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5874 struct TransportPlugin *plug;
5875 struct OwnAddressList *al;
5876 struct CheckHelloValidatedContext *chvc;
5878 while (neighbours != NULL)
5880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5881 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5883 disconnect_neighbour (neighbours, GNUNET_NO);
5886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5887 "Transport service is unloading plugins...\n");
5889 while (NULL != (plug = plugins))
5891 plugins = plug->next;
5892 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5894 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5895 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5897 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5898 GNUNET_free (plug->lib_name);
5899 GNUNET_free (plug->short_name);
5900 while (NULL != (al = plug->addresses))
5902 plug->addresses = al->next;
5907 if (my_private_key != NULL)
5908 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5909 GNUNET_free_non_null (our_hello);
5911 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5914 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5915 validation_map = NULL;
5919 /* free 'chvc' data structure */
5920 while (NULL != (chvc = chvc_head))
5922 chvc_head = chvc->next;
5923 if (chvc->piter != NULL)
5925 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5926 GNUNET_STATISTICS_update (stats,
5927 gettext_noop ("# outstanding peerinfo iterate requests"),
5933 GNUNET_assert (chvc->ve_count == 0);
5940 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5943 if (peerinfo != NULL)
5945 GNUNET_PEERINFO_disconnect (peerinfo);
5948 /* Can we assume those are gone by now, or do we need to clean up
5950 GNUNET_break (bl_head == NULL);
5951 GNUNET_break (bc_head == NULL);
5955 static int ats_evaluate_results (int result, int solution, char * problem)
5957 int cont = GNUNET_NO;
5958 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5960 error_kind = GNUNET_ERROR_TYPE_ERROR;
5964 case GLP_ESTOP : /* search terminated by application */
5965 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5967 case GLP_EITLIM : /* iteration limit exceeded */
5968 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5971 case GLP_ETMLIM : /* time limit exceeded */
5972 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5974 case GLP_ENOPFS : /* no primal feasible solution */
5975 case GLP_ENODFS : /* no dual feasible solution */
5976 GNUNET_log (error_kind, "%s No feasible solution", problem);
5979 case GLP_EBADB : /* invalid basis */
5980 case GLP_ESING : /* singular matrix */
5981 case GLP_ECOND : /* ill-conditioned matrix */
5982 case GLP_EBOUND : /* invalid bounds */
5983 case GLP_EFAIL : /* solver failed */
5984 case GLP_EOBJLL : /* objective lower limit reached */
5985 case GLP_EOBJUL : /* objective upper limit reached */
5986 case GLP_EROOT : /* root LP optimum not provided */
5987 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5991 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5997 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
6000 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
6004 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"));
6008 GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem, (0==strcmp(problem,"LP")?"":"integer "));
6011 GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
6014 GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
6022 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)
6028 glp_prob *prob = ats->prob;
6031 glp_init_smcp(&opt_lp);
6034 opt_lp.msg_lev = GLP_MSG_ALL;
6036 opt_lp.msg_lev = GLP_MSG_OFF;
6038 //opt_lp.presolve = GLP_ON;
6039 result = glp_simplex(prob, &opt_lp);
6040 solution = glp_get_status (prob);
6042 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
6046 glp_init_iocp(&opt_mlp);
6047 /* maximum duration */
6048 //opt_mlp.presolve = GLP_ON;
6049 opt_mlp.tm_lim = max_dur;
6052 opt_mlp.msg_lev = GLP_MSG_ALL;
6054 opt_mlp.msg_lev = GLP_MSG_OFF;
6056 result = glp_intopt (prob, &opt_mlp);
6057 solution = glp_mip_status (prob);
6058 stat->solution = solution;
6059 stat->valid = GNUNET_NO;
6060 if (ats_evaluate_results(result, solution, "MLP") == GNUNET_YES)
6061 stat->valid = GNUNET_YES;
6065 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
6068 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6069 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6070 glp_write_lp (prob, NULL, filename);
6071 GNUNET_free (filename);
6073 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
6076 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6077 //if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6078 glp_print_sol (prob, filename);
6079 GNUNET_free (filename);
6084 int error = GNUNET_NO;
6086 struct ATS_mechanism *t = NULL;
6087 for (c=1; c<= (c_peers); c++ )
6090 t = peers[c].m_head;
6093 bw = glp_get_col_prim(prob, t->col_index);
6097 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);
6099 if (check ==GNUNET_YES)
6101 glp_write_sol(prob, "invalid_solution.mlp");
6102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6103 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6106 if (check ==GNUNET_NO)
6114 if (glp_get_col_prim(prob,2*c_mechs+1) != 1)
6117 for (c=1; c<= available_quality_metrics; c++ )
6119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3+c), glp_get_col_prim(prob,2*c_mechs+3+c));
6121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+1), glp_get_col_prim(prob,2*c_mechs+1));
6122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+2), glp_get_col_prim(prob,2*c_mechs+2));
6123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3), glp_get_col_prim(prob,2*c_mechs+3));
6124 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value: %f\n", glp_mip_obj_val(ats->prob));
6129 static void ats_delete_problem ()
6133 for (c=0; c< (ats->stat).c_mechs; c++)
6134 GNUNET_free_non_null (ats->mechanisms[c].rc);
6136 if (ats->mechanisms!=NULL)
6138 GNUNET_free(ats->mechanisms);
6139 ats->mechanisms = NULL;
6141 if (ats->peers!=NULL)
6143 GNUNET_free(ats->peers);
6147 if (ats->prob != NULL)
6149 glp_delete_prob(ats->prob);
6153 ats->stat.begin_cr = GNUNET_SYSERR;
6154 ats->stat.begin_qm = GNUNET_SYSERR;
6155 ats->stat.c_mechs = 0;
6156 ats->stat.c_peers = 0;
6157 ats->stat.end_cr = GNUNET_SYSERR;
6158 ats->stat.end_qm = GNUNET_SYSERR;
6159 ats->stat.solution = GNUNET_SYSERR;
6160 ats->stat.valid = GNUNET_SYSERR;
6163 static void ats_update_problem_qm ()
6168 int c_q_metrics = available_quality_metrics;
6170 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6171 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6175 row_index = ats->stat.begin_qm;
6177 for (c=1; c <= c_q_metrics; c++)
6182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6185 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6186 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6188 ja[array_index] = c2;
6190 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6193 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6194 if (v1 < 1) v0 = 0.1;
6195 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6196 if (v1 < 1) v0 = 0.1;
6197 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6198 if (v1 < 1) v0 = 0.1;
6199 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6202 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6205 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6207 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6209 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6211 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6213 value = (double) 10 / value;
6217 ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6219 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]);
6223 ja[array_index] = ats->stat.col_qm + c - 1;
6224 ar[array_index] = -1;
6227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6229 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6235 GNUNET_free_non_null (ja);
6236 GNUNET_free_non_null (ar);
6241 static void ats_update_problem_cr ()
6247 double ct_max, ct_min;
6249 int *ja = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6250 double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6253 row_index = ats->stat.begin_cr;
6255 for (c=0; c<available_ressources; c++)
6257 ct_max = ressources[c].c_max;
6258 ct_min = ressources[c].c_min;
6260 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6262 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6264 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6267 ja[array_index] = c2;
6268 value = ats->mechanisms[c2].addr->ressources[c].c;
6269 ar[array_index] = value;
6271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6275 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6281 GNUNET_free_non_null (ja);
6282 GNUNET_free_non_null (ar);
6286 /** solve the bandwidth distribution problem
6287 * @param max_it maximum iterations
6288 * @param max_dur maximum duration in ms
6289 * @param D weight for diversity
6290 * @param U weight for utility
6291 * @param R weight for relativity
6292 * @param v_b_min minimal bandwidth per peer
6293 * @param v_n_min minimum number of connections
6294 * @param stat result struct
6295 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6297 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
6299 if (ats->prob != NULL)
6300 glp_delete_prob(ats->prob);
6302 ats->prob = glp_create_prob();
6308 int c_c_ressources = available_ressources;
6309 int c_q_metrics = available_quality_metrics;
6311 double M = VERY_BIG_DOUBLE_VALUE;
6312 double Q[c_q_metrics+1];
6313 for (c=1; c<=c_q_metrics; c++)
6318 struct NeighbourList *next = neighbours;
6321 struct ReadyList *r_next = next->plugins;
6322 while (r_next != NULL)
6324 struct ForeignAddressList * a_next = r_next->addresses;
6325 while (a_next != NULL)
6328 a_next = a_next->next;
6330 r_next = r_next->next;
6339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6341 stat->valid = GNUNET_NO;
6344 return GNUNET_SYSERR;
6347 ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6348 ats->peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6350 struct ATS_mechanism * mechanisms = ats->mechanisms;
6351 struct ATS_peer * peers = ats->peers;
6358 peers[c_peers].peer = next->id;
6359 peers[c_peers].m_head = NULL;
6360 peers[c_peers].m_tail = NULL;
6362 peers[c_peers].f = 1.0 / c_mechs;
6364 struct ReadyList *r_next = next->plugins;
6365 while (r_next != NULL)
6367 struct ForeignAddressList * a_next = r_next->addresses;
6368 while (a_next != NULL)
6370 mechanisms[c_mechs].addr = a_next;
6371 mechanisms[c_mechs].col_index = c_mechs;
6372 mechanisms[c_mechs].peer = &peers[c_peers];
6373 mechanisms[c_mechs].next = NULL;
6374 mechanisms[c_mechs].plugin = r_next->plugin;
6376 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6378 a_next = a_next->next;
6380 r_next = r_next->next;
6388 if (v_n_min > c_peers)
6392 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);
6395 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6398 int * ia = GNUNET_malloc (size * sizeof (int));
6399 int * ja = GNUNET_malloc (size * sizeof (int));
6400 double * ar = GNUNET_malloc(size* sizeof (double));
6402 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6403 glp_set_obj_dir(ats->prob, GLP_MAX);
6405 /* adding columns */
6407 glp_add_cols(ats->prob, 2 * c_mechs);
6408 /* adding b_t cols */
6409 for (c=1; c <= c_mechs; c++)
6412 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6413 glp_set_col_name(ats->prob, c, name);
6415 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6416 glp_set_obj_coef(ats->prob, c, 0);
6419 /* adding n_t cols */
6420 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6422 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6423 glp_set_col_name(ats->prob, c, name);
6425 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6426 glp_set_col_kind(ats->prob, c, GLP_IV);
6427 glp_set_obj_coef(ats->prob, c, 0);
6430 /* feasibility constraints */
6431 /* Constraint 1: one address per peer*/
6433 glp_add_rows(ats->prob, c_peers);
6434 for (c=1; c<=c_peers; c++)
6436 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6438 struct ATS_mechanism *m = peers[c].m_head;
6441 ia[array_index] = row_index;
6442 ja[array_index] = (c_mechs + m->col_index);
6443 ar[array_index] = 1;
6445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6453 /* Constraint 2: only active mechanism gets bandwidth assigned */
6454 glp_add_rows(ats->prob, c_mechs);
6455 for (c=1; c<=c_mechs; c++)
6457 /* b_t - n_t * M <= 0 */
6459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6461 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6463 ia[array_index] = row_index;
6464 ja[array_index] = mechanisms[c].col_index;
6465 ar[array_index] = 1;
6467 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6470 ia[array_index] = row_index;
6471 ja[array_index] = c_mechs + mechanisms[c].col_index;
6472 ar[array_index] = -M;
6474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6480 /* Constraint 3: minimum bandwidth*/
6481 glp_add_rows(ats->prob, c_mechs);
6482 for (c=1; c<=c_mechs; c++)
6484 /* b_t - n_t * b_min <= 0 */
6486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6488 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6490 ia[array_index] = row_index;
6491 ja[array_index] = mechanisms[c].col_index;
6492 ar[array_index] = 1;
6494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6497 ia[array_index] = row_index;
6498 ja[array_index] = c_mechs + mechanisms[c].col_index;
6499 ar[array_index] = -v_b_min;
6501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6507 /* Constraint 4: max ressource capacity */
6508 /* V cr: bt * ct_r <= cr_max
6510 glp_add_rows(ats->prob, available_ressources);
6511 double ct_max = VERY_BIG_DOUBLE_VALUE;
6512 double ct_min = 0.0;
6514 stat->begin_cr = array_index;
6516 for (c=0; c<available_ressources; c++)
6518 ct_max = ressources[c].c_max;
6519 ct_min = ressources[c].c_min;
6521 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6523 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6525 for (c2=1; c2<=c_mechs; c2++)
6528 ia[array_index] = row_index;
6529 ja[array_index] = c2;
6530 value = mechanisms[c2].addr->ressources[c].c;
6531 ar[array_index] = value;
6533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6539 stat->end_cr = array_index--;
6541 /* Constraint 5: min number of connections*/
6542 glp_add_rows(ats->prob, 1);
6543 for (c=1; c<=c_mechs; c++)
6545 // b_t - n_t * b_min >= 0
6547 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6549 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6551 ia[array_index] = row_index;
6552 ja[array_index] = c_mechs + mechanisms[c].col_index;
6553 ar[array_index] = 1;
6555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6561 // optimisation constraints
6565 // Constraint 6: optimize for diversity
6567 col_d = glp_add_cols(ats->prob, 1);
6568 stat->col_d = col_d;
6569 //GNUNET_assert (col_d == (2*c_mechs) + 1);
6570 glp_set_col_name(ats->prob, col_d, "d");
6571 glp_set_obj_coef(ats->prob, col_d, D);
6572 glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
6573 glp_add_rows(ats->prob, 1);
6575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6577 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6578 for (c=1; c<=c_mechs; c++)
6580 // b_t - n_t * b_min >= 0
6581 ia[array_index] = row_index;
6582 ja[array_index] = c_mechs + mechanisms[c].col_index;
6583 ar[array_index] = 1;
6585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6589 ia[array_index] = row_index;
6590 ja[array_index] = col_d;
6591 ar[array_index] = -1;
6593 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6599 // Constraint 7: optimize for quality
6601 col_qm = glp_add_cols(ats->prob, c_q_metrics);
6602 stat->col_qm = col_qm;
6603 //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
6604 for (c=0; c< c_q_metrics; c++)
6606 GNUNET_asprintf(&name, "Q_%s",qm[c].name);
6607 glp_set_col_name(ats->prob, col_qm + c, name);
6608 glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
6610 glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
6612 glp_add_rows(ats->prob, available_quality_metrics);
6613 stat->begin_qm = row_index;
6614 for (c=1; c <= c_q_metrics; c++)
6617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6620 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6621 for (c2=1; c2<=c_mechs; c2++)
6624 ia[array_index] = row_index;
6625 ja[array_index] = c2;
6626 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6629 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6630 if (v1 < 1) v0 = 0.1;
6631 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6632 if (v1 < 1) v0 = 0.1;
6633 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6634 if (v1 < 1) v0 = 0.1;
6635 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6638 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6641 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6643 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6645 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6647 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6649 value = (double) 10 / value;
6653 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6655 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]);
6660 ia[array_index] = row_index;
6661 ja[array_index] = col_qm + c - 1;
6662 ar[array_index] = -1;
6664 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6669 stat->end_qm = row_index-1;
6671 // Constraint 8: optimize bandwidth utility
6673 col_u = glp_add_cols(ats->prob, 1);
6674 stat->col_u = col_u;
6675 //GNUNET_assert (col_u == (2*c_mechs) + 2);
6676 glp_set_col_name(ats->prob, col_u, "u");
6677 glp_set_obj_coef(ats->prob, col_u, U);
6678 glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
6679 glp_add_rows(ats->prob, 1);
6681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6683 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6684 for (c=1; c<=c_mechs; c++)
6686 ia[array_index] = row_index;
6687 ja[array_index] = c;
6688 ar[array_index] = mechanisms[c].peer->f;
6690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6694 ia[array_index] = row_index;
6695 ja[array_index] = col_u;
6696 ar[array_index] = -1;
6698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6704 // Constraint 9: optimize relativity
6706 col_r = glp_add_cols(ats->prob, 1);
6707 stat->col_r = col_r;
6708 //GNUNET_assert (col_r == (2*c_mechs) + 3);
6709 glp_set_col_name(ats->prob, col_r, "r");
6710 glp_set_obj_coef(ats->prob, col_r, R);
6711 glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
6712 glp_add_rows(ats->prob, c_peers);
6713 for (c=1; c<=c_peers; c++)
6715 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6717 struct ATS_mechanism *m = peers[c].m_head;
6720 ia[array_index] = row_index;
6721 ja[array_index] = m->col_index;
6722 ar[array_index] = 1 / mechanisms[c].peer->f;
6724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6729 ia[array_index] = row_index;
6730 ja[array_index] = col_r;
6731 ar[array_index] = -1;
6733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6740 /* Loading the matrix */
6741 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6743 stat->c_mechs = c_mechs;
6744 stat->c_peers = c_peers;
6746 stat->valid = GNUNET_YES;
6758 void ats_notify_ats_data (
6759 const struct GNUNET_PeerIdentity *peer,
6760 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6763 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6765 ats_calculate_bandwidth_distribution(ats);
6771 ats_calculate_bandwidth_distribution ()
6774 struct GNUNET_TIME_Absolute start;
6775 struct GNUNET_TIME_Relative creation;
6776 struct GNUNET_TIME_Relative solving;
6778 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6779 if (delta.rel_value < ats->min_delta.rel_value)
6782 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6788 if (INT_MAX < ats->max_exec_duration.rel_value)
6791 dur = (int) ats->max_exec_duration.rel_value;
6793 start = GNUNET_TIME_absolute_get();
6794 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6796 ats_delete_problem ();
6797 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
6799 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);
6802 else if (ats->modified_resources == GNUNET_YES)
6804 ats_update_problem_cr();
6806 else if (ats->modified_quality == GNUNET_YES)
6808 ats_update_problem_qm();
6811 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6814 creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6815 start = GNUNET_TIME_absolute_get();
6817 if (ats->stat.valid == GNUNET_YES)
6819 ats->stat.solution = GNUNET_SYSERR;
6820 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
6821 if (ats->stat.solution != 5)
6822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem solution is not optimal: %i\n", ats->stat.solution);
6825 solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6827 if (ats->stat.valid == GNUNET_YES)
6830 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP: creation time in [ms] %llu execution time in [ms] %llu for %i mechanisms\n", creation.rel_value, solving.rel_value, ats->stat.c_mechs);
6832 GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
6833 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
6834 GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
6835 GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
6836 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6837 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6838 GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
6839 else if ((ats->modified_resources == GNUNET_YES) && (ats->modified_quality == GNUNET_NO))
6840 GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
6841 else if ((ats->modified_resources == GNUNET_NO) && (ats->modified_quality == GNUNET_YES))
6842 GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
6843 else if ((ats->modified_resources == GNUNET_YES) && (ats->modified_quality == GNUNET_YES))
6844 GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
6846 GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
6850 else if (ats->stat.valid == GNUNET_NO)
6852 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6855 ats->last = GNUNET_TIME_absolute_get();
6857 ats->modified_addr = GNUNET_NO;
6858 ats->modified_resources = GNUNET_NO;
6859 ats->modified_quality = GNUNET_NO;
6866 ats_schedule_calculation (void *cls,
6867 const struct GNUNET_SCHEDULER_TaskContext *tc)
6869 struct ATS_info *ats = (struct ATS_info *) cls;
6873 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6874 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6881 ats_calculate_bandwidth_distribution (ats);
6883 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6884 &ats_schedule_calculation, ats);
6890 unsigned long long value;
6893 ats = GNUNET_malloc(sizeof (struct ATS_info));
6895 ats->min_delta = ATS_MIN_INTERVAL;
6896 ats->exec_intervall = ATS_EXEC_INTERVAL;
6897 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6898 ats->max_iterations = ATS_MAX_ITERATIONS;
6899 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6902 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active\n");
6909 ats->v_b_min = 64000;
6915 /* loading cost ressources */
6916 for (c=0; c<available_ressources; c++)
6918 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6919 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6921 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6926 ressources[c].c_max = value;
6929 GNUNET_free (section);
6930 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6931 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6933 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6936 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6938 ressources[c].c_min = value;
6941 GNUNET_free (section);
6944 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6945 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6947 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6948 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6950 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6954 static void ats_shutdown ()
6957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6959 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6960 GNUNET_SCHEDULER_cancel(ats->ats_task);
6961 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6963 ats_delete_problem ();
6969 void ats_notify_peer_connect (
6970 const struct GNUNET_PeerIdentity *peer,
6971 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
6974 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6977 //update_addr_ats();
6978 ats->modified_addr = GNUNET_YES;
6980 ats_calculate_bandwidth_distribution(ats);
6983 void ats_notify_peer_disconnect (
6984 const struct GNUNET_PeerIdentity *peer)
6987 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6990 ats->modified_addr = GNUNET_YES;
6992 ats_calculate_bandwidth_distribution (ats);
6995 struct ForeignAddressList * ats_get_preferred_address (
6996 struct NeighbourList *n)
6999 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
7001 struct ReadyList *next = n->plugins;
7002 while (next != NULL)
7005 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
7009 return find_ready_address(n);
7013 * Initiate transport service.
7015 * @param cls closure
7016 * @param server the initialized server
7017 * @param c configuration to use
7021 struct GNUNET_SERVER_Handle *server,
7022 const struct GNUNET_CONFIGURATION_Handle *c)
7024 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
7025 {&handle_start, NULL,
7026 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
7027 {&handle_hello, NULL,
7028 GNUNET_MESSAGE_TYPE_HELLO, 0},
7029 {&handle_send, NULL,
7030 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
7031 {&handle_request_connect, NULL,
7032 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
7033 {&handle_set_quota, NULL,
7034 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
7035 {&handle_address_lookup, NULL,
7036 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
7038 {&handle_blacklist_init, NULL,
7039 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
7040 {&handle_blacklist_reply, NULL,
7041 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
7047 unsigned long long tneigh;
7051 stats = GNUNET_STATISTICS_create ("transport", cfg);
7052 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
7053 /* parse configuration */
7055 GNUNET_CONFIGURATION_get_value_number (c,
7060 GNUNET_CONFIGURATION_get_value_filename (c,
7062 "HOSTKEY", &keyfile)))
7064 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7066 ("Transport service is lacking key configuration settings. Exiting.\n"));
7067 GNUNET_SCHEDULER_shutdown ();
7070 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7073 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7074 validation_map = NULL;
7078 max_connect_per_transport = (uint32_t) tneigh;
7079 peerinfo = GNUNET_PEERINFO_connect (cfg);
7080 if (peerinfo == NULL)
7082 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7083 _("Could not access PEERINFO service. Exiting.\n"));
7084 GNUNET_SCHEDULER_shutdown ();
7087 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7090 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7091 validation_map = NULL;
7092 GNUNET_free (keyfile);
7095 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
7096 GNUNET_free (keyfile);
7097 if (my_private_key == NULL)
7099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7101 ("Transport service could not access hostkey. Exiting.\n"));
7102 GNUNET_SCHEDULER_shutdown ();
7105 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7108 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7109 validation_map = NULL;
7112 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
7113 GNUNET_CRYPTO_hash (&my_public_key,
7114 sizeof (my_public_key), &my_identity.hashPubKey);
7115 /* setup notification */
7116 GNUNET_SERVER_disconnect_notify (server,
7117 &client_disconnect_notification, NULL);
7118 /* load plugins... */
7121 GNUNET_CONFIGURATION_get_value_string (c,
7122 "TRANSPORT", "PLUGINS", &plugs))
7124 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7125 _("Starting transport plugins `%s'\n"), plugs);
7126 pos = strtok (plugs, " ");
7129 start_transport (server, pos);
7131 pos = strtok (NULL, " ");
7133 GNUNET_free (plugs);
7135 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
7136 &shutdown_task, NULL);
7143 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7145 /* If we have a blacklist file, read from it */
7146 read_blacklist_file(cfg);
7147 /* process client requests */
7148 GNUNET_SERVER_add_handlers (server, handlers);
7153 * The main function for the transport service.
7155 * @param argc number of arguments from the command line
7156 * @param argv command line arguments
7157 * @return 0 ok, 1 on error
7160 main (int argc, char *const *argv)
7162 a2s (NULL, NULL, 0); /* make compiler happy */
7163 return (GNUNET_OK ==
7164 GNUNET_SERVICE_run (argc,
7167 GNUNET_SERVICE_OPTION_NONE,
7168 &run, NULL)) ? 0 : 1;
7171 /* end of gnunet-service-transport.c */