2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_ATS GNUNET_NO
53 #define VERBOSE_ATS GNUNET_NO
56 * Should we do some additional checks (to validate behavior
59 #define EXTRA_CHECKS GNUNET_YES
62 * How many messages can we have pending for a given client process
63 * before we start to drop incoming messages? We typically should
64 * have only one client and so this would be the primary buffer for
65 * messages, so the number should be chosen rather generously.
67 * The expectation here is that most of the time the queue is large
68 * enough so that a drop is virtually never required. Note that
69 * this value must be about as large as 'TOTAL_MSGS' in the
70 * 'test_transport_api_reliability.c', otherwise that testcase may
73 #define MAX_PENDING (128 * 1024)
76 * Size of the per-transport blacklist hash maps.
78 #define TRANSPORT_BLACKLIST_HT_SIZE 16
81 * How often should we try to reconnect to a peer using a particular
82 * transport plugin before giving up? Note that the plugin may be
83 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
85 #define MAX_CONNECT_RETRY 3
88 * Limit on the number of ready-to-run tasks when validating
89 * HELLOs. If more tasks are ready to run, we will drop
90 * HELLOs instead of validating them.
92 #define MAX_HELLO_LOAD 4
95 * How often must a peer violate bandwidth quotas before we start
96 * to simply drop its messages?
98 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
101 * How long until a HELLO verification attempt should time out?
102 * Must be rather small, otherwise a partially successful HELLO
103 * validation (some addresses working) might not be available
104 * before a client's request for a connection fails for good.
105 * Besides, if a single request to an address takes a long time,
106 * then the peer is unlikely worthwhile anyway.
108 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
111 * How long is a PONG signature valid? We'll recycle a signature until
112 * 1/4 of this time is remaining. PONGs should expire so that if our
113 * external addresses change an adversary cannot replay them indefinitely.
114 * OTOH, we don't want to spend too much time generating PONG signatures,
115 * so they must have some lifetime to reduce our CPU usage.
117 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
120 * Priority to use for PONG messages.
122 #define TRANSPORT_PONG_PRIORITY 4
125 * How often do we re-add (cheaper) plugins to our list of plugins
126 * to try for a given connected peer?
128 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
131 * After how long do we expire an address in a HELLO that we just
132 * validated? This value is also used for our own addresses when we
135 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
139 * How long before an existing address expires should we again try to
140 * validate it? Must be (significantly) smaller than
141 * HELLO_ADDRESS_EXPIRATION.
143 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
146 * Maximum frequency for re-evaluating latencies for all transport addresses.
148 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
151 * Maximum frequency for re-evaluating latencies for connected addresses.
153 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
155 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
158 * List of addresses of other peers
160 struct ForeignAddressList
163 * This is a linked list.
165 struct ForeignAddressList *next;
168 * Which ready list does this entry belong to.
170 struct ReadyList *ready_list;
173 * How long until we auto-expire this address (unless it is
174 * re-confirmed by the transport)?
176 struct GNUNET_TIME_Absolute expires;
179 * Task used to re-validate addresses, updates latencies and
182 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
190 * Session (or NULL if no valid session currently exists or if the
191 * plugin does not use sessions).
193 struct Session *session;
195 struct ATS_ressource_entry * ressources;
197 struct ATS_quality_entry * quality;
200 * What was the last latency observed for this address, plugin and peer?
202 struct GNUNET_TIME_Relative latency;
205 * If we did not successfully transmit a message to the given peer
206 * via this connection during the specified time, we should consider
207 * the connection to be dead. This is used in the case that a TCP
208 * transport simply stalls writing to the stream but does not
209 * formerly get a signal that the other peer died.
211 struct GNUNET_TIME_Absolute timeout;
214 * How often have we tried to connect using this plugin? Used to
215 * discriminate against addresses that do not work well.
216 * FIXME: not yet used, but should be!
218 unsigned int connect_attempts;
221 * DV distance to this peer (1 if no DV is used).
222 * FIXME: need to set this from transport plugins!
232 * Have we ever estimated the latency of this address? Used to
233 * ensure that the first time we add an address, we immediately
239 * Are we currently connected via this address? The first time we
240 * successfully transmit or receive data to a peer via a particular
241 * address, we set this to GNUNET_YES. If we later get an error
242 * (disconnect notification, transmission failure, timeout), we set
243 * it back to GNUNET_NO.
248 * Is this plugin currently busy transmitting to the specific target?
249 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
250 * messages do not count as 'in transmit'.
255 * Has this address been validated yet?
263 * Entry in linked list of network addresses for ourselves. Also
264 * includes a cached signature for 'struct TransportPongMessage's.
266 struct OwnAddressList
269 * This is a linked list.
271 struct OwnAddressList *next;
274 * How long until we actually auto-expire this address (unless it is
275 * re-confirmed by the transport)?
277 struct GNUNET_TIME_Absolute expires;
280 * How long until the current signature expires? (ZERO if the
281 * signature was never created).
283 struct GNUNET_TIME_Absolute pong_sig_expires;
286 * Signature for a 'struct TransportPongMessage' for this address.
288 struct GNUNET_CRYPTO_RsaSignature pong_signature;
299 * Entry in linked list of all of our plugins.
301 struct TransportPlugin
305 * This is a linked list.
307 struct TransportPlugin *next;
310 * API of the transport as returned by the plugin's
311 * initialization function.
313 struct GNUNET_TRANSPORT_PluginFunctions *api;
316 * Short name for the plugin (i.e. "tcp").
321 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
326 * List of our known addresses for this transport.
328 struct OwnAddressList *addresses;
331 * Environment this transport service is using
334 struct GNUNET_TRANSPORT_PluginEnvironment env;
337 * ID of task that is used to clean up expired addresses.
339 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
342 * Set to GNUNET_YES if we need to scrap the existing list of
343 * "addresses" and start fresh when we receive the next address
344 * update from a transport. Set to GNUNET_NO if we should just add
345 * the new address to the list and wait for the commit call.
349 struct ATS_plugin * rc;
352 * Hashmap of blacklisted peers for this particular transport.
354 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
357 struct NeighbourList;
360 * For each neighbour we keep a list of messages
361 * that we still want to transmit to the neighbour.
367 * This is a doubly linked list.
369 struct MessageQueue *next;
372 * This is a doubly linked list.
374 struct MessageQueue *prev;
377 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
378 * stuck together in memory. Allocated at the end of this struct.
380 const char *message_buf;
383 * Size of the message buf
385 size_t message_buf_size;
388 * Client responsible for queueing the message;
389 * used to check that a client has no two messages
390 * pending for the same target. Can be NULL.
392 struct TransportClient *client;
395 * Using which specific address should we send this message?
397 struct ForeignAddressList *specific_address;
400 * Peer ID of the Neighbour this entry belongs to.
402 struct GNUNET_PeerIdentity neighbour_id;
405 * Plugin that we used for the transmission.
406 * NULL until we scheduled a transmission.
408 struct TransportPlugin *plugin;
411 * At what time should we fail?
413 struct GNUNET_TIME_Absolute timeout;
416 * Internal message of the transport system that should not be
417 * included in the usual SEND-SEND_OK transmission confirmation
418 * traffic management scheme. Typically, "internal_msg" will
419 * be set whenever "client" is NULL (but it is not strictly
425 * How important is the message?
427 unsigned int priority;
433 * For a given Neighbour, which plugins are available
434 * to talk to this peer and what are their costs?
439 * This is a linked list.
441 struct ReadyList *next;
444 * Which of our transport plugins does this entry
447 struct TransportPlugin *plugin;
450 * Transport addresses, latency, and readiness for
451 * this particular plugin.
453 struct ForeignAddressList *addresses;
456 * To which neighbour does this ready list belong to?
458 struct NeighbourList *neighbour;
463 * Entry in linked list of all of our current neighbours.
469 * This is a linked list.
471 struct NeighbourList *next;
474 * Which of our transports is connected to this peer
475 * and what is their status?
477 struct ReadyList *plugins;
480 * Head of list of messages we would like to send to this peer;
481 * must contain at most one message per client.
483 struct MessageQueue *messages_head;
486 * Tail of list of messages we would like to send to this peer; must
487 * contain at most one message per client.
489 struct MessageQueue *messages_tail;
492 * Buffer for at most one payload message used when we receive
493 * payload data before our PING-PONG has succeeded. We then
494 * store such messages in this intermediary buffer until the
495 * connection is fully up.
497 struct GNUNET_MessageHeader *pre_connect_message_buffer;
500 * Context for peerinfo iteration.
501 * NULL after we are done processing peerinfo's information.
503 struct GNUNET_PEERINFO_IteratorContext *piter;
506 * Public key for this peer. Valid only if the respective flag is set below.
508 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
511 * Identity of this neighbour.
513 struct GNUNET_PeerIdentity id;
516 * ID of task scheduled to run when this peer is about to
517 * time out (will free resources associated with the peer).
519 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
522 * ID of task scheduled to run when we should retry transmitting
523 * the head of the message queue. Actually triggered when the
524 * transmission is timing out (we trigger instantly when we have
525 * a chance of success).
527 GNUNET_SCHEDULER_TaskIdentifier retry_task;
530 * How long until we should consider this peer dead
531 * (if we don't receive another message in the
534 struct GNUNET_TIME_Absolute peer_timeout;
537 * Tracker for inbound bandwidth.
539 struct GNUNET_BANDWIDTH_Tracker in_tracker;
542 * The latency we have seen for this particular address for
543 * this particular peer. This latency may have been calculated
544 * over multiple transports. This value reflects how long it took
545 * us to receive a response when SENDING via this particular
546 * transport/neighbour/address combination!
548 * FIXME: we need to periodically send PINGs to update this
549 * latency (at least more often than the current "huge" (11h?)
552 struct GNUNET_TIME_Relative latency;
555 * How often has the other peer (recently) violated the
556 * inbound traffic limit? Incremented by 10 per violation,
557 * decremented by 1 per non-violation (for each
560 unsigned int quota_violation_count;
563 * DV distance to this peer (1 if no DV is used).
568 * Have we seen an PONG from this neighbour in the past (and
569 * not had a disconnect since)?
574 * Do we have a valid public key for this neighbour?
576 int public_key_valid;
579 * Performance data for the peer.
581 struct GNUNET_TRANSPORT_ATS_Information *ats;
584 * Identity of the neighbour.
586 struct GNUNET_PeerIdentity peer;
591 * Message used to ask a peer to validate receipt (to check an address
592 * from a HELLO). Followed by the address we are trying to validate,
593 * or an empty address if we are just sending a PING to confirm that a
594 * connection which the receiver (of the PING) initiated is still valid.
596 struct TransportPingMessage
600 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
602 struct GNUNET_MessageHeader header;
605 * Challenge code (to ensure fresh reply).
607 uint32_t challenge GNUNET_PACKED;
610 * Who is the intended recipient?
612 struct GNUNET_PeerIdentity target;
618 * Message used to validate a HELLO. The challenge is included in the
619 * confirmation to make matching of replies to requests possible. The
620 * signature signs our public key, an expiration time and our address.<p>
622 * This message is followed by our transport address that the PING tried
623 * to confirm (if we liked it). The address can be empty (zero bytes)
624 * if the PING had not address either (and we received the request via
625 * a connection that we initiated).
627 struct TransportPongMessage
631 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
633 struct GNUNET_MessageHeader header;
636 * Challenge code from PING (showing freshness). Not part of what
637 * is signed so that we can re-use signatures.
639 uint32_t challenge GNUNET_PACKED;
644 struct GNUNET_CRYPTO_RsaSignature signature;
647 * What are we signing and why? Two possible reason codes can be here:
648 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
649 * plausible address for this peer (pid is set to identity of signer); or
650 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
651 * an address we used to connect to the peer with the given pid.
653 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
656 * When does this signature expire?
658 struct GNUNET_TIME_AbsoluteNBO expiration;
661 * Either the identity of the peer Who signed this message, or the
662 * identity of the peer that we're connected to using the given
663 * address (depending on purpose.type).
665 struct GNUNET_PeerIdentity pid;
668 * Size of address appended to this message (part of what is
669 * being signed, hence not redundant).
677 * Linked list of messages to be transmitted to the client. Each
678 * entry is followed by the actual message.
680 struct ClientMessageQueueEntry
683 * This is a doubly-linked list.
685 struct ClientMessageQueueEntry *next;
688 * This is a doubly-linked list.
690 struct ClientMessageQueueEntry *prev;
695 * Client connected to the transport service.
697 struct TransportClient
701 * This is a linked list.
703 struct TransportClient *next;
706 * Handle to the client.
708 struct GNUNET_SERVER_Client *client;
711 * Linked list of messages yet to be transmitted to
714 struct ClientMessageQueueEntry *message_queue_head;
717 * Tail of linked list of messages yet to be transmitted to the
720 struct ClientMessageQueueEntry *message_queue_tail;
723 * Current transmit request handle.
725 struct GNUNET_CONNECTION_TransmitHandle *th;
728 * Is a call to "transmit_send_continuation" pending? If so, we
729 * must not free this struct (even if the corresponding client
730 * disconnects) and instead only remove it from the linked list and
731 * set the "client" field to NULL.
736 * Length of the list of messages pending for this client.
738 unsigned int message_count;
744 * Context of currently active requests to peerinfo
745 * for validation of HELLOs.
747 struct CheckHelloValidatedContext;
751 * Entry in map of all HELLOs awaiting validation.
753 struct ValidationEntry
757 * NULL if this entry is not part of a larger HELLO validation.
759 struct CheckHelloValidatedContext *chvc;
762 * The address, actually a pointer to the end
763 * of this struct. Do not free!
768 * Name of the transport.
770 char *transport_name;
773 * The public key of the peer.
775 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
778 * ID of task that will clean up this entry if we don't succeed
779 * with the validation first.
781 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
784 * At what time did we send this validation?
786 struct GNUNET_TIME_Absolute send_time;
789 * Session being validated (or NULL for none).
791 struct Session *session;
794 * Challenge number we used.
807 * Context of currently active requests to peerinfo
808 * for validation of HELLOs.
810 struct CheckHelloValidatedContext
814 * This is a doubly-linked list.
816 struct CheckHelloValidatedContext *next;
819 * This is a doubly-linked list.
821 struct CheckHelloValidatedContext *prev;
824 * Hello that we are validating.
826 const struct GNUNET_HELLO_Message *hello;
829 * Context for peerinfo iteration.
830 * NULL after we are done processing peerinfo's information.
832 struct GNUNET_PEERINFO_IteratorContext *piter;
835 * Was a HELLO known for this peer to peerinfo?
840 * Number of validation entries currently referring to this
843 unsigned int ve_count;
846 struct ATS_quality_metric
855 struct ATS_mechanism * prev;
856 struct ATS_mechanism * next;
857 struct ForeignAddressList * addr;
858 struct TransportPlugin * plugin;
859 struct ATS_peer * peer;
862 struct ATS_ressource_cost * rc;
868 struct GNUNET_PeerIdentity peer;
869 struct NeighbourList * n;
870 struct ATS_mechanism * m_head;
871 struct ATS_mechanism * m_tail;
873 /* preference value f */
885 struct ATS_ressource_entry
887 /* index in ressources array */
889 /* depending ATSi parameter to calculcate limits */
898 /* index in ressources array */
900 /* depending ATSi parameter to calculcate limits */
902 /* cfg option to load limits */
909 /* cofficients for the specific plugins */
919 static struct ATS_ressource ressources[] =
921 /* FIXME: the coefficients for the specific plugins */
922 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
923 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
924 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
926 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
927 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
928 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
929 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
932 static int available_ressources = 3;
940 * Time of last execution
942 struct GNUNET_TIME_Absolute last;
944 * Minimum intervall between two executions
946 struct GNUNET_TIME_Relative min_delta;
948 * Regular intervall when execution is triggered
950 struct GNUNET_TIME_Relative exec_intervall;
952 * Maximum execution time per calculation
954 struct GNUNET_TIME_Relative max_exec_duration;
956 * Maximum number of LP iterations per calculation
969 GNUNET_SCHEDULER_TaskIdentifier ats_task;
971 struct ATS_plugin * head;
972 struct ATS_plugin * tail;
979 static struct GNUNET_HELLO_Message *our_hello;
984 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
989 static struct GNUNET_PeerIdentity my_identity;
994 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
999 const struct GNUNET_CONFIGURATION_Handle *cfg;
1002 * Linked list of all clients to this service.
1004 static struct TransportClient *clients;
1007 * All loaded plugins.
1009 static struct TransportPlugin *plugins;
1012 * Handle to peerinfo service.
1014 static struct GNUNET_PEERINFO_Handle *peerinfo;
1017 * All known neighbours and their HELLOs.
1019 static struct NeighbourList *neighbours;
1022 * Number of neighbours we'd like to have.
1024 static uint32_t max_connect_per_transport;
1027 * Head of linked list.
1029 static struct CheckHelloValidatedContext *chvc_head;
1032 * Tail of linked list.
1034 static struct CheckHelloValidatedContext *chvc_tail;
1037 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1038 * of the given peer that we are currently validating).
1040 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1043 * Handle for reporting statistics.
1045 static struct GNUNET_STATISTICS_Handle *stats;
1048 * Handle for ats information
1050 static struct ATS_info *ats;
1052 struct ATS_quality_entry
1060 static struct ATS_quality_metric qm[] =
1062 {1, 1028, "QUALITY_NET_DISTANCE"},
1063 {2, 1034, "QUALITY_NET_DELAY"},
1065 static int available_quality_metrics = 2;
1069 * The peer specified by the given neighbour has timed-out or a plugin
1070 * has disconnected. We may either need to do nothing (other plugins
1071 * still up), or trigger a full disconnect and clean up. This
1072 * function updates our state and do the necessary notifications.
1073 * Also notifies our clients that the neighbour is now officially
1076 * @param n the neighbour list entry for the peer
1077 * @param check should we just check if all plugins
1078 * disconnected or must we ask all plugins to
1081 static void disconnect_neighbour (struct NeighbourList *n, int check);
1084 * Check the ready list for the given neighbour and if a plugin is
1085 * ready for transmission (and if we have a message), do so!
1087 * @param nexi target peer for which to transmit
1089 static void try_transmission_to_peer (struct NeighbourList *n);
1094 void ats_shutdown ( );
1096 void ats_notify_peer_connect (
1097 const struct GNUNET_PeerIdentity *peer,
1098 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1100 void ats_notify_peer_disconnect (
1101 const struct GNUNET_PeerIdentity *peer);
1103 void ats_notify_ats_data (
1104 const struct GNUNET_PeerIdentity *peer,
1105 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1107 struct ForeignAddressList * ats_get_preferred_address (
1108 struct NeighbourList *n);
1111 * Find an entry in the neighbour list for a particular peer.
1113 * @return NULL if not found.
1115 static struct NeighbourList *
1116 find_neighbour (const struct GNUNET_PeerIdentity *key)
1118 struct NeighbourList *head = neighbours;
1120 while ((head != NULL) &&
1121 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1126 static void update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1129 for (c1=0; c1<ats_count; c1++)
1131 for (c2=0; c2<available_quality_metrics; c2++)
1133 if (ntohl(ats_data[c1].type) == qm[c2].atis_index)
1135 fal->quality[c2].values[0] = fal->quality[c2].values[1];
1136 fal->quality[c2].values[1] = fal->quality[c2].values[2];
1137 fal->quality[c2].values[2] = ntohl(ats_data[c1].value);
1143 static void update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1146 for (c=0; c<available_quality_metrics; c++)
1148 if (ats_index == qm[c].atis_index)
1150 fal->quality[c].values[0] = fal->quality[c].values[1];
1151 fal->quality[c].values[1] = fal->quality[c].values[2];
1152 fal->quality[c].values[2] = value;
1158 * Find an entry in the transport list for a particular transport.
1160 * @return NULL if not found.
1162 static struct TransportPlugin *
1163 find_transport (const char *short_name)
1165 struct TransportPlugin *head = plugins;
1166 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1172 * Is a particular peer blacklisted for a particular transport?
1174 * @param peer the peer to check for
1175 * @param plugin the plugin used to connect to the peer
1177 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1180 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1183 if (plugin->blacklist != NULL)
1185 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1189 "Peer `%s:%s' is blacklisted!\n",
1190 plugin->short_name, GNUNET_i2s (peer));
1193 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1203 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1205 struct TransportPlugin *plugin;
1207 plugin = find_transport(transport_name);
1208 if (plugin == NULL) /* Nothing to do */
1210 if (plugin->blacklist == NULL)
1211 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1212 GNUNET_assert(plugin->blacklist != NULL);
1213 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1215 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1220 * Read the blacklist file, containing transport:peer entries.
1221 * Provided the transport is loaded, set up hashmap with these
1222 * entries to blacklist peers by transport.
1226 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1233 struct GNUNET_PeerIdentity pid;
1235 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1236 unsigned int entries_found;
1237 char *transport_name;
1240 GNUNET_CONFIGURATION_get_value_filename (cfg,
1246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1247 "Option `%s' in section `%s' not specified!\n",
1253 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1254 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1255 | GNUNET_DISK_PERM_USER_WRITE);
1256 if (0 != STAT (fn, &frstat))
1258 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1259 _("Could not read blacklist file `%s'\n"), fn);
1263 if (frstat.st_size == 0)
1266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1267 _("Blacklist file `%s' is empty.\n"),
1273 /* FIXME: use mmap */
1274 data = GNUNET_malloc_large (frstat.st_size);
1275 GNUNET_assert(data != NULL);
1276 if (frstat.st_size !=
1277 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1280 _("Failed to read blacklist from `%s'\n"), fn);
1287 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1289 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1290 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1293 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1296 if (colon_pos >= frstat.st_size)
1298 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1299 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1300 (unsigned long long) colon_pos);
1306 if (isspace( (unsigned char) data[colon_pos]))
1308 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1309 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1310 (unsigned long long) colon_pos);
1312 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1316 tsize = colon_pos - pos;
1317 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1319 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1320 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1321 (unsigned long long) colon_pos);
1330 transport_name = GNUNET_malloc(tsize + 1);
1331 memcpy(transport_name, &data[pos], tsize);
1332 pos = colon_pos + 1;
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1335 "Read transport name %s in blacklist file.\n",
1338 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1339 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1341 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1342 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1343 (unsigned long long) pos);
1345 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1347 GNUNET_free_non_null(transport_name);
1350 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1351 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1353 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1354 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1355 (unsigned long long) pos,
1360 if (0 != memcmp (&pid,
1362 sizeof (struct GNUNET_PeerIdentity)))
1365 add_peer_to_blacklist (&pid,
1370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1371 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1375 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1376 GNUNET_free_non_null(transport_name);
1377 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1380 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1387 * Function called to notify a client about the socket being ready to
1388 * queue more data. "buf" will be NULL and "size" zero if the socket
1389 * was closed for writing in the meantime.
1391 * @param cls closure
1392 * @param size number of bytes available in buf
1393 * @param buf where the callee should write the message
1394 * @return number of bytes written to buf
1397 transmit_to_client_callback (void *cls, size_t size, void *buf)
1399 struct TransportClient *client = cls;
1400 struct ClientMessageQueueEntry *q;
1403 const struct GNUNET_MessageHeader *msg;
1410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1411 "Transmission to client failed, closing connection.\n");
1413 /* fatal error with client, free message queue! */
1414 while (NULL != (q = client->message_queue_head))
1416 GNUNET_STATISTICS_update (stats,
1417 gettext_noop ("# bytes discarded (could not transmit to client)"),
1418 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1420 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1421 client->message_queue_tail,
1425 client->message_count = 0;
1430 while (NULL != (q = client->message_queue_head))
1432 msg = (const struct GNUNET_MessageHeader *) &q[1];
1433 msize = ntohs (msg->size);
1434 if (msize + tsize > size)
1437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1438 "Transmitting message of type %u to client.\n",
1441 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1442 client->message_queue_tail,
1444 memcpy (&cbuf[tsize], msg, msize);
1447 client->message_count--;
1451 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1452 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1454 GNUNET_TIME_UNIT_FOREVER_REL,
1455 &transmit_to_client_callback,
1457 GNUNET_assert (client->th != NULL);
1464 * Convert an address to a string.
1466 * @param plugin name of the plugin responsible for the address
1467 * @param addr binary address
1468 * @param addr_len number of bytes in addr
1469 * @return NULL on error, otherwise address string
1472 a2s (const char *plugin,
1476 struct TransportPlugin *p;
1480 p = find_transport (plugin);
1483 return p->api->address_to_string (p->api->cls,
1490 * Mark the given FAL entry as 'connected' (and hence preferred for
1491 * sending); also mark all others for the same peer as 'not connected'
1492 * (since only one can be preferred).
1494 * @param fal address to set to 'connected'
1497 mark_address_connected (struct ForeignAddressList *fal)
1499 struct ForeignAddressList *pos;
1502 GNUNET_assert (GNUNET_YES == fal->validated);
1503 if (fal->connected == GNUNET_YES)
1504 return; /* nothing to do */
1506 pos = fal->ready_list->addresses;
1509 if (GNUNET_YES == pos->connected)
1512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1513 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1514 a2s (pos->ready_list->plugin->short_name,
1518 GNUNET_break (cnt == GNUNET_YES);
1520 pos->connected = GNUNET_NO;
1521 GNUNET_STATISTICS_update (stats,
1522 gettext_noop ("# connected addresses"),
1528 fal->connected = GNUNET_YES;
1529 if (GNUNET_YES == cnt)
1531 GNUNET_STATISTICS_update (stats,
1532 gettext_noop ("# connected addresses"),
1540 * Send the specified message to the specified client. Since multiple
1541 * messages may be pending for the same client at a time, this code
1542 * makes sure that no message is lost.
1544 * @param client client to transmit the message to
1545 * @param msg the message to send
1546 * @param may_drop can this message be dropped if the
1547 * message queue for this client is getting far too large?
1550 transmit_to_client (struct TransportClient *client,
1551 const struct GNUNET_MessageHeader *msg, int may_drop)
1553 struct ClientMessageQueueEntry *q;
1556 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1558 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1560 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1563 client->message_count,
1565 GNUNET_STATISTICS_update (stats,
1566 gettext_noop ("# messages dropped due to slow client"),
1571 msize = ntohs (msg->size);
1572 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1573 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1574 memcpy (&q[1], msg, msize);
1575 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1576 client->message_queue_tail,
1577 client->message_queue_tail,
1579 client->message_count++;
1580 if (client->th == NULL)
1582 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1584 GNUNET_TIME_UNIT_FOREVER_REL,
1585 &transmit_to_client_callback,
1587 GNUNET_assert (client->th != NULL);
1593 * Transmit a 'SEND_OK' notification to the given client for the
1596 * @param client who to notify
1597 * @param n neighbour to notify about, can be NULL (on failure)
1598 * @param target target of the transmission
1599 * @param result status code for the transmission request
1602 transmit_send_ok (struct TransportClient *client,
1603 struct NeighbourList *n,
1604 const struct GNUNET_PeerIdentity *target,
1607 struct SendOkMessage send_ok_msg;
1609 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1610 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1611 send_ok_msg.success = htonl (result);
1613 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1615 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1616 send_ok_msg.peer = *target;
1617 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1622 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1623 * upon "completion" of a send request. This tells the API
1624 * that it is now legal to send another message to the given
1627 * @param cls closure, identifies the entry on the
1628 * message queue that was transmitted and the
1629 * client responsible for queuing the message
1630 * @param target the peer receiving the message
1631 * @param result GNUNET_OK on success, if the transmission
1632 * failed, we should not tell the client to transmit
1636 transmit_send_continuation (void *cls,
1637 const struct GNUNET_PeerIdentity *target,
1640 struct MessageQueue *mq = cls;
1641 struct NeighbourList *n;
1643 GNUNET_STATISTICS_update (stats,
1644 gettext_noop ("# bytes pending with plugins"),
1645 - (int64_t) mq->message_buf_size,
1647 if (result == GNUNET_OK)
1649 GNUNET_STATISTICS_update (stats,
1650 gettext_noop ("# bytes successfully transmitted by plugins"),
1651 mq->message_buf_size,
1656 GNUNET_STATISTICS_update (stats,
1657 gettext_noop ("# bytes with transmission failure by plugins"),
1658 mq->message_buf_size,
1661 if (mq->specific_address != NULL)
1663 if (result == GNUNET_OK)
1665 mq->specific_address->timeout =
1666 GNUNET_TIME_relative_to_absolute
1667 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1668 if (mq->specific_address->validated == GNUNET_YES)
1669 mark_address_connected (mq->specific_address);
1673 if (mq->specific_address->connected != GNUNET_NO)
1676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1677 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1678 a2s (mq->specific_address->ready_list->plugin->short_name,
1679 mq->specific_address->addr,
1680 mq->specific_address->addrlen));
1682 GNUNET_STATISTICS_update (stats,
1683 gettext_noop ("# connected addresses"),
1686 mq->specific_address->connected = GNUNET_NO;
1689 if (! mq->internal_msg)
1690 mq->specific_address->in_transmit = GNUNET_NO;
1692 n = find_neighbour(&mq->neighbour_id);
1693 if (mq->client != NULL)
1694 transmit_send_ok (mq->client, n, target, result);
1697 try_transmission_to_peer (n);
1702 * Find an address in any of the available transports for
1703 * the given neighbour that would be good for message
1704 * transmission. This is essentially the transport selection
1707 * @param neighbour for whom to select an address
1708 * @return selected address, NULL if we have none
1710 struct ForeignAddressList *
1711 find_ready_address(struct NeighbourList *neighbour)
1713 struct ReadyList *head = neighbour->plugins;
1714 struct ForeignAddressList *addresses;
1715 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1716 struct ForeignAddressList *best_address;
1718 /* Hack to prefer unix domain sockets */
1719 struct ForeignAddressList *unix_address = NULL;
1721 best_address = NULL;
1722 while (head != NULL)
1724 addresses = head->addresses;
1725 while (addresses != NULL)
1727 if ( (addresses->timeout.abs_value < now.abs_value) &&
1728 (addresses->connected == GNUNET_YES) )
1731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732 "Marking long-time inactive connection to `%4s' as down.\n",
1733 GNUNET_i2s (&neighbour->id));
1735 GNUNET_STATISTICS_update (stats,
1736 gettext_noop ("# connected addresses"),
1739 addresses->connected = GNUNET_NO;
1741 addresses = addresses->next;
1744 addresses = head->addresses;
1745 while (addresses != NULL)
1747 #if DEBUG_TRANSPORT > 1
1748 if (addresses->addr != NULL)
1749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1750 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1751 a2s (head->plugin->short_name,
1753 addresses->addrlen),
1754 GNUNET_i2s (&neighbour->id),
1755 addresses->connected,
1756 addresses->in_transmit,
1757 addresses->validated,
1758 addresses->connect_attempts,
1759 (unsigned long long) addresses->timeout.abs_value,
1760 (unsigned int) addresses->distance);
1762 if (0==strcmp(head->plugin->short_name,"unix"))
1764 if ((unix_address == NULL) || ((unix_address != NULL) &&
1765 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1766 unix_address = addresses;
1768 if ( ( (best_address == NULL) ||
1769 (addresses->connected == GNUNET_YES) ||
1770 (best_address->connected == GNUNET_NO) ) &&
1771 (addresses->in_transmit == GNUNET_NO) &&
1772 ( (best_address == NULL) ||
1773 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1774 best_address = addresses;
1775 /* FIXME: also give lower-latency addresses that are not
1776 connected a chance some times... */
1777 addresses = addresses->next;
1779 if (unix_address != NULL)
1783 if (unix_address != NULL)
1785 best_address = unix_address;
1787 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1790 if (best_address != NULL)
1794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1795 "Best address found (`%s') has latency of %llu ms.\n",
1796 (best_address->addrlen > 0)
1797 ? a2s (best_address->ready_list->plugin->short_name,
1799 best_address->addrlen)
1801 best_address->latency.rel_value);
1806 GNUNET_STATISTICS_update (stats,
1807 gettext_noop ("# transmission attempts failed (no address)"),
1812 return best_address;
1818 * We should re-try transmitting to the given peer,
1819 * hopefully we've learned something in the meantime.
1822 retry_transmission_task (void *cls,
1823 const struct GNUNET_SCHEDULER_TaskContext *tc)
1825 struct NeighbourList *n = cls;
1827 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1828 try_transmission_to_peer (n);
1833 * Check the ready list for the given neighbour and if a plugin is
1834 * ready for transmission (and if we have a message), do so!
1836 * @param neighbour target peer for which to transmit
1839 try_transmission_to_peer (struct NeighbourList *n)
1841 struct ReadyList *rl;
1842 struct MessageQueue *mq;
1843 struct GNUNET_TIME_Relative timeout;
1847 if (n->messages_head == NULL)
1850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1851 "Transmission queue for `%4s' is empty\n",
1852 GNUNET_i2s (&n->id));
1854 return; /* nothing to do */
1857 mq = n->messages_head;
1858 force_address = GNUNET_YES;
1859 if (mq->specific_address == NULL)
1862 mq->specific_address = ats_get_preferred_address(n);
1863 GNUNET_STATISTICS_update (stats,
1864 gettext_noop ("# transport selected peer address freely"),
1867 force_address = GNUNET_NO;
1869 if (mq->specific_address == NULL)
1871 GNUNET_STATISTICS_update (stats,
1872 gettext_noop ("# transport failed to selected peer address"),
1875 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1876 if (timeout.rel_value == 0)
1879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1880 "No destination address available to transmit message of size %u to peer `%4s'\n",
1881 mq->message_buf_size,
1882 GNUNET_i2s (&mq->neighbour_id));
1884 GNUNET_STATISTICS_update (stats,
1885 gettext_noop ("# bytes in message queue for other peers"),
1886 - (int64_t) mq->message_buf_size,
1888 GNUNET_STATISTICS_update (stats,
1889 gettext_noop ("# bytes discarded (no destination address available)"),
1890 mq->message_buf_size,
1892 if (mq->client != NULL)
1893 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1894 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1898 return; /* nobody ready */
1900 GNUNET_STATISTICS_update (stats,
1901 gettext_noop ("# message delivery deferred (no address)"),
1904 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1905 GNUNET_SCHEDULER_cancel (n->retry_task);
1906 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1907 &retry_transmission_task,
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1912 mq->message_buf_size,
1913 GNUNET_i2s (&mq->neighbour_id),
1916 /* FIXME: might want to trigger peerinfo lookup here
1917 (unless that's already pending...) */
1920 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1923 if (mq->specific_address->connected == GNUNET_NO)
1924 mq->specific_address->connect_attempts++;
1925 rl = mq->specific_address->ready_list;
1926 mq->plugin = rl->plugin;
1927 if (!mq->internal_msg)
1928 mq->specific_address->in_transmit = GNUNET_YES;
1930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1931 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1932 mq->message_buf_size,
1933 GNUNET_i2s (&n->id),
1934 (mq->specific_address->addr != NULL)
1935 ? a2s (mq->plugin->short_name,
1936 mq->specific_address->addr,
1937 mq->specific_address->addrlen)
1939 rl->plugin->short_name);
1941 GNUNET_STATISTICS_update (stats,
1942 gettext_noop ("# bytes in message queue for other peers"),
1943 - (int64_t) mq->message_buf_size,
1945 GNUNET_STATISTICS_update (stats,
1946 gettext_noop ("# bytes pending with plugins"),
1947 mq->message_buf_size,
1949 ret = rl->plugin->api->send (rl->plugin->api->cls,
1952 mq->message_buf_size,
1954 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1955 mq->specific_address->session,
1956 mq->specific_address->addr,
1957 mq->specific_address->addrlen,
1959 &transmit_send_continuation, mq);
1962 /* failure, but 'send' would not call continuation in this case,
1963 so we need to do it here! */
1964 transmit_send_continuation (mq,
1972 * Send the specified message to the specified peer.
1974 * @param client source of the transmission request (can be NULL)
1975 * @param peer_address ForeignAddressList where we should send this message
1976 * @param priority how important is the message
1977 * @param timeout how long do we have to transmit?
1978 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1979 * @param message_buf_size total size of all messages in message_buf
1980 * @param is_internal is this an internal message; these are pre-pended and
1981 * also do not count for plugins being "ready" to transmit
1982 * @param neighbour handle to the neighbour for transmission
1985 transmit_to_peer (struct TransportClient *client,
1986 struct ForeignAddressList *peer_address,
1987 unsigned int priority,
1988 struct GNUNET_TIME_Relative timeout,
1989 const char *message_buf,
1990 size_t message_buf_size,
1991 int is_internal, struct NeighbourList *neighbour)
1993 struct MessageQueue *mq;
1998 /* check for duplicate submission */
1999 mq = neighbour->messages_head;
2002 if (mq->client == client)
2004 /* client transmitted to same peer twice
2005 before getting SEND_OK! */
2013 GNUNET_STATISTICS_update (stats,
2014 gettext_noop ("# bytes in message queue for other peers"),
2017 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2018 mq->specific_address = peer_address;
2019 mq->client = client;
2020 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2021 memcpy (&mq[1], message_buf, message_buf_size);
2022 mq->message_buf = (const char*) &mq[1];
2023 mq->message_buf_size = message_buf_size;
2024 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2025 mq->internal_msg = is_internal;
2026 mq->priority = priority;
2027 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2029 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2030 neighbour->messages_tail,
2033 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2034 neighbour->messages_tail,
2035 neighbour->messages_tail,
2037 try_transmission_to_peer (neighbour);
2044 struct GeneratorContext
2046 struct TransportPlugin *plug_pos;
2047 struct OwnAddressList *addr_pos;
2048 struct GNUNET_TIME_Absolute expiration;
2056 address_generator (void *cls, size_t max, void *buf)
2058 struct GeneratorContext *gc = cls;
2061 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2063 gc->plug_pos = gc->plug_pos->next;
2064 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2066 if (NULL == gc->plug_pos)
2071 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2074 gc->addr_pos->addrlen, buf, max);
2075 gc->addr_pos = gc->addr_pos->next;
2081 * Construct our HELLO message from all of the addresses of
2082 * all of the transports.
2087 struct GNUNET_HELLO_Message *hello;
2088 struct TransportClient *cpos;
2089 struct NeighbourList *npos;
2090 struct GeneratorContext gc;
2092 gc.plug_pos = plugins;
2093 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2094 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2095 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2098 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2100 GNUNET_STATISTICS_update (stats,
2101 gettext_noop ("# refreshed my HELLO"),
2105 while (cpos != NULL)
2107 transmit_to_client (cpos,
2108 (const struct GNUNET_MessageHeader *) hello,
2113 GNUNET_free_non_null (our_hello);
2115 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2117 while (npos != NULL)
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2121 "Transmitting updated `%s' to neighbour `%4s'\n",
2122 "HELLO", GNUNET_i2s (&npos->id));
2124 GNUNET_STATISTICS_update (stats,
2125 gettext_noop ("# transmitted my HELLO to other peers"),
2128 transmit_to_peer (NULL, NULL, 0,
2129 HELLO_ADDRESS_EXPIRATION,
2130 (const char *) our_hello,
2131 GNUNET_HELLO_size(our_hello),
2139 * Task used to clean up expired addresses for a plugin.
2141 * @param cls closure
2145 expire_address_task (void *cls,
2146 const struct GNUNET_SCHEDULER_TaskContext *tc);
2150 * Update the list of addresses for this plugin,
2151 * expiring those that are past their expiration date.
2153 * @param plugin addresses of which plugin should be recomputed?
2154 * @param fresh set to GNUNET_YES if a new address was added
2155 * and we need to regenerate the HELLO even if nobody
2159 update_addresses (struct TransportPlugin *plugin,
2162 static struct GNUNET_TIME_Absolute last_update;
2163 struct GNUNET_TIME_Relative min_remaining;
2164 struct GNUNET_TIME_Relative remaining;
2165 struct GNUNET_TIME_Absolute now;
2166 struct OwnAddressList *pos;
2167 struct OwnAddressList *prev;
2168 struct OwnAddressList *next;
2171 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2172 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2173 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2174 now = GNUNET_TIME_absolute_get ();
2175 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2176 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2178 pos = plugin->addresses;
2182 if (pos->expires.abs_value < now.abs_value)
2184 expired = GNUNET_YES;
2186 plugin->addresses = pos->next;
2188 prev->next = pos->next;
2193 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2194 if (remaining.rel_value < min_remaining.rel_value)
2195 min_remaining = remaining;
2201 if (expired || fresh)
2206 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2207 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2209 plugin->address_update_task
2210 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2211 &expire_address_task, plugin);
2216 * Task used to clean up expired addresses for a plugin.
2218 * @param cls closure
2222 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2224 struct TransportPlugin *plugin = cls;
2226 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2227 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2228 update_addresses (plugin, GNUNET_NO);
2233 * Iterator over hash map entries that NULLs the session of validation
2234 * entries that match the given session.
2236 * @param cls closure (the 'struct Session*' to match against)
2237 * @param key current key code (peer ID, not used)
2238 * @param value value in the hash map ('struct ValidationEntry*')
2239 * @return GNUNET_YES (we should continue to iterate)
2242 remove_session_validations (void *cls,
2243 const GNUNET_HashCode * key,
2246 struct Session *session = cls;
2247 struct ValidationEntry *ve = value;
2249 if (session == ve->session)
2256 * We've been disconnected from the other peer (for some
2257 * connection-oriented transport). Either quickly
2258 * re-establish the connection or signal the disconnect
2261 * Only signal CORE level disconnect if ALL addresses
2262 * for the peer are exhausted.
2264 * @param p overall plugin context
2265 * @param nl neighbour that was disconnected
2268 try_fast_reconnect (struct TransportPlugin *p,
2269 struct NeighbourList *nl)
2271 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2272 /* Note: the idea here is to hide problems with transports (or
2273 switching between plugins) from the core to eliminate the need to
2274 re-negotiate session keys and the like; OTOH, we should tell core
2275 quickly (much faster than timeout) `if a connection was lost and
2276 could not be re-established (i.e. other peer went down or is
2277 unable / refuses to communicate);
2279 So we should consider:
2280 1) ideally: our own willingness / need to connect
2281 2) prior failures to connect to this peer (by plugin)
2282 3) ideally: reasons why other peer terminated (as far as knowable)
2284 Most importantly, it must be POSSIBLE for another peer to terminate
2285 a connection for a while (without us instantly re-establishing it).
2286 Similarly, if another peer is gone we should quickly notify CORE.
2287 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2288 on the other end), we should reconnect in such a way that BOTH CORE
2289 services never even notice.
2290 Furthermore, the same mechanism (or small variation) could be used
2291 to switch to a better-performing plugin (ATS).
2293 Finally, this needs to be tested throughly... */
2296 * GNUNET_NO in the call below makes transport disconnect the peer,
2297 * even if only a single address (out of say, six) went away. This
2298 * function must be careful to ONLY disconnect if the peer is gone,
2299 * not just a specifi address.
2301 * More specifically, half the places it was used had it WRONG.
2304 /* No reconnect, signal disconnect instead! */
2305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2306 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2307 "try_fast_reconnect");
2308 disconnect_neighbour (nl, GNUNET_YES);
2313 * Function that will be called whenever the plugin internally
2314 * cleans up a session pointer and hence the service needs to
2315 * discard all of those sessions as well. Plugins that do not
2316 * use sessions can simply omit calling this function and always
2317 * use NULL wherever a session pointer is needed.
2319 * @param cls closure
2320 * @param peer which peer was the session for
2321 * @param session which session is being destoyed
2324 plugin_env_session_end (void *cls,
2325 const struct GNUNET_PeerIdentity *peer,
2326 struct Session *session)
2328 struct TransportPlugin *p = cls;
2329 struct NeighbourList *nl;
2330 struct ReadyList *rl;
2331 struct ForeignAddressList *pos;
2332 struct ForeignAddressList *prev;
2334 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2335 &remove_session_validations,
2337 nl = find_neighbour (peer);
2339 return; /* was never marked as connected */
2343 if (rl->plugin == p)
2348 return; /* was never marked as connected */
2350 pos = rl->addresses;
2351 while ( (pos != NULL) &&
2352 (pos->session != session) )
2358 return; /* was never marked as connected */
2359 pos->session = NULL;
2360 if (pos->addrlen != 0)
2362 if (nl->received_pong != GNUNET_NO)
2363 try_fast_reconnect (p, nl);
2366 /* was inbound connection, free 'pos' */
2368 rl->addresses = pos->next;
2370 prev->next = pos->next;
2371 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2373 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2374 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2377 if (nl->received_pong == GNUNET_NO)
2378 return; /* nothing to do, never connected... */
2379 /* check if we have any validated addresses left */
2380 pos = rl->addresses;
2385 try_fast_reconnect (p, nl);
2390 /* no valid addresses left, signal disconnect! */
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2394 "plugin_env_session_end");
2395 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2396 * it means there aren't any left for this PLUGIN/PEER combination! So
2397 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2398 * when it isn't necessary. Using GNUNET_YES at least checks to see
2399 * if there are any addresses that work first, so as not to overdo it.
2402 disconnect_neighbour (nl, GNUNET_YES);
2407 * Function that must be called by each plugin to notify the
2408 * transport service about the addresses under which the transport
2409 * provided by the plugin can be reached.
2411 * @param cls closure
2412 * @param name name of the transport that generated the address
2413 * @param addr one of the addresses of the host, NULL for the last address
2414 * the specific address format depends on the transport
2415 * @param addrlen length of the address
2416 * @param expires when should this address automatically expire?
2419 plugin_env_notify_address (void *cls,
2423 struct GNUNET_TIME_Relative expires)
2425 struct TransportPlugin *p = cls;
2426 struct OwnAddressList *al;
2427 struct GNUNET_TIME_Absolute abex;
2429 GNUNET_assert (addr != NULL);
2430 abex = GNUNET_TIME_relative_to_absolute (expires);
2431 GNUNET_assert (p == find_transport (name));
2435 if ( (addrlen == al->addrlen) &&
2436 (0 == memcmp (addr, &al[1], addrlen)) )
2439 update_addresses (p, GNUNET_NO);
2444 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2445 al->next = p->addresses;
2448 al->addrlen = addrlen;
2449 memcpy (&al[1], addr, addrlen);
2450 update_addresses (p, GNUNET_YES);
2455 * Notify all of our clients about a peer connecting.
2458 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2459 struct GNUNET_TIME_Relative latency,
2462 struct ConnectInfoMessage * cim;
2463 struct TransportClient *cpos;
2468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469 "Notifying clients about connection from `%s'\n",
2472 GNUNET_STATISTICS_update (stats,
2473 gettext_noop ("# peers connected"),
2478 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2479 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2483 cim = GNUNET_malloc (size);
2485 cim->header.size = htons (size);
2486 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2487 cim->ats_count = htonl(2);
2488 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2489 (&(cim->ats))[0].value = htonl (distance);
2490 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2491 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2492 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2493 (&(cim->ats))[2].value = htonl (0);
2494 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2496 /* notify ats about connecting peer */
2497 ats_notify_peer_connect (peer, &(cim->ats));
2500 while (cpos != NULL)
2502 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2511 * Notify all of our clients about a peer disconnecting.
2514 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2516 struct DisconnectInfoMessage dim;
2517 struct TransportClient *cpos;
2520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2521 "Notifying clients about lost connection to `%s'\n",
2524 GNUNET_STATISTICS_update (stats,
2525 gettext_noop ("# peers connected"),
2528 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2529 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2530 dim.reserved = htonl (0);
2531 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2533 /* notify ats about connecting peer */
2534 ats_notify_peer_disconnect (peer);
2537 while (cpos != NULL)
2539 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2546 * Find a ForeignAddressList entry for the given neighbour
2547 * that matches the given address and transport.
2549 * @param neighbour which peer we care about
2550 * @param tname name of the transport plugin
2551 * @param session session to look for, NULL for 'any'; otherwise
2552 * can be used for the service to "learn" this session ID
2554 * @param addr binary address
2555 * @param addrlen length of addr
2556 * @return NULL if no such entry exists
2558 static struct ForeignAddressList *
2559 find_peer_address(struct NeighbourList *neighbour,
2561 struct Session *session,
2565 struct ReadyList *head;
2566 struct ForeignAddressList *pos;
2568 head = neighbour->plugins;
2569 while (head != NULL)
2571 if (0 == strcmp (tname, head->plugin->short_name))
2577 pos = head->addresses;
2578 while ( (pos != NULL) &&
2579 ( (pos->addrlen != addrlen) ||
2580 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2582 if ( (session != NULL) &&
2583 (pos->session == session) )
2587 if ( (session != NULL) && (pos != NULL) )
2588 pos->session = session; /* learn it! */
2594 * Get the peer address struct for the given neighbour and
2595 * address. If it doesn't yet exist, create it.
2597 * @param neighbour which peer we care about
2598 * @param tname name of the transport plugin
2599 * @param session session of the plugin, or NULL for none
2600 * @param addr binary address
2601 * @param addrlen length of addr
2602 * @return NULL if we do not have a transport plugin for 'tname'
2604 static struct ForeignAddressList *
2605 add_peer_address (struct NeighbourList *neighbour,
2607 struct Session *session,
2611 struct ReadyList *head;
2612 struct ForeignAddressList *ret;
2615 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2618 head = neighbour->plugins;
2620 while (head != NULL)
2622 if (0 == strcmp (tname, head->plugin->short_name))
2628 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2629 ret->session = session;
2630 if ((addrlen > 0) && (addr != NULL))
2632 ret->addr = (const char*) &ret[1];
2633 memcpy (&ret[1], addr, addrlen);
2640 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2642 for (c=0; c<available_ressources; c++)
2644 struct ATS_ressource_entry *r = ret->ressources;
2646 r[c].atis_index = ressources[c].atis_index;
2647 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2649 r[c].c = ressources[c].c_unix;
2652 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2654 r[c].c = ressources[c].c_udp;
2657 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2659 r[c].c = ressources[c].c_tcp;
2662 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2664 r[c].c = ressources[c].c_http;
2667 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2669 r[c].c = ressources[c].c_https;
2672 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2674 r[c].c = ressources[c].c_wlan;
2680 r[c].c = ressources[c].c_default;
2681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2682 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2686 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2687 ret->addrlen = addrlen;
2688 ret->expires = GNUNET_TIME_relative_to_absolute
2689 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2690 ret->latency = GNUNET_TIME_relative_get_forever();
2692 ret->timeout = GNUNET_TIME_relative_to_absolute
2693 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2694 ret->ready_list = head;
2695 ret->next = head->addresses;
2696 head->addresses = ret;
2702 * Closure for 'add_validated_address'.
2704 struct AddValidatedAddressContext
2707 * Entry that has been validated.
2709 const struct ValidationEntry *ve;
2712 * Flag set after we have added the address so
2713 * that we terminate the iteration next time.
2720 * Callback function used to fill a buffer of max bytes with a list of
2721 * addresses in the format used by HELLOs. Should use
2722 * "GNUNET_HELLO_add_address" as a helper function.
2724 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2725 * @param max maximum number of bytes that can be written to buf
2726 * @param buf where to write the address information
2727 * @return number of bytes written, 0 to signal the
2728 * end of the iteration.
2731 add_validated_address (void *cls,
2732 size_t max, void *buf)
2734 struct AddValidatedAddressContext *avac = cls;
2735 const struct ValidationEntry *ve = avac->ve;
2737 if (GNUNET_YES == avac->done)
2739 avac->done = GNUNET_YES;
2740 return GNUNET_HELLO_add_address (ve->transport_name,
2741 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2751 * Closure for 'check_address_exists'.
2753 struct CheckAddressExistsClosure
2756 * Address to check for.
2761 * Name of the transport.
2768 struct Session *session;
2771 * Set to GNUNET_YES if the address exists.
2784 * Iterator over hash map entries. Checks if the given
2785 * validation entry is for the same address as what is given
2788 * @param cls the 'struct CheckAddressExistsClosure*'
2789 * @param key current key code (ignored)
2790 * @param value value in the hash map ('struct ValidationEntry')
2791 * @return GNUNET_YES if we should continue to
2792 * iterate (mismatch), GNUNET_NO if not (entry matched)
2795 check_address_exists (void *cls,
2796 const GNUNET_HashCode * key,
2799 struct CheckAddressExistsClosure *caec = cls;
2800 struct ValidationEntry *ve = value;
2802 if ( (0 == strcmp (caec->tname,
2803 ve->transport_name)) &&
2804 (caec->addrlen == ve->addrlen) &&
2805 (0 == memcmp (caec->addr,
2809 caec->exists = GNUNET_YES;
2812 if ( (ve->session != NULL) &&
2813 (caec->session == ve->session) )
2815 caec->exists = GNUNET_YES;
2824 * Iterator to free entries in the validation_map.
2826 * @param cls closure (unused)
2827 * @param key current key code
2828 * @param value value in the hash map (validation to abort)
2829 * @return GNUNET_YES (always)
2832 abort_validation (void *cls,
2833 const GNUNET_HashCode * key,
2836 struct ValidationEntry *va = value;
2838 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2839 GNUNET_SCHEDULER_cancel (va->timeout_task);
2840 GNUNET_free (va->transport_name);
2841 if (va->chvc != NULL)
2843 va->chvc->ve_count--;
2844 if (va->chvc->ve_count == 0)
2846 GNUNET_CONTAINER_DLL_remove (chvc_head,
2849 GNUNET_free (va->chvc);
2859 * HELLO validation cleanup task (validation failed).
2861 * @param cls the 'struct ValidationEntry' that failed
2862 * @param tc scheduler context (unused)
2865 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2867 struct ValidationEntry *va = cls;
2868 struct GNUNET_PeerIdentity pid;
2870 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2871 GNUNET_STATISTICS_update (stats,
2872 gettext_noop ("# address validation timeouts"),
2875 GNUNET_CRYPTO_hash (&va->publicKey,
2877 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2879 GNUNET_break (GNUNET_OK ==
2880 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2883 abort_validation (NULL, NULL, va);
2888 neighbour_timeout_task (void *cls,
2889 const struct GNUNET_SCHEDULER_TaskContext *tc)
2891 struct NeighbourList *n = cls;
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2895 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2897 GNUNET_STATISTICS_update (stats,
2898 gettext_noop ("# disconnects due to timeout"),
2901 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2902 disconnect_neighbour (n, GNUNET_NO);
2907 * Schedule the job that will cause us to send a PING to the
2908 * foreign address to evaluate its validity and latency.
2910 * @param fal address to PING
2913 schedule_next_ping (struct ForeignAddressList *fal);
2917 * Add the given address to the list of foreign addresses
2918 * available for the given peer (check for duplicates).
2920 * @param cls the respective 'struct NeighbourList' to update
2921 * @param tname name of the transport
2922 * @param expiration expiration time
2923 * @param addr the address
2924 * @param addrlen length of the address
2925 * @return GNUNET_OK (always)
2928 add_to_foreign_address_list (void *cls,
2930 struct GNUNET_TIME_Absolute expiration,
2934 struct NeighbourList *n = cls;
2935 struct ForeignAddressList *fal;
2938 GNUNET_STATISTICS_update (stats,
2939 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2943 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2946 #if DEBUG_TRANSPORT_HELLO
2947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2948 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2949 a2s (tname, addr, addrlen),
2951 GNUNET_i2s (&n->id),
2952 expiration.abs_value);
2954 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2957 GNUNET_STATISTICS_update (stats,
2958 gettext_noop ("# previously validated addresses lacking transport"),
2964 fal->expires = GNUNET_TIME_absolute_max (expiration,
2966 schedule_next_ping (fal);
2972 fal->expires = GNUNET_TIME_absolute_max (expiration,
2977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2978 "Failed to add new address for `%4s'\n",
2979 GNUNET_i2s (&n->id));
2982 if (fal->validated == GNUNET_NO)
2984 fal->validated = GNUNET_YES;
2985 GNUNET_STATISTICS_update (stats,
2986 gettext_noop ("# peer addresses considered valid"),
2990 if (try == GNUNET_YES)
2992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2993 "Have new addresses, will try to trigger transmissions.\n");
2994 try_transmission_to_peer (n);
3001 * Add addresses in validated HELLO "h" to the set of addresses
3002 * we have for this peer.
3004 * @param cls closure ('struct NeighbourList*')
3005 * @param peer id of the peer, NULL for last call
3006 * @param h hello message for the peer (can be NULL)
3007 * @param err_msg NULL if successful, otherwise contains error message
3010 add_hello_for_peer (void *cls,
3011 const struct GNUNET_PeerIdentity *peer,
3012 const struct GNUNET_HELLO_Message *h,
3013 const char *err_msg)
3015 struct NeighbourList *n = cls;
3017 if (err_msg != NULL)
3019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3020 _("Error in communication with PEERINFO service\n"));
3025 GNUNET_STATISTICS_update (stats,
3026 gettext_noop ("# outstanding peerinfo iterate requests"),
3033 return; /* no HELLO available */
3035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3036 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3040 if (GNUNET_YES != n->public_key_valid)
3042 GNUNET_HELLO_get_key (h, &n->publicKey);
3043 n->public_key_valid = GNUNET_YES;
3045 GNUNET_HELLO_iterate_addresses (h,
3047 &add_to_foreign_address_list,
3053 * Create a fresh entry in our neighbour list for the given peer.
3054 * Will try to transmit our current HELLO to the new neighbour.
3055 * Do not call this function directly, use 'setup_peer_check_blacklist.
3057 * @param peer the peer for which we create the entry
3058 * @param do_hello should we schedule transmitting a HELLO
3059 * @return the new neighbour list entry
3061 static struct NeighbourList *
3062 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3065 struct NeighbourList *n;
3066 struct TransportPlugin *tp;
3067 struct ReadyList *rl;
3070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071 "Setting up state for neighbour `%4s'\n",
3074 GNUNET_assert (our_hello != NULL);
3075 GNUNET_STATISTICS_update (stats,
3076 gettext_noop ("# active neighbours"),
3079 n = GNUNET_malloc (sizeof (struct NeighbourList));
3080 n->next = neighbours;
3084 GNUNET_TIME_relative_to_absolute
3085 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3086 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3087 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3088 MAX_BANDWIDTH_CARRY_S);
3092 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3094 rl = GNUNET_malloc (sizeof (struct ReadyList));
3096 rl->next = n->plugins;
3099 rl->addresses = NULL;
3103 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3105 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3106 &neighbour_timeout_task, n);
3109 GNUNET_STATISTICS_update (stats,
3110 gettext_noop ("# peerinfo new neighbor iterate requests"),
3113 GNUNET_STATISTICS_update (stats,
3114 gettext_noop ("# outstanding peerinfo iterate requests"),
3117 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3118 GNUNET_TIME_UNIT_FOREVER_REL,
3119 &add_hello_for_peer, n);
3121 GNUNET_STATISTICS_update (stats,
3122 gettext_noop ("# HELLO's sent to new neighbors"),
3125 transmit_to_peer (NULL, NULL, 0,
3126 HELLO_ADDRESS_EXPIRATION,
3127 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3135 * Function called after we have checked if communicating
3136 * with a given peer is acceptable.
3138 * @param cls closure
3139 * @param n NULL if communication is not acceptable
3141 typedef void (*SetupContinuation)(void *cls,
3142 struct NeighbourList *n);
3146 * Information kept for each client registered to perform
3152 * This is a linked list.
3154 struct Blacklisters *next;
3157 * This is a linked list.
3159 struct Blacklisters *prev;
3162 * Client responsible for this entry.
3164 struct GNUNET_SERVER_Client *client;
3167 * Blacklist check that we're currently performing.
3169 struct BlacklistCheck *bc;
3175 * Head of DLL of blacklisting clients.
3177 static struct Blacklisters *bl_head;
3180 * Tail of DLL of blacklisting clients.
3182 static struct Blacklisters *bl_tail;
3186 * Context we use when performing a blacklist check.
3188 struct BlacklistCheck
3192 * This is a linked list.
3194 struct BlacklistCheck *next;
3197 * This is a linked list.
3199 struct BlacklistCheck *prev;
3202 * Peer being checked.
3204 struct GNUNET_PeerIdentity peer;
3207 * Option for setup neighbour afterwards.
3212 * Continuation to call with the result.
3214 SetupContinuation cont;
3222 * Current transmission request handle for this client, or NULL if no
3223 * request is pending.
3225 struct GNUNET_CONNECTION_TransmitHandle *th;
3228 * Our current position in the blacklisters list.
3230 struct Blacklisters *bl_pos;
3233 * Current task performing the check.
3235 GNUNET_SCHEDULER_TaskIdentifier task;
3240 * Head of DLL of active blacklisting queries.
3242 static struct BlacklistCheck *bc_head;
3245 * Tail of DLL of active blacklisting queries.
3247 static struct BlacklistCheck *bc_tail;
3251 * Perform next action in the blacklist check.
3253 * @param cls the 'struct BlacklistCheck*'
3257 do_blacklist_check (void *cls,
3258 const struct GNUNET_SCHEDULER_TaskContext *tc);
3261 * Transmit blacklist query to the client.
3263 * @param cls the 'struct BlacklistCheck'
3264 * @param size number of bytes allowed
3265 * @param buf where to copy the message
3266 * @return number of bytes copied to buf
3269 transmit_blacklist_message (void *cls,
3273 struct BlacklistCheck *bc = cls;
3274 struct Blacklisters *bl;
3275 struct BlacklistMessage bm;
3280 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3281 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3286 bm.header.size = htons (sizeof (struct BlacklistMessage));
3287 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3288 bm.is_allowed = htonl (0);
3290 memcpy (buf, &bm, sizeof (bm));
3291 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3297 * Perform next action in the blacklist check.
3299 * @param cls the 'struct BlacklistCheck*'
3303 do_blacklist_check (void *cls,
3304 const struct GNUNET_SCHEDULER_TaskContext *tc)
3306 struct BlacklistCheck *bc = cls;
3307 struct Blacklisters *bl;
3309 bc->task = GNUNET_SCHEDULER_NO_TASK;
3313 bc->cont (bc->cont_cls,
3314 setup_new_neighbour (&bc->peer, bc->do_hello));
3321 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3322 sizeof (struct BlacklistMessage),
3323 GNUNET_TIME_UNIT_FOREVER_REL,
3324 &transmit_blacklist_message,
3331 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3332 * does not yet exist, check the blacklist. If the blacklist says creating
3333 * one is acceptable, create one and call the continuation; otherwise
3334 * call the continuation with NULL.
3336 * @param peer peer to setup or look up a struct NeighbourList for
3337 * @param do_hello should we also schedule sending our HELLO to the peer
3338 * if this is a new record
3339 * @param cont function to call with the 'struct NeigbhbourList*'
3340 * @param cont_cls closure for cont
3343 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3345 SetupContinuation cont,
3348 struct NeighbourList *n;
3349 struct BlacklistCheck *bc;
3351 n = find_neighbour(peer);
3358 if (bl_head == NULL)
3361 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3363 setup_new_neighbour(peer, do_hello);
3366 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3367 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3369 bc->do_hello = do_hello;
3371 bc->cont_cls = cont_cls;
3372 bc->bl_pos = bl_head;
3373 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3379 * Function called with the result of querying a new blacklister about
3380 * it being allowed (or not) to continue to talk to an existing neighbour.
3382 * @param cls the original 'struct NeighbourList'
3383 * @param n NULL if we need to disconnect
3386 confirm_or_drop_neighbour (void *cls,
3387 struct NeighbourList *n)
3389 struct NeighbourList * orig = cls;
3393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3394 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3395 "confirm_or_drop_neighboUr");
3396 disconnect_neighbour (orig, GNUNET_NO);
3402 * Handle a request to start a blacklist.
3404 * @param cls closure (always NULL)
3405 * @param client identification of the client
3406 * @param message the actual message
3409 handle_blacklist_init (void *cls,
3410 struct GNUNET_SERVER_Client *client,
3411 const struct GNUNET_MessageHeader *message)
3413 struct Blacklisters *bl;
3414 struct BlacklistCheck *bc;
3415 struct NeighbourList *n;
3420 if (bl->client == client)
3423 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3428 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3429 bl->client = client;
3430 GNUNET_SERVER_client_keep (client);
3431 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3432 /* confirm that all existing connections are OK! */
3436 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3437 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3439 bc->do_hello = GNUNET_NO;
3440 bc->cont = &confirm_or_drop_neighbour;
3443 if (n == neighbours) /* all would wait for the same client, no need to
3444 create more than just the first task right now */
3445 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3453 * Handle a request to blacklist a peer.
3455 * @param cls closure (always NULL)
3456 * @param client identification of the client
3457 * @param message the actual message
3460 handle_blacklist_reply (void *cls,
3461 struct GNUNET_SERVER_Client *client,
3462 const struct GNUNET_MessageHeader *message)
3464 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3465 struct Blacklisters *bl;
3466 struct BlacklistCheck *bc;
3469 while ( (bl != NULL) &&
3470 (bl->client != client) )
3474 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3479 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3481 bc->cont (bc->cont_cls, NULL);
3482 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3487 bc->bl_pos = bc->bl_pos->next;
3488 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3491 /* check if any other bc's are waiting for this blacklister */
3495 if ( (bc->bl_pos == bl) &&
3496 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3497 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3505 * Send periodic PING messages to a given foreign address.
3507 * @param cls our 'struct PeriodicValidationContext*'
3508 * @param tc task context
3511 send_periodic_ping (void *cls,
3512 const struct GNUNET_SCHEDULER_TaskContext *tc)
3514 struct ForeignAddressList *peer_address = cls;
3515 struct TransportPlugin *tp;
3516 struct ValidationEntry *va;
3517 struct NeighbourList *neighbour;
3518 struct TransportPingMessage ping;
3519 struct CheckAddressExistsClosure caec;
3521 uint16_t hello_size;
3525 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3526 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3528 tp = peer_address->ready_list->plugin;
3529 neighbour = peer_address->ready_list->neighbour;
3530 if (GNUNET_YES != neighbour->public_key_valid)
3532 /* no public key yet, try again later */
3533 schedule_next_ping (peer_address);
3536 caec.addr = peer_address->addr;
3537 caec.addrlen = peer_address->addrlen;
3538 caec.tname = tp->short_name;
3539 caec.session = peer_address->session;
3540 caec.exists = GNUNET_NO;
3541 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3542 &check_address_exists,
3544 if (caec.exists == GNUNET_YES)
3546 /* During validation attempts we will likely trigger the other
3547 peer trying to validate our address which in turn will cause
3548 it to send us its HELLO, so we expect to hit this case rather
3549 frequently. Only print something if we are very verbose. */
3550 #if DEBUG_TRANSPORT > 1
3551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3552 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3553 (peer_address->addr != NULL)
3554 ? a2s (tp->short_name,
3556 peer_address->addrlen)
3559 GNUNET_i2s (&neighbour->id));
3561 schedule_next_ping (peer_address);
3564 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3565 va->transport_name = GNUNET_strdup (tp->short_name);
3566 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3568 va->send_time = GNUNET_TIME_absolute_get();
3569 va->session = peer_address->session;
3570 if (peer_address->addr != NULL)
3572 va->addr = (const void*) &va[1];
3573 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3574 va->addrlen = peer_address->addrlen;
3576 memcpy(&va->publicKey,
3577 &neighbour->publicKey,
3578 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3580 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3581 &timeout_hello_validation,
3583 GNUNET_CONTAINER_multihashmap_put (validation_map,
3584 &neighbour->id.hashPubKey,
3586 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3588 if (peer_address->validated != GNUNET_YES)
3589 hello_size = GNUNET_HELLO_size(our_hello);
3593 tsize = sizeof(struct TransportPingMessage) + hello_size;
3595 if (peer_address->addr != NULL)
3597 slen = strlen (tp->short_name) + 1;
3598 tsize += slen + peer_address->addrlen;
3602 slen = 0; /* make gcc happy */
3604 message_buf = GNUNET_malloc(tsize);
3605 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3606 ping.challenge = htonl(va->challenge);
3607 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3608 if (peer_address->validated != GNUNET_YES)
3610 memcpy(message_buf, our_hello, hello_size);
3613 if (peer_address->addr != NULL)
3615 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3616 peer_address->addrlen +
3618 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3621 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3623 peer_address->addrlen);
3627 ping.header.size = htons(sizeof(struct TransportPingMessage));
3630 memcpy(&message_buf[hello_size],
3632 sizeof(struct TransportPingMessage));
3634 #if DEBUG_TRANSPORT_REVALIDATION
3635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3636 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3637 (peer_address->addr != NULL)
3638 ? a2s (peer_address->plugin->short_name,
3640 peer_address->addrlen)
3643 GNUNET_i2s (&neighbour->id),
3644 "HELLO", hello_size,
3647 if (peer_address->validated != GNUNET_YES)
3648 GNUNET_STATISTICS_update (stats,
3649 gettext_noop ("# PING with HELLO messages sent"),
3653 GNUNET_STATISTICS_update (stats,
3654 gettext_noop ("# PING without HELLO messages sent"),
3657 GNUNET_STATISTICS_update (stats,
3658 gettext_noop ("# PING messages sent for re-validation"),
3661 transmit_to_peer (NULL, peer_address,
3662 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3663 HELLO_VERIFICATION_TIMEOUT,
3665 GNUNET_YES, neighbour);
3666 GNUNET_free(message_buf);
3667 schedule_next_ping (peer_address);
3672 * Schedule the job that will cause us to send a PING to the
3673 * foreign address to evaluate its validity and latency.
3675 * @param fal address to PING
3678 schedule_next_ping (struct ForeignAddressList *fal)
3680 struct GNUNET_TIME_Relative delay;
3682 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3684 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3685 delay.rel_value /= 2; /* do before expiration */
3686 delay = GNUNET_TIME_relative_min (delay,
3687 LATENCY_EVALUATION_MAX_DELAY);
3688 if (GNUNET_YES != fal->estimated)
3690 delay = GNUNET_TIME_UNIT_ZERO;
3691 fal->estimated = GNUNET_YES;
3693 if (GNUNET_YES == fal->connected)
3695 delay = GNUNET_TIME_relative_min (delay,
3696 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3698 /* FIXME: also adjust delay based on how close the last
3699 observed latency is to the latency of the best alternative */
3700 /* bound how fast we can go */
3701 delay = GNUNET_TIME_relative_max (delay,
3702 GNUNET_TIME_UNIT_SECONDS);
3703 /* randomize a bit (to avoid doing all at the same time) */
3704 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3705 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3706 &send_periodic_ping,
3714 * Function that will be called if we receive some payload
3715 * from another peer.
3717 * @param message the payload
3718 * @param n peer who claimed to be the sender
3721 handle_payload_message (const struct GNUNET_MessageHeader *message,
3722 struct NeighbourList *n)
3724 struct InboundMessage *im;
3725 struct TransportClient *cpos;
3728 msize = ntohs (message->size);
3729 if (n->received_pong == GNUNET_NO)
3731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3732 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3733 ntohs (message->type),
3734 ntohs (message->size),
3735 GNUNET_i2s (&n->id));
3736 GNUNET_free_non_null (n->pre_connect_message_buffer);
3737 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3738 memcpy (n->pre_connect_message_buffer, message, msize);
3743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3744 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3745 ntohs (message->type),
3746 ntohs (message->size),
3747 GNUNET_i2s (&n->id));
3749 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3752 n->quota_violation_count++;
3754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3755 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3756 n->in_tracker.available_bytes_per_s__,
3757 n->quota_violation_count);
3759 /* Discount 32k per violation */
3760 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3765 if (n->quota_violation_count > 0)
3767 /* try to add 32k back */
3768 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3770 n->quota_violation_count--;
3773 GNUNET_STATISTICS_update (stats,
3774 gettext_noop ("# payload received from other peers"),
3777 /* transmit message to all clients */
3778 uint32_t ats_count = 2;
3779 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3780 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3783 im = GNUNET_malloc (size);
3784 im->header.size = htons (size);
3785 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3787 im->ats_count = htonl(ats_count);
3788 /* Setting ATS data */
3789 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3790 (&(im->ats))[0].value = htonl (n->distance);
3791 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3792 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3793 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3794 (&(im->ats))[ats_count].value = htonl (0);
3796 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3798 while (cpos != NULL)
3800 transmit_to_client (cpos, &im->header, GNUNET_YES);
3808 * Iterator over hash map entries. Checks if the given validation
3809 * entry is for the same challenge as what is given in the PONG.
3811 * @param cls the 'struct TransportPongMessage*'
3812 * @param key peer identity
3813 * @param value value in the hash map ('struct ValidationEntry')
3814 * @return GNUNET_YES if we should continue to
3815 * iterate (mismatch), GNUNET_NO if not (entry matched)
3818 check_pending_validation (void *cls,
3819 const GNUNET_HashCode * key,
3822 const struct TransportPongMessage *pong = cls;
3823 struct ValidationEntry *ve = value;
3824 struct AddValidatedAddressContext avac;
3825 unsigned int challenge = ntohl(pong->challenge);
3826 struct GNUNET_HELLO_Message *hello;
3827 struct GNUNET_PeerIdentity target;
3828 struct NeighbourList *n;
3829 struct ForeignAddressList *fal;
3830 struct OwnAddressList *oal;
3831 struct TransportPlugin *tp;
3832 struct GNUNET_MessageHeader *prem;
3838 ps = ntohs (pong->header.size);
3839 if (ps < sizeof (struct TransportPongMessage))
3841 GNUNET_break_op (0);
3844 addr = (const char*) &pong[1];
3845 slen = strlen (ve->transport_name) + 1;
3846 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3847 (ve->challenge != challenge) ||
3848 (addr[slen-1] != '\0') ||
3849 (0 != strcmp (addr, ve->transport_name)) ||
3850 (ntohl (pong->purpose.size)
3851 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3853 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3854 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3859 alen = ps - sizeof (struct TransportPongMessage) - slen;
3860 switch (ntohl (pong->purpose.purpose))
3862 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3863 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3864 (0 != memcmp (&addr[slen],
3868 return GNUNET_YES; /* different entry, keep trying! */
3870 if (0 != memcmp (&pong->pid,
3872 sizeof (struct GNUNET_PeerIdentity)))
3874 GNUNET_break_op (0);
3878 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3883 GNUNET_break_op (0);
3888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3889 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3891 a2s (ve->transport_name,
3892 (const struct sockaddr *) ve->addr,
3894 ve->transport_name);
3897 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3898 if (0 != memcmp (&pong->pid,
3900 sizeof (struct GNUNET_PeerIdentity)))
3902 GNUNET_break_op (0);
3905 if (ve->addrlen != 0)
3907 /* must have been for a different validation entry */
3910 tp = find_transport (ve->transport_name);
3916 oal = tp->addresses;
3919 if ( (oal->addrlen == alen) &&
3920 (0 == memcmp (&oal[1],
3928 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3929 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3930 a2s (ve->transport_name,
3936 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3941 GNUNET_break_op (0);
3946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3947 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3949 a2s (ve->transport_name,
3952 ve->transport_name);
3956 GNUNET_break_op (0);
3959 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3962 _("Received expired signature. Check system time.\n"));
3965 GNUNET_STATISTICS_update (stats,
3966 gettext_noop ("# address validation successes"),
3969 /* create the updated HELLO */
3970 GNUNET_CRYPTO_hash (&ve->publicKey,
3971 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3972 &target.hashPubKey);
3973 if (ve->addr != NULL)
3975 avac.done = GNUNET_NO;
3977 hello = GNUNET_HELLO_create (&ve->publicKey,
3978 &add_validated_address,
3980 GNUNET_PEERINFO_add_peer (peerinfo,
3982 GNUNET_free (hello);
3984 n = find_neighbour (&target);
3987 n->publicKey = ve->publicKey;
3988 n->public_key_valid = GNUNET_YES;
3989 fal = add_peer_address (n,
3994 GNUNET_assert (fal != NULL);
3995 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3996 fal->validated = GNUNET_YES;
3997 mark_address_connected (fal);
3998 GNUNET_STATISTICS_update (stats,
3999 gettext_noop ("# peer addresses considered valid"),
4002 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4003 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4005 schedule_next_ping (fal);
4006 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4007 n->latency = fal->latency;
4009 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4011 n->distance = fal->distance;
4012 if (GNUNET_NO == n->received_pong)
4014 n->received_pong = GNUNET_YES;
4016 notify_clients_connect (&target, n->latency, n->distance);
4017 if (NULL != (prem = n->pre_connect_message_buffer))
4019 n->pre_connect_message_buffer = NULL;
4020 handle_payload_message (prem, n);
4024 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4026 GNUNET_SCHEDULER_cancel (n->retry_task);
4027 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4028 try_transmission_to_peer (n);
4032 /* clean up validation entry */
4033 GNUNET_assert (GNUNET_YES ==
4034 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4037 abort_validation (NULL, NULL, ve);
4043 * Function that will be called if we receive a validation
4044 * of an address challenge that we transmitted to another
4045 * peer. Note that the validation should only be considered
4046 * acceptable if the challenge matches AND if the sender
4047 * address is at least a plausible address for this peer
4048 * (otherwise we may be seeing a MiM attack).
4050 * @param cls closure
4051 * @param message the pong message
4052 * @param peer who responded to our challenge
4053 * @param sender_address string describing our sender address (as observed
4054 * by the other peer in binary format)
4055 * @param sender_address_len number of bytes in 'sender_address'
4058 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4059 const struct GNUNET_PeerIdentity *peer,
4060 const char *sender_address,
4061 size_t sender_address_len)
4063 #if DEBUG_TRANSPORT > 1
4064 /* we get tons of these that just get discarded, only log
4065 if we are quite verbose */
4066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4067 "Receiving `%s' message from `%4s'.\n", "PONG",
4070 GNUNET_STATISTICS_update (stats,
4071 gettext_noop ("# PONG messages received"),
4074 if (GNUNET_SYSERR !=
4075 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4077 &check_pending_validation,
4080 /* This is *expected* to happen a lot since we send
4081 PONGs to *all* known addresses of the sender of
4082 the PING, so most likely we get multiple PONGs
4083 per PING, and all but the first PONG will end up
4084 here. So really we should not print anything here
4085 unless we want to be very, very verbose... */
4086 #if DEBUG_TRANSPORT > 2
4087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4088 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4100 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4102 * @param cls the 'struct ValidationEntry*'
4103 * @param neighbour neighbour to validate, NULL if validation failed
4106 transmit_hello_and_ping (void *cls,
4107 struct NeighbourList *neighbour)
4109 struct ValidationEntry *va = cls;
4110 struct ForeignAddressList *peer_address;
4111 struct TransportPingMessage ping;
4112 uint16_t hello_size;
4115 struct GNUNET_PeerIdentity id;
4118 GNUNET_CRYPTO_hash (&va->publicKey,
4119 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4121 if (neighbour == NULL)
4123 /* FIXME: stats... */
4124 GNUNET_break (GNUNET_OK ==
4125 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4128 abort_validation (NULL, NULL, va);
4131 neighbour->publicKey = va->publicKey;
4132 neighbour->public_key_valid = GNUNET_YES;
4133 peer_address = add_peer_address (neighbour,
4134 va->transport_name, NULL,
4135 (const void*) &va[1],
4137 if (peer_address == NULL)
4139 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4140 "Failed to add peer `%4s' for plugin `%s'\n",
4141 GNUNET_i2s (&neighbour->id),
4142 va->transport_name);
4143 GNUNET_break (GNUNET_OK ==
4144 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4147 abort_validation (NULL, NULL, va);
4150 hello_size = GNUNET_HELLO_size(our_hello);
4151 slen = strlen(va->transport_name) + 1;
4152 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4153 message_buf = GNUNET_malloc(tsize);
4154 ping.challenge = htonl(va->challenge);
4155 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4156 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4157 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4158 memcpy(message_buf, our_hello, hello_size);
4159 memcpy(&message_buf[hello_size],
4161 sizeof(struct TransportPingMessage));
4162 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4165 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4170 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4173 : a2s (va->transport_name,
4174 (const void*) &va[1], va->addrlen),
4176 GNUNET_i2s (&neighbour->id),
4177 "HELLO", hello_size,
4178 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4181 GNUNET_STATISTICS_update (stats,
4182 gettext_noop ("# PING messages sent for initial validation"),
4185 transmit_to_peer (NULL, peer_address,
4186 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4187 HELLO_VERIFICATION_TIMEOUT,
4189 GNUNET_YES, neighbour);
4190 GNUNET_free(message_buf);
4195 * Check if the given address is already being validated; if not,
4196 * append the given address to the list of entries that are being be
4197 * validated and initiate validation.
4199 * @param cls closure ('struct CheckHelloValidatedContext *')
4200 * @param tname name of the transport
4201 * @param expiration expiration time
4202 * @param addr the address
4203 * @param addrlen length of the address
4204 * @return GNUNET_OK (always)
4207 run_validation (void *cls,
4209 struct GNUNET_TIME_Absolute expiration,
4213 struct CheckHelloValidatedContext *chvc = cls;
4214 struct GNUNET_PeerIdentity id;
4215 struct TransportPlugin *tp;
4216 struct ValidationEntry *va;
4217 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4218 struct CheckAddressExistsClosure caec;
4219 struct OwnAddressList *oal;
4221 GNUNET_assert (addr != NULL);
4223 GNUNET_STATISTICS_update (stats,
4224 gettext_noop ("# peer addresses scheduled for validation"),
4227 tp = find_transport (tname);
4230 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4231 GNUNET_ERROR_TYPE_BULK,
4233 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4235 GNUNET_STATISTICS_update (stats,
4236 gettext_noop ("# peer addresses not validated (plugin not available)"),
4241 /* check if this is one of our own addresses */
4242 oal = tp->addresses;
4245 if ( (oal->addrlen == addrlen) &&
4246 (0 == memcmp (&oal[1],
4250 /* not plausible, this address is equivalent to our own address! */
4251 GNUNET_STATISTICS_update (stats,
4252 gettext_noop ("# peer addresses not validated (loopback)"),
4259 GNUNET_HELLO_get_key (chvc->hello, &pk);
4260 GNUNET_CRYPTO_hash (&pk,
4262 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4265 if (is_blacklisted(&id, tp))
4268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4269 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4277 caec.addrlen = addrlen;
4278 caec.session = NULL;
4280 caec.exists = GNUNET_NO;
4281 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4282 &check_address_exists,
4284 if (caec.exists == GNUNET_YES)
4286 /* During validation attempts we will likely trigger the other
4287 peer trying to validate our address which in turn will cause
4288 it to send us its HELLO, so we expect to hit this case rather
4289 frequently. Only print something if we are very verbose. */
4290 #if DEBUG_TRANSPORT > 1
4291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4292 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4293 a2s (tname, addr, addrlen),
4297 GNUNET_STATISTICS_update (stats,
4298 gettext_noop ("# peer addresses not validated (in progress)"),
4303 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4306 va->transport_name = GNUNET_strdup (tname);
4307 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4309 va->send_time = GNUNET_TIME_absolute_get();
4310 va->addr = (const void*) &va[1];
4311 memcpy (&va[1], addr, addrlen);
4312 va->addrlen = addrlen;
4313 GNUNET_HELLO_get_key (chvc->hello,
4315 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4316 &timeout_hello_validation,
4318 GNUNET_CONTAINER_multihashmap_put (validation_map,
4321 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4322 setup_peer_check_blacklist (&id, GNUNET_NO,
4323 &transmit_hello_and_ping,
4330 * Check if addresses in validated hello "h" overlap with
4331 * those in "chvc->hello" and validate the rest.
4333 * @param cls closure
4334 * @param peer id of the peer, NULL for last call
4335 * @param h hello message for the peer (can be NULL)
4336 * @param err_msg NULL if successful, otherwise contains error message
4339 check_hello_validated (void *cls,
4340 const struct GNUNET_PeerIdentity *peer,
4341 const struct GNUNET_HELLO_Message *h,
4342 const char *err_msg)
4344 struct CheckHelloValidatedContext *chvc = cls;
4345 struct GNUNET_HELLO_Message *plain_hello;
4346 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4347 struct GNUNET_PeerIdentity target;
4348 struct NeighbourList *n;
4350 if (err_msg != NULL)
4352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4353 _("Error in communication with PEERINFO service\n"));
4359 GNUNET_STATISTICS_update (stats,
4360 gettext_noop ("# outstanding peerinfo iterate requests"),
4364 if (GNUNET_NO == chvc->hello_known)
4366 /* notify PEERINFO about the peer now, so that we at least
4367 have the public key if some other component needs it */
4368 GNUNET_HELLO_get_key (chvc->hello, &pk);
4369 GNUNET_CRYPTO_hash (&pk,
4370 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4371 &target.hashPubKey);
4372 plain_hello = GNUNET_HELLO_create (&pk,
4375 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4376 GNUNET_free (plain_hello);
4377 #if DEBUG_TRANSPORT_HELLO
4378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4379 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4381 GNUNET_i2s (&target));
4383 GNUNET_STATISTICS_update (stats,
4384 gettext_noop ("# new HELLOs requiring full validation"),
4387 GNUNET_HELLO_iterate_addresses (chvc->hello,
4394 GNUNET_STATISTICS_update (stats,
4395 gettext_noop ("# duplicate HELLO (peer known)"),
4400 if (chvc->ve_count == 0)
4402 GNUNET_CONTAINER_DLL_remove (chvc_head,
4411 #if DEBUG_TRANSPORT_HELLO
4412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4413 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4417 chvc->hello_known = GNUNET_YES;
4418 n = find_neighbour (peer);
4421 #if DEBUG_TRANSPORT_HELLO
4422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4423 "Calling hello_iterate_addresses for %s!\n",
4426 GNUNET_HELLO_iterate_addresses (h,
4428 &add_to_foreign_address_list,
4430 try_transmission_to_peer (n);
4434 #if DEBUG_TRANSPORT_HELLO
4435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4436 "No existing neighbor record for %s!\n",
4439 GNUNET_STATISTICS_update (stats,
4440 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4444 GNUNET_STATISTICS_update (stats,
4445 gettext_noop ("# HELLO validations (update case)"),
4448 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4450 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4457 * Process HELLO-message.
4459 * @param plugin transport involved, may be NULL
4460 * @param message the actual message
4461 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4464 process_hello (struct TransportPlugin *plugin,
4465 const struct GNUNET_MessageHeader *message)
4468 struct GNUNET_PeerIdentity target;
4469 const struct GNUNET_HELLO_Message *hello;
4470 struct CheckHelloValidatedContext *chvc;
4471 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4472 #if DEBUG_TRANSPORT_HELLO > 2
4475 hsize = ntohs (message->size);
4476 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4477 (hsize < sizeof (struct GNUNET_MessageHeader)))
4480 return GNUNET_SYSERR;
4482 GNUNET_STATISTICS_update (stats,
4483 gettext_noop ("# HELLOs received for validation"),
4487 /* first, check if load is too high */
4488 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4490 GNUNET_STATISTICS_update (stats,
4491 gettext_noop ("# HELLOs ignored due to high load"),
4494 #if DEBUG_TRANSPORT_HELLO
4495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4496 "Ignoring `%s' for `%4s', load too high.\n",
4498 GNUNET_i2s (&target));
4502 hello = (const struct GNUNET_HELLO_Message *) message;
4503 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4505 #if DEBUG_TRANSPORT_HELLO
4506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4507 "Unable to get public key from `%s' for `%4s'!\n",
4509 GNUNET_i2s (&target));
4511 GNUNET_break_op (0);
4512 return GNUNET_SYSERR;
4515 GNUNET_CRYPTO_hash (&publicKey,
4516 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4517 &target.hashPubKey);
4519 #if DEBUG_TRANSPORT_HELLO
4520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4521 "Received `%s' message for `%4s'\n",
4523 GNUNET_i2s (&target));
4526 if (0 == memcmp (&my_identity,
4528 sizeof (struct GNUNET_PeerIdentity)))
4530 GNUNET_STATISTICS_update (stats,
4531 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4537 while (NULL != chvc)
4539 if (GNUNET_HELLO_equals (hello,
4541 GNUNET_TIME_absolute_get ()).abs_value > 0)
4543 #if DEBUG_TRANSPORT_HELLO > 2
4544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4545 "Received duplicate `%s' message for `%4s'; ignored\n",
4547 GNUNET_i2s (&target));
4549 return GNUNET_OK; /* validation already pending */
4551 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4552 GNUNET_break (0 != memcmp (hello, chvc->hello,
4553 GNUNET_HELLO_size(hello)));
4558 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4559 if ((NULL != temp_neighbor))
4561 fprintf(stderr, "Already know peer, ignoring hello\n");
4566 #if DEBUG_TRANSPORT_HELLO > 2
4569 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4571 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4574 GNUNET_i2s (&target),
4576 GNUNET_HELLO_size(hello));
4580 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4582 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4583 memcpy (&chvc[1], hello, hsize);
4584 GNUNET_CONTAINER_DLL_insert (chvc_head,
4587 /* finally, check if HELLO was previously validated
4588 (continuation will then schedule actual validation) */
4589 GNUNET_STATISTICS_update (stats,
4590 gettext_noop ("# peerinfo process hello iterate requests"),
4593 GNUNET_STATISTICS_update (stats,
4594 gettext_noop ("# outstanding peerinfo iterate requests"),
4597 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4599 HELLO_VERIFICATION_TIMEOUT,
4600 &check_hello_validated, chvc);
4606 * The peer specified by the given neighbour has timed-out or a plugin
4607 * has disconnected. We may either need to do nothing (other plugins
4608 * still up), or trigger a full disconnect and clean up. This
4609 * function updates our state and does the necessary notifications.
4610 * Also notifies our clients that the neighbour is now officially
4613 * @param n the neighbour list entry for the peer
4614 * @param check GNUNET_YES to check if ALL addresses for this peer
4615 * are gone, GNUNET_NO to force a disconnect of the peer
4616 * regardless of whether other addresses exist.
4619 disconnect_neighbour (struct NeighbourList *n, int check)
4621 struct ReadyList *rpos;
4622 struct NeighbourList *npos;
4623 struct NeighbourList *nprev;
4624 struct MessageQueue *mq;
4625 struct ForeignAddressList *peer_addresses;
4626 struct ForeignAddressList *peer_pos;
4628 if (GNUNET_YES == check)
4631 while (NULL != rpos)
4633 peer_addresses = rpos->addresses;
4634 while (peer_addresses != NULL)
4636 if (GNUNET_YES == peer_addresses->connected)
4638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4639 "NOT Disconnecting from `%4s', still have live addresses!\n",
4640 GNUNET_i2s (&n->id));
4641 return; /* still connected */
4643 peer_addresses = peer_addresses->next;
4649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4650 "Disconnecting from `%4s'\n",
4651 GNUNET_i2s (&n->id));
4653 /* remove n from neighbours list */
4656 while ((npos != NULL) && (npos != n))
4661 GNUNET_assert (npos != NULL);
4663 neighbours = n->next;
4665 nprev->next = n->next;
4667 /* notify all clients about disconnect */
4668 if (GNUNET_YES == n->received_pong)
4669 notify_clients_disconnect (&n->id);
4671 /* clean up all plugins, cancel connections and pending transmissions */
4672 while (NULL != (rpos = n->plugins))
4674 n->plugins = rpos->next;
4675 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4676 while (rpos->addresses != NULL)
4678 peer_pos = rpos->addresses;
4679 rpos->addresses = peer_pos->next;
4680 if (peer_pos->connected == GNUNET_YES)
4681 GNUNET_STATISTICS_update (stats,
4682 gettext_noop ("# connected addresses"),
4685 if (GNUNET_YES == peer_pos->validated)
4686 GNUNET_STATISTICS_update (stats,
4687 gettext_noop ("# peer addresses considered valid"),
4690 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4692 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4693 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4695 GNUNET_free(peer_pos->ressources);
4696 GNUNET_free(peer_pos->quality);
4697 GNUNET_free(peer_pos);
4702 /* free all messages on the queue */
4703 while (NULL != (mq = n->messages_head))
4705 GNUNET_STATISTICS_update (stats,
4706 gettext_noop ("# bytes in message queue for other peers"),
4707 - (int64_t) mq->message_buf_size,
4709 GNUNET_STATISTICS_update (stats,
4710 gettext_noop ("# bytes discarded due to disconnect"),
4711 mq->message_buf_size,
4713 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4716 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4718 sizeof(struct GNUNET_PeerIdentity)));
4721 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4723 GNUNET_SCHEDULER_cancel (n->timeout_task);
4724 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4726 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4728 GNUNET_SCHEDULER_cancel (n->retry_task);
4729 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4731 if (n->piter != NULL)
4733 GNUNET_PEERINFO_iterate_cancel (n->piter);
4734 GNUNET_STATISTICS_update (stats,
4735 gettext_noop ("# outstanding peerinfo iterate requests"),
4740 /* finally, free n itself */
4741 GNUNET_STATISTICS_update (stats,
4742 gettext_noop ("# active neighbours"),
4745 GNUNET_free_non_null (n->pre_connect_message_buffer);
4751 * We have received a PING message from someone. Need to send a PONG message
4752 * in response to the peer by any means necessary.
4755 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4756 const struct GNUNET_PeerIdentity *peer,
4757 struct Session *session,
4758 const char *sender_address,
4759 uint16_t sender_address_len)
4761 struct TransportPlugin *plugin = cls;
4762 struct SessionHeader *session_header = (struct SessionHeader*) session;
4763 struct TransportPingMessage *ping;
4764 struct TransportPongMessage *pong;
4765 struct NeighbourList *n;
4766 struct ReadyList *rl;
4767 struct ForeignAddressList *fal;
4768 struct OwnAddressList *oal;
4773 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4775 GNUNET_break_op (0);
4776 return GNUNET_SYSERR;
4779 ping = (struct TransportPingMessage *) message;
4780 if (0 != memcmp (&ping->target,
4781 plugin->env.my_identity,
4782 sizeof (struct GNUNET_PeerIdentity)))
4784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4785 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4787 (sender_address != NULL)
4788 ? a2s (plugin->short_name,
4789 (const struct sockaddr *)sender_address,
4792 GNUNET_i2s (&ping->target));
4793 return GNUNET_SYSERR;
4796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4797 "Processing `%s' from `%s'\n",
4799 (sender_address != NULL)
4800 ? a2s (plugin->short_name,
4801 (const struct sockaddr *)sender_address,
4805 GNUNET_STATISTICS_update (stats,
4806 gettext_noop ("# PING messages received"),
4809 addr = (const char*) &ping[1];
4810 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4811 slen = strlen (plugin->short_name) + 1;
4814 /* peer wants to confirm that we have an outbound connection to him */
4815 if (session == NULL)
4817 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4818 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4820 return GNUNET_SYSERR;
4822 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4823 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4824 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4825 pong->purpose.size =
4826 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4828 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4829 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4830 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4831 pong->challenge = ping->challenge;
4832 pong->addrlen = htonl(sender_address_len + slen);
4835 sizeof(struct GNUNET_PeerIdentity));
4839 if ((sender_address!=NULL) && (sender_address_len > 0))
4840 memcpy (&((char*)&pong[1])[slen],
4842 sender_address_len);
4843 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4845 /* create / update cached sig */
4847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4848 "Creating PONG signature to indicate active connection.\n");
4850 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4851 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4852 GNUNET_assert (GNUNET_OK ==
4853 GNUNET_CRYPTO_rsa_sign (my_private_key,
4855 &session_header->pong_signature));
4859 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4861 memcpy (&pong->signature,
4862 &session_header->pong_signature,
4863 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4869 /* peer wants to confirm that this is one of our addresses */
4873 plugin->api->check_address (plugin->api->cls,
4877 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4878 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4879 a2s (plugin->short_name,
4884 oal = plugin->addresses;
4887 if ( (oal->addrlen == alen) &&
4894 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4895 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4896 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4897 pong->purpose.size =
4898 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4900 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4901 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4902 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4903 pong->challenge = ping->challenge;
4904 pong->addrlen = htonl(alen + slen);
4907 sizeof(struct GNUNET_PeerIdentity));
4908 memcpy (&pong[1], plugin->short_name, slen);
4909 memcpy (&((char*)&pong[1])[slen], addr, alen);
4910 if ( (oal != NULL) &&
4911 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4913 /* create / update cached sig */
4915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4916 "Creating PONG signature to indicate ownership.\n");
4918 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4919 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4920 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4921 GNUNET_assert (GNUNET_OK ==
4922 GNUNET_CRYPTO_rsa_sign (my_private_key,
4924 &oal->pong_signature));
4925 memcpy (&pong->signature,
4926 &oal->pong_signature,
4927 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4929 else if (oal == NULL)
4931 /* not using cache (typically DV-only) */
4932 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4933 GNUNET_assert (GNUNET_OK ==
4934 GNUNET_CRYPTO_rsa_sign (my_private_key,
4940 /* can used cached version */
4941 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4942 memcpy (&pong->signature,
4943 &oal->pong_signature,
4944 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4947 n = find_neighbour(peer);
4948 GNUNET_assert (n != NULL);
4949 /* first try reliable response transmission */
4953 fal = rl->addresses;
4956 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4959 ntohs (pong->header.size),
4960 TRANSPORT_PONG_PRIORITY,
4961 HELLO_VERIFICATION_TIMEOUT,
4969 GNUNET_STATISTICS_update (stats,
4970 gettext_noop ("# PONGs unicast via reliable transport"),
4980 /* no reliable method found, do multicast */
4981 GNUNET_STATISTICS_update (stats,
4982 gettext_noop ("# PONGs multicast to all available addresses"),
4988 fal = rl->addresses;
4991 transmit_to_peer(NULL, fal,
4992 TRANSPORT_PONG_PRIORITY,
4993 HELLO_VERIFICATION_TIMEOUT,
4995 ntohs(pong->header.size),
5011 * Function called by the plugin for each received message.
5012 * Update data volumes, possibly notify plugins about
5013 * reducing the rate at which they read from the socket
5014 * and generally forward to our receive callback.
5016 * @param cls the "struct TransportPlugin *" we gave to the plugin
5017 * @param peer (claimed) identity of the other peer
5018 * @param message the message, NULL if we only care about
5019 * learning about the delay until we should receive again
5020 * @param ats_data information for automatic transport selection
5021 * @param ats_count number of elements in ats not including 0-terminator
5022 * @param session identifier used for this session (can be NULL)
5023 * @param sender_address binary address of the sender (if observed)
5024 * @param sender_address_len number of bytes in sender_address
5025 * @return how long in ms the plugin should wait until receiving more data
5026 * (plugins that do not support this, can ignore the return value)
5028 static struct GNUNET_TIME_Relative
5029 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5030 const struct GNUNET_MessageHeader *message,
5031 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5033 struct Session *session,
5034 const char *sender_address,
5035 uint16_t sender_address_len)
5037 struct TransportPlugin *plugin = cls;
5038 struct ReadyList *service_context;
5039 struct ForeignAddressList *peer_address;
5041 struct NeighbourList *n;
5042 struct GNUNET_TIME_Relative ret;
5043 if (is_blacklisted (peer, plugin))
5044 return GNUNET_TIME_UNIT_FOREVER_REL;
5048 n = find_neighbour (peer);
5050 n = setup_new_neighbour (peer, GNUNET_YES);
5051 service_context = n->plugins;
5052 while ((service_context != NULL) && (plugin != service_context->plugin))
5053 service_context = service_context->next;
5054 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5055 peer_address = NULL;
5058 for (c=0; c<ats_count; c++)
5060 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5062 distance = ntohl(ats_data[c].value);
5065 /* notify ATS about incoming data */
5066 //ats_notify_ats_data(peer, ats_data);
5068 if (message != NULL)
5070 if ( (session != NULL) ||
5071 (sender_address != NULL) )
5072 peer_address = add_peer_address (n,
5076 sender_address_len);
5077 if (peer_address != NULL)
5080 update_addr_ats(peer_address, ats_data, ats_count);
5081 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5083 peer_address->distance = distance;
5084 if (GNUNET_YES == peer_address->validated)
5085 mark_address_connected (peer_address);
5086 peer_address->timeout
5088 GNUNET_TIME_relative_to_absolute
5089 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5090 schedule_next_ping (peer_address);
5092 /* update traffic received amount ... */
5093 msize = ntohs (message->size);
5094 GNUNET_STATISTICS_update (stats,
5095 gettext_noop ("# bytes received from other peers"),
5098 n->distance = distance;
5100 GNUNET_TIME_relative_to_absolute
5101 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5102 GNUNET_SCHEDULER_cancel (n->timeout_task);
5104 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5105 &neighbour_timeout_task, n);
5106 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5108 /* dropping message due to frequent inbound volume violations! */
5109 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5110 GNUNET_ERROR_TYPE_BULK,
5112 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5113 n->in_tracker.available_bytes_per_s__,
5114 n->quota_violation_count);
5115 GNUNET_STATISTICS_update (stats,
5116 gettext_noop ("# bandwidth quota violations by other peers"),
5119 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5124 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5125 ntohs (message->type),
5126 ntohs (message->size),
5129 switch (ntohs (message->type))
5131 case GNUNET_MESSAGE_TYPE_HELLO:
5132 GNUNET_STATISTICS_update (stats,
5133 gettext_noop ("# HELLO messages received from other peers"),
5136 process_hello (plugin, message);
5138 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5139 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5141 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5142 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5145 handle_payload_message (message, n);
5149 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5150 if (ret.rel_value > 0)
5152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5153 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5154 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5155 (unsigned int) n->in_tracker.available_bytes_per_s__,
5156 (unsigned long long) ret.rel_value);
5157 GNUNET_STATISTICS_update (stats,
5158 gettext_noop ("# ms throttling suggested"),
5159 (int64_t) ret.rel_value,
5166 * Handle START-message. This is the first message sent to us
5167 * by any client which causes us to add it to our list.
5169 * @param cls closure (always NULL)
5170 * @param client identification of the client
5171 * @param message the actual message
5174 handle_start (void *cls,
5175 struct GNUNET_SERVER_Client *client,
5176 const struct GNUNET_MessageHeader *message)
5178 const struct StartMessage *start;
5179 struct TransportClient *c;
5180 struct ConnectInfoMessage * cim;
5181 struct NeighbourList *n;
5185 start = (const struct StartMessage*) message;
5187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5188 "Received `%s' request from client\n", "START");
5193 if (c->client == client)
5195 /* client already on our list! */
5197 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5202 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5203 (0 != memcmp (&start->self,
5205 sizeof (struct GNUNET_PeerIdentity))) )
5207 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5208 _("Rejecting control connection from peer `%s', which is not me!\n"),
5209 GNUNET_i2s (&start->self));
5210 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5213 c = GNUNET_malloc (sizeof (struct TransportClient));
5217 if (our_hello != NULL)
5220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5221 "Sending our own `%s' to new client\n", "HELLO");
5223 transmit_to_client (c,
5224 (const struct GNUNET_MessageHeader *) our_hello,
5226 /* tell new client about all existing connections */
5228 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5229 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5233 cim = GNUNET_malloc (size);
5234 cim->header.size = htons (size);
5235 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5236 cim->ats_count = htonl(ats_count);
5237 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5238 (&(cim->ats))[2].value = htonl (0);
5242 if (GNUNET_YES == n->received_pong)
5244 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5245 (&(cim->ats))[0].value = htonl (n->distance);
5246 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5247 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5249 transmit_to_client (c, &cim->header, GNUNET_NO);
5255 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5260 * Handle HELLO-message.
5262 * @param cls closure (always NULL)
5263 * @param client identification of the client
5264 * @param message the actual message
5267 handle_hello (void *cls,
5268 struct GNUNET_SERVER_Client *client,
5269 const struct GNUNET_MessageHeader *message)
5273 GNUNET_STATISTICS_update (stats,
5274 gettext_noop ("# HELLOs received from clients"),
5277 ret = process_hello (NULL, message);
5278 GNUNET_SERVER_receive_done (client, ret);
5283 * Closure for 'transmit_client_message'; followed by
5284 * 'msize' bytes of the actual message.
5286 struct TransmitClientMessageContext
5289 * Client on whom's behalf we are sending.
5291 struct GNUNET_SERVER_Client *client;
5294 * Timeout for the transmission.
5296 struct GNUNET_TIME_Absolute timeout;
5304 * Size of the message in bytes.
5311 * Schedule transmission of a message we got from a client to a peer.
5313 * @param cls the 'struct TransmitClientMessageContext*'
5314 * @param n destination, or NULL on error (in that case, drop the message)
5317 transmit_client_message (void *cls,
5318 struct NeighbourList *n)
5320 struct TransmitClientMessageContext *tcmc = cls;
5321 struct TransportClient *tc;
5324 while ((tc != NULL) && (tc->client != tcmc->client))
5329 transmit_to_peer (tc, NULL, tcmc->priority,
5330 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5332 tcmc->msize, GNUNET_NO, n);
5334 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5335 GNUNET_SERVER_client_drop (tcmc->client);
5341 * Handle SEND-message.
5343 * @param cls closure (always NULL)
5344 * @param client identification of the client
5345 * @param message the actual message
5348 handle_send (void *cls,
5349 struct GNUNET_SERVER_Client *client,
5350 const struct GNUNET_MessageHeader *message)
5352 const struct OutboundMessage *obm;
5353 const struct GNUNET_MessageHeader *obmm;
5354 struct TransmitClientMessageContext *tcmc;
5358 size = ntohs (message->size);
5360 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5363 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5366 GNUNET_STATISTICS_update (stats,
5367 gettext_noop ("# payload received for other peers"),
5370 obm = (const struct OutboundMessage *) message;
5371 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5372 msize = size - sizeof (struct OutboundMessage);
5374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5375 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5376 "SEND", GNUNET_i2s (&obm->peer),
5380 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5381 tcmc->client = client;
5382 tcmc->priority = ntohl (obm->priority);
5383 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5384 tcmc->msize = msize;
5385 /* FIXME: this memcpy can be up to 7% of our total runtime */
5386 memcpy (&tcmc[1], obmm, msize);
5387 GNUNET_SERVER_client_keep (client);
5388 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5389 &transmit_client_message,
5395 * Handle request connect message
5397 * @param cls closure (always NULL)
5398 * @param client identification of the client
5399 * @param message the actual message
5402 handle_request_connect (void *cls,
5403 struct GNUNET_SERVER_Client *client,
5404 const struct GNUNET_MessageHeader *message)
5406 const struct TransportRequestConnectMessage *trcm =
5407 (const struct TransportRequestConnectMessage *) message;
5409 GNUNET_STATISTICS_update (stats,
5410 gettext_noop ("# REQUEST CONNECT messages received"),
5413 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5414 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5416 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5420 * Handle SET_QUOTA-message.
5422 * @param cls closure (always NULL)
5423 * @param client identification of the client
5424 * @param message the actual message
5427 handle_set_quota (void *cls,
5428 struct GNUNET_SERVER_Client *client,
5429 const struct GNUNET_MessageHeader *message)
5431 const struct QuotaSetMessage *qsm =
5432 (const struct QuotaSetMessage *) message;
5433 struct NeighbourList *n;
5435 GNUNET_STATISTICS_update (stats,
5436 gettext_noop ("# SET QUOTA messages received"),
5439 n = find_neighbour (&qsm->peer);
5442 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5443 GNUNET_STATISTICS_update (stats,
5444 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5451 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5453 (unsigned int) ntohl (qsm->quota.value__),
5454 (unsigned int) n->in_tracker.available_bytes_per_s__,
5455 GNUNET_i2s (&qsm->peer));
5457 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5459 if (0 == ntohl (qsm->quota.value__))
5461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5462 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5464 disconnect_neighbour (n, GNUNET_NO);
5466 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5471 * Take the given address and append it to the set of results sent back to
5474 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5475 * @param address the resolved name, NULL to indicate the last response
5478 transmit_address_to_client (void *cls, const char *address)
5480 struct GNUNET_SERVER_TransmitContext *tc = cls;
5483 if (NULL == address)
5486 slen = strlen (address) + 1;
5488 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5489 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5490 if (NULL == address)
5491 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5496 * Handle AddressLookup-message.
5498 * @param cls closure (always NULL)
5499 * @param client identification of the client
5500 * @param message the actual message
5503 handle_address_lookup (void *cls,
5504 struct GNUNET_SERVER_Client *client,
5505 const struct GNUNET_MessageHeader *message)
5507 const struct AddressLookupMessage *alum;
5508 struct TransportPlugin *lsPlugin;
5509 const char *nameTransport;
5510 const char *address;
5512 struct GNUNET_SERVER_TransmitContext *tc;
5513 struct GNUNET_TIME_Absolute timeout;
5514 struct GNUNET_TIME_Relative rtimeout;
5517 size = ntohs (message->size);
5518 if (size < sizeof (struct AddressLookupMessage))
5520 GNUNET_break_op (0);
5521 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5524 alum = (const struct AddressLookupMessage *) message;
5525 uint32_t addressLen = ntohl (alum->addrlen);
5526 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5528 GNUNET_break_op (0);
5529 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5532 address = (const char *) &alum[1];
5533 nameTransport = (const char *) &address[addressLen];
5535 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5537 GNUNET_break_op (0);
5538 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5541 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5542 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5543 numeric = ntohl (alum->numeric_only);
5544 lsPlugin = find_transport (nameTransport);
5545 if (NULL == lsPlugin)
5547 tc = GNUNET_SERVER_transmit_context_create (client);
5548 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5549 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5550 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5553 tc = GNUNET_SERVER_transmit_context_create (client);
5554 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5556 address, addressLen,
5559 &transmit_address_to_client, tc);
5564 * Setup the environment for this plugin.
5567 create_environment (struct TransportPlugin *plug)
5569 plug->env.cfg = cfg;
5570 plug->env.my_identity = &my_identity;
5571 plug->env.our_hello = &our_hello;
5572 plug->env.cls = plug;
5573 plug->env.receive = &plugin_env_receive;
5574 plug->env.notify_address = &plugin_env_notify_address;
5575 plug->env.session_end = &plugin_env_session_end;
5576 plug->env.max_connections = max_connect_per_transport;
5577 plug->env.stats = stats;
5582 * Start the specified transport (load the plugin).
5585 start_transport (struct GNUNET_SERVER_Handle *server,
5588 struct TransportPlugin *plug;
5591 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5592 _("Loading `%s' transport plugin\n"), name);
5593 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5594 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5595 create_environment (plug);
5596 plug->short_name = GNUNET_strdup (name);
5597 plug->lib_name = libname;
5598 plug->next = plugins;
5600 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5601 if (plug->api == NULL)
5603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5604 _("Failed to load transport plugin for `%s'\n"), name);
5605 GNUNET_free (plug->short_name);
5606 plugins = plug->next;
5607 GNUNET_free (libname);
5614 * Called whenever a client is disconnected. Frees our
5615 * resources associated with that client.
5617 * @param cls closure
5618 * @param client identification of the client
5621 client_disconnect_notification (void *cls,
5622 struct GNUNET_SERVER_Client *client)
5624 struct TransportClient *pos;
5625 struct TransportClient *prev;
5626 struct ClientMessageQueueEntry *mqe;
5627 struct Blacklisters *bl;
5628 struct BlacklistCheck *bc;
5633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5634 "Client disconnected, cleaning up.\n");
5636 /* clean up blacklister */
5640 if (bl->client == client)
5645 if (bc->bl_pos == bl)
5647 bc->bl_pos = bl->next;
5650 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5653 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5654 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5660 GNUNET_CONTAINER_DLL_remove (bl_head,
5663 GNUNET_SERVER_client_drop (bl->client);
5669 /* clean up 'normal' clients */
5672 while ((pos != NULL) && (pos->client != client))
5679 while (NULL != (mqe = pos->message_queue_head))
5681 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5682 pos->message_queue_tail,
5684 pos->message_count--;
5688 clients = pos->next;
5690 prev->next = pos->next;
5691 if (GNUNET_YES == pos->tcs_pending)
5696 if (pos->th != NULL)
5698 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5701 GNUNET_break (0 == pos->message_count);
5707 * Function called when the service shuts down. Unloads our plugins
5708 * and cancels pending validations.
5710 * @param cls closure, unused
5711 * @param tc task context (unused)
5714 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5716 struct TransportPlugin *plug;
5717 struct OwnAddressList *al;
5718 struct CheckHelloValidatedContext *chvc;
5720 while (neighbours != NULL)
5722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5723 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5725 disconnect_neighbour (neighbours, GNUNET_NO);
5728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5729 "Transport service is unloading plugins...\n");
5731 while (NULL != (plug = plugins))
5733 plugins = plug->next;
5734 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5736 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5737 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5739 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5740 GNUNET_free (plug->lib_name);
5741 GNUNET_free (plug->short_name);
5742 while (NULL != (al = plug->addresses))
5744 plug->addresses = al->next;
5749 if (my_private_key != NULL)
5750 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5751 GNUNET_free_non_null (our_hello);
5753 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5756 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5757 validation_map = NULL;
5761 /* free 'chvc' data structure */
5762 while (NULL != (chvc = chvc_head))
5764 chvc_head = chvc->next;
5765 if (chvc->piter != NULL)
5767 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5768 GNUNET_STATISTICS_update (stats,
5769 gettext_noop ("# outstanding peerinfo iterate requests"),
5775 GNUNET_assert (chvc->ve_count == 0);
5782 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5785 if (peerinfo != NULL)
5787 GNUNET_PEERINFO_disconnect (peerinfo);
5790 /* Can we assume those are gone by now, or do we need to clean up
5792 GNUNET_break (bl_head == NULL);
5793 GNUNET_break (bc_head == NULL);
5797 static int ats_evaluate_results (int result, int solution, char * problem)
5799 int cont = GNUNET_NO;
5800 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5802 error_kind = GNUNET_ERROR_TYPE_ERROR;
5806 case GLP_ESTOP : /* search terminated by application */
5807 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5809 case GLP_EITLIM : /* iteration limit exceeded */
5810 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5813 case GLP_ETMLIM : /* time limit exceeded */
5814 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5816 case GLP_ENOPFS : /* no primal feasible solution */
5817 case GLP_ENODFS : /* no dual feasible solution */
5818 GNUNET_log (error_kind, "%s No feasible solution", problem);
5821 case GLP_EBADB : /* invalid basis */
5822 case GLP_ESING : /* singular matrix */
5823 case GLP_ECOND : /* ill-conditioned matrix */
5824 case GLP_EBOUND : /* invalid bounds */
5825 case GLP_EFAIL : /* solver failed */
5826 case GLP_EOBJLL : /* objective lower limit reached */
5827 case GLP_EOBJUL : /* objective upper limit reached */
5828 case GLP_EROOT : /* root LP optimum not provided */
5829 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5833 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5839 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
5842 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
5846 GNUNET_log (error_kind, "%s solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n", problem);
5850 GNUNET_log (error_kind, "%s problem has no integer feasible solution\n", problem);
5860 /** solve the bandwidth distribution problem
5861 * @param max_it maximum iterations
5862 * @param max_dur maximum duration in ms
5863 * @param D weight for diversity
5864 * @param U weight for utility
5865 * @param R weight for relativity
5866 * @param v_b_min minimal bandwidth per peer
5867 * @param v_n_min minimum number of connections
5868 * @param res result struct
5869 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5871 static int ats_solve_problem (int max_it, int max_dur , double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
5874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5875 return GNUNET_SYSERR;
5878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5890 int c_c_ressources = available_ressources;
5891 int c_q_metrics = available_quality_metrics;
5893 double M = VERY_BIG_DOUBLE_VALUE;
5894 double Q[c_q_metrics+1];
5895 for (c=1; c<=c_q_metrics; c++)
5900 struct NeighbourList *next = neighbours;
5903 struct ReadyList *r_next = next->plugins;
5904 while (r_next != NULL)
5906 struct ForeignAddressList * a_next = r_next->addresses;
5907 while (a_next != NULL)
5910 a_next = a_next->next;
5912 r_next = r_next->next;
5921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5923 return GNUNET_SYSERR;
5926 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5927 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5934 peers[c_peers].peer = next->id;
5935 peers[c_peers].m_head = NULL;
5936 peers[c_peers].m_tail = NULL;
5938 peers[c_peers].f = 1.0 / c_mechs;
5940 struct ReadyList *r_next = next->plugins;
5941 while (r_next != NULL)
5943 struct ForeignAddressList * a_next = r_next->addresses;
5944 while (a_next != NULL)
5946 mechanisms[c_mechs].addr = a_next;
5947 mechanisms[c_mechs].col_index = c_mechs;
5948 mechanisms[c_mechs].peer = &peers[c_peers];
5949 mechanisms[c_mechs].next = NULL;
5950 mechanisms[c_mechs].plugin = r_next->plugin;
5952 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5954 a_next = a_next->next;
5956 r_next = r_next->next;
5964 if (v_n_min > c_peers)
5968 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);
5971 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
5974 int * ia = GNUNET_malloc (size * sizeof (int));
5975 int * ja = GNUNET_malloc (size * sizeof (int));
5976 double * ar = GNUNET_malloc(size* sizeof (double));
5978 prob = glp_create_prob();
5979 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5980 glp_set_obj_dir(prob, GLP_MAX);
5982 /* adding columns */
5984 glp_add_cols(prob, 2 * c_mechs);
5985 /* adding b_t cols */
5986 for (c=1; c <= c_mechs; c++)
5989 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
5990 glp_set_col_name(prob, c, name);
5992 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5993 glp_set_obj_coef(prob, c, 1);
5996 /* adding n_t cols */
5997 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5999 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6000 glp_set_col_name(prob, c, name);
6002 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
6003 glp_set_col_kind(prob, c, GLP_IV);
6004 glp_set_obj_coef(prob, c, 0);
6007 /* feasibility constraints */
6008 /* Constraint 1: one address per peer*/
6010 glp_add_rows(prob, c_peers);
6011 for (c=1; c<=c_peers; c++)
6013 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
6015 struct ATS_mechanism *m = peers[c].m_head;
6018 ia[array_index] = row_index;
6019 ja[array_index] = (c_mechs + m->col_index);
6020 ar[array_index] = 1;
6022 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6030 /* Constraint 2: only active mechanism gets bandwidth assigned */
6031 glp_add_rows(prob, c_mechs);
6032 for (c=1; c<=c_mechs; c++)
6034 /* b_t - n_t * M <= 0 */
6036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6038 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6040 ia[array_index] = row_index;
6041 ja[array_index] = mechanisms[c].col_index;
6042 ar[array_index] = 1;
6044 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6047 ia[array_index] = row_index;
6048 ja[array_index] = c_mechs + mechanisms[c].col_index;
6049 ar[array_index] = -M;
6051 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6057 /* Constraint 3: minimum bandwidth*/
6058 glp_add_rows(prob, c_mechs);
6059 for (c=1; c<=c_mechs; c++)
6061 /* b_t - n_t * b_min <= 0 */
6063 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6065 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6067 ia[array_index] = row_index;
6068 ja[array_index] = mechanisms[c].col_index;
6069 ar[array_index] = 1;
6071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6074 ia[array_index] = row_index;
6075 ja[array_index] = c_mechs + mechanisms[c].col_index;
6076 ar[array_index] = -v_b_min;
6078 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6084 /* Constraint 4: max ressource capacity */
6085 /* V cr: bt * ct_r <= cr_maxsolution
6087 glp_add_rows(prob, available_ressources);
6088 double ct_max = VERY_BIG_DOUBLE_VALUE;
6089 double ct_min = 0.0;
6091 for (c=0; c<available_ressources; c++)
6093 ct_max = ressources[c].c_max;
6094 ct_min = ressources[c].c_min;
6096 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6098 glp_set_row_bnds(prob, row_index, GLP_DB, ct_min, ct_max);
6100 for (c2=1; c2<=c_mechs; c2++)
6103 ia[array_index] = row_index;
6104 ja[array_index] = c2;
6105 value = mechanisms[c2].addr->ressources[c].c;
6106 ar[array_index] = value;
6108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6115 /* Constraint 5: min number of connections*/
6116 glp_add_rows(prob, 1);
6117 for (c=1; c<=c_mechs; c++)
6119 // b_t - n_t * b_min >= 0
6121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6123 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
6125 ia[array_index] = row_index;
6126 ja[array_index] = c_mechs + mechanisms[c].col_index;
6127 ar[array_index] = 1;
6129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6135 /* optimisation constraints*/
6137 /* adding columns */
6138 glp_add_cols(prob, 3 + c_q_metrics);
6140 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
6141 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
6142 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6143 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
6144 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
6145 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6146 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
6147 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
6148 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6150 for (c=1; c<= c_q_metrics; c++)
6152 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6153 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
6154 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6156 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6159 // Constraint 6: optimize for diversity
6160 glp_add_rows(prob, 1);
6162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6164 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6165 for (c=1; c<=c_mechs; c++)
6167 // b_t - n_t * b_min >= 0
6168 ia[array_index] = row_index;
6169 ja[array_index] = c_mechs + mechanisms[c].col_index;
6170 ar[array_index] = 1;
6172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6176 ia[array_index] = row_index;
6177 ja[array_index] = (2*c_mechs) + 1;
6178 ar[array_index] = -1;
6180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6186 // Constraint 7: optimize for quality
6187 glp_add_rows(prob, available_quality_metrics);
6188 for (c=1; c <= c_q_metrics; c++)
6191 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6193 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6195 for (c2=1; c2<=c_mechs; c2++)
6198 ia[array_index] = row_index;
6199 ja[array_index] = c2;
6200 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6203 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6204 if (v1 < 1) v0 = 0.1;
6205 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6206 if (v1 < 1) v0 = 0.1;
6207 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6208 if (v1 < 1) v0 = 0.1;
6209 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6211 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6214 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6216 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6218 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6220 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6222 value = (double) 10 / value;
6226 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6228 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]);
6233 ia[array_index] = row_index;
6234 ja[array_index] = (2*c_mechs) + 3 +c;
6235 ar[array_index] = -1;
6237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6243 // Constraint 8: optimize bandwidth utility
6244 glp_add_rows(prob, 1);
6246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6248 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6249 for (c=1; c<=c_mechs; c++)
6251 ia[array_index] = row_index;
6252 ja[array_index] = c;
6253 ar[array_index] = mechanisms[c].peer->f;
6255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6259 ia[array_index] = row_index;
6260 ja[array_index] = (2*c_mechs) + 2;
6261 ar[array_index] = -1;
6263 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6269 // Constraint 9: optimize relativity
6270 glp_add_rows(prob, c_peers);
6271 for (c=1; c<=c_peers; c++)
6273 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6275 struct ATS_mechanism *m = peers[c].m_head;
6278 ia[array_index] = row_index;
6279 ja[array_index] = m->col_index;
6280 ar[array_index] = 1;
6282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6287 ia[array_index] = row_index;
6288 ja[array_index] = (2*c_mechs) + 3;
6289 ar[array_index] = -1;
6291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6297 /* Loading the matrix */
6298 glp_load_matrix(prob, array_index-1, ia, ja, ar);
6300 /* Solving simplex */
6302 glp_init_smcp(&opt_lp);
6305 opt_lp.msg_lev = GLP_MSG_ALL;
6307 opt_lp.msg_lev = GLP_MSG_OFF;
6309 opt_lp.presolve = GLP_ON;
6310 result = glp_simplex(prob, &opt_lp);
6311 solution = glp_get_status (prob);
6313 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
6317 glp_init_iocp(&opt_mlp);
6318 /* maximum duration */
6319 opt_mlp.tm_lim = max_dur;
6322 opt_mlp.msg_lev = GLP_MSG_ALL;
6324 opt_mlp.msg_lev = GLP_MSG_OFF;
6326 result = glp_intopt (prob, &opt_mlp);
6327 solution = glp_mip_status (prob);
6328 ats_evaluate_results(result, solution, "MLP");
6331 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
6334 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6335 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6336 glp_write_mip (prob, filename);
6337 GNUNET_free (filename);
6339 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
6342 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6343 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6344 glp_print_sol (prob, filename);
6345 GNUNET_free (filename);
6349 int error = GNUNET_NO;
6351 struct ATS_mechanism *t = NULL;
6352 for (c=1; c<= (c_peers); c++ )
6355 t = peers[c].m_head;
6358 bw = glp_get_col_prim(prob, t->col_index);
6362 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);
6364 if (check ==GNUNET_YES)
6366 glp_write_sol(prob, "invalid_solution.mlp");
6367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6368 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6371 if (check ==GNUNET_NO)
6379 for (c=1; c<= c_q_metrics; c++ )
6381 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));
6383 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));
6384 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));
6385 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));
6387 res->c_mechs = c_mechs;
6388 res->c_peers = c_peers;
6389 res->solution = solution;
6393 glp_delete_prob(prob);
6399 for (c=0; c<c_mechs; c++)
6400 GNUNET_free_non_null (mechanisms[c].rc);
6402 GNUNET_free(mechanisms);
6409 void ats_calculate_bandwidth_distribution ()
6411 struct GNUNET_TIME_Absolute start;
6412 struct GNUNET_TIME_Relative duration;
6413 struct ATS_result result;
6416 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6417 if (delta.rel_value < ats->min_delta.rel_value)
6420 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6426 if (INT_MAX < ats->max_exec_duration.rel_value)
6429 dur = (int) ats->max_exec_duration.rel_value;
6431 start = GNUNET_TIME_absolute_get();
6432 c_mechs = ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &result);
6433 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6438 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);
6440 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6441 GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6442 GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6443 GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6444 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6447 else if (c_mechs == 0)
6449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6452 ats->last = GNUNET_TIME_absolute_get();
6458 ats_schedule_calculation (void *cls,
6459 const struct GNUNET_SCHEDULER_TaskContext *tc)
6461 struct ATS_info *ats = (struct ATS_info *) cls;
6465 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6466 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6470 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6473 ats_calculate_bandwidth_distribution (ats);
6475 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6476 &ats_schedule_calculation, ats);
6481 ats = GNUNET_malloc(sizeof (struct ATS_info));
6483 ats->min_delta = ATS_MIN_INTERVAL;
6484 ats->exec_intervall = ATS_EXEC_INTERVAL;
6485 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6486 ats->max_iterations = ATS_MAX_ITERATIONS;
6487 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active");
6497 ats->v_b_min = 64000;
6501 unsigned long long value;
6503 /* loading cost ressources */
6504 for (c=0; c<available_ressources; c++)
6506 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6507 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6509 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6512 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6514 ressources[c].c_max = value;
6517 GNUNET_free (section);
6518 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6519 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6521 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6526 ressources[c].c_min = value;
6529 GNUNET_free (section);
6532 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6533 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6535 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6536 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6538 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6542 void ats_shutdown ()
6545 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6547 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6548 GNUNET_SCHEDULER_cancel(ats->ats_task);
6549 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6551 struct ATS_plugin * p;
6552 struct ATS_ressource_cost * rc;
6556 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6560 GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6564 GNUNET_free(p->short_name);
6573 void ats_notify_peer_connect (
6574 const struct GNUNET_PeerIdentity *peer,
6575 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6579 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6582 while (ntohl(ats_data[c].type)!=0)
6585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6589 ats_calculate_bandwidth_distribution(ats);
6592 void ats_notify_peer_disconnect (
6593 const struct GNUNET_PeerIdentity *peer)
6596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6598 ats_calculate_bandwidth_distribution (ats);
6602 void ats_notify_ats_data (
6603 const struct GNUNET_PeerIdentity *peer,
6604 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6607 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6609 ats_calculate_bandwidth_distribution(ats);
6612 struct ForeignAddressList * ats_get_preferred_address (
6613 struct NeighbourList *n)
6616 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6618 struct ReadyList *next = n->plugins;
6619 while (next != NULL)
6622 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6626 return find_ready_address(n);
6630 * Initiate transport service.
6632 * @param cls closure
6633 * @param server the initialized server
6634 * @param c configuration to use
6638 struct GNUNET_SERVER_Handle *server,
6639 const struct GNUNET_CONFIGURATION_Handle *c)
6641 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6642 {&handle_start, NULL,
6643 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6644 {&handle_hello, NULL,
6645 GNUNET_MESSAGE_TYPE_HELLO, 0},
6646 {&handle_send, NULL,
6647 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6648 {&handle_request_connect, NULL,
6649 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6650 {&handle_set_quota, NULL,
6651 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6652 {&handle_address_lookup, NULL,
6653 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6655 {&handle_blacklist_init, NULL,
6656 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6657 {&handle_blacklist_reply, NULL,
6658 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6664 unsigned long long tneigh;
6668 stats = GNUNET_STATISTICS_create ("transport", cfg);
6669 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6670 /* parse configuration */
6672 GNUNET_CONFIGURATION_get_value_number (c,
6677 GNUNET_CONFIGURATION_get_value_filename (c,
6679 "HOSTKEY", &keyfile)))
6681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6683 ("Transport service is lacking key configuration settings. Exiting.\n"));
6684 GNUNET_SCHEDULER_shutdown ();
6687 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6690 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6691 validation_map = NULL;
6695 max_connect_per_transport = (uint32_t) tneigh;
6696 peerinfo = GNUNET_PEERINFO_connect (cfg);
6697 if (peerinfo == NULL)
6699 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6700 _("Could not access PEERINFO service. Exiting.\n"));
6701 GNUNET_SCHEDULER_shutdown ();
6704 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6707 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6708 validation_map = NULL;
6709 GNUNET_free (keyfile);
6712 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6713 GNUNET_free (keyfile);
6714 if (my_private_key == NULL)
6716 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6718 ("Transport service could not access hostkey. Exiting.\n"));
6719 GNUNET_SCHEDULER_shutdown ();
6722 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6725 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6726 validation_map = NULL;
6729 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6730 GNUNET_CRYPTO_hash (&my_public_key,
6731 sizeof (my_public_key), &my_identity.hashPubKey);
6732 /* setup notification */
6733 GNUNET_SERVER_disconnect_notify (server,
6734 &client_disconnect_notification, NULL);
6735 /* load plugins... */
6738 GNUNET_CONFIGURATION_get_value_string (c,
6739 "TRANSPORT", "PLUGINS", &plugs))
6741 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6742 _("Starting transport plugins `%s'\n"), plugs);
6743 pos = strtok (plugs, " ");
6746 start_transport (server, pos);
6748 pos = strtok (NULL, " ");
6750 GNUNET_free (plugs);
6752 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6753 &shutdown_task, NULL);
6760 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6762 /* If we have a blacklist file, read from it */
6763 read_blacklist_file(cfg);
6764 /* process client requests */
6765 GNUNET_SERVER_add_handlers (server, handlers);
6770 * The main function for the transport service.
6772 * @param argc number of arguments from the command line
6773 * @param argv command line arguments
6774 * @return 0 ok, 1 on error
6777 main (int argc, char *const *argv)
6779 a2s (NULL, NULL, 0); /* make compiler happy */
6780 return (GNUNET_OK ==
6781 GNUNET_SERVICE_run (argc,
6784 GNUNET_SERVICE_OPTION_NONE,
6785 &run, NULL)) ? 0 : 1;
6788 /* end of gnunet-service-transport.c */