2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_ATS GNUNET_NO
53 #define VERBOSE_ATS GNUNET_NO
56 * Should we do some additional checks (to validate behavior
59 #define EXTRA_CHECKS GNUNET_YES
62 * How many messages can we have pending for a given client process
63 * before we start to drop incoming messages? We typically should
64 * have only one client and so this would be the primary buffer for
65 * messages, so the number should be chosen rather generously.
67 * The expectation here is that most of the time the queue is large
68 * enough so that a drop is virtually never required. Note that
69 * this value must be about as large as 'TOTAL_MSGS' in the
70 * 'test_transport_api_reliability.c', otherwise that testcase may
73 #define MAX_PENDING (128 * 1024)
76 * Size of the per-transport blacklist hash maps.
78 #define TRANSPORT_BLACKLIST_HT_SIZE 16
81 * How often should we try to reconnect to a peer using a particular
82 * transport plugin before giving up? Note that the plugin may be
83 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
85 #define MAX_CONNECT_RETRY 3
88 * Limit on the number of ready-to-run tasks when validating
89 * HELLOs. If more tasks are ready to run, we will drop
90 * HELLOs instead of validating them.
92 #define MAX_HELLO_LOAD 4
95 * How often must a peer violate bandwidth quotas before we start
96 * to simply drop its messages?
98 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
101 * How long until a HELLO verification attempt should time out?
102 * Must be rather small, otherwise a partially successful HELLO
103 * validation (some addresses working) might not be available
104 * before a client's request for a connection fails for good.
105 * Besides, if a single request to an address takes a long time,
106 * then the peer is unlikely worthwhile anyway.
108 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
111 * How long is a PONG signature valid? We'll recycle a signature until
112 * 1/4 of this time is remaining. PONGs should expire so that if our
113 * external addresses change an adversary cannot replay them indefinitely.
114 * OTOH, we don't want to spend too much time generating PONG signatures,
115 * so they must have some lifetime to reduce our CPU usage.
117 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
120 * Priority to use for PONG messages.
122 #define TRANSPORT_PONG_PRIORITY 4
125 * How often do we re-add (cheaper) plugins to our list of plugins
126 * to try for a given connected peer?
128 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
131 * After how long do we expire an address in a HELLO that we just
132 * validated? This value is also used for our own addresses when we
135 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
139 * How long before an existing address expires should we again try to
140 * validate it? Must be (significantly) smaller than
141 * HELLO_ADDRESS_EXPIRATION.
143 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
146 * Maximum frequency for re-evaluating latencies for all transport addresses.
148 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
151 * Maximum frequency for re-evaluating latencies for connected addresses.
153 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
155 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
158 * List of addresses of other peers
160 struct ForeignAddressList
163 * This is a linked list.
165 struct ForeignAddressList *next;
168 * Which ready list does this entry belong to.
170 struct ReadyList *ready_list;
173 * How long until we auto-expire this address (unless it is
174 * re-confirmed by the transport)?
176 struct GNUNET_TIME_Absolute expires;
179 * Task used to re-validate addresses, updates latencies and
182 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
190 * Session (or NULL if no valid session currently exists or if the
191 * plugin does not use sessions).
193 struct Session *session;
195 struct ATS_ressource_entry * ressources;
197 struct ATS_quality_entry * quality;
200 * What was the last latency observed for this address, plugin and peer?
202 struct GNUNET_TIME_Relative latency;
205 * If we did not successfully transmit a message to the given peer
206 * via this connection during the specified time, we should consider
207 * the connection to be dead. This is used in the case that a TCP
208 * transport simply stalls writing to the stream but does not
209 * formerly get a signal that the other peer died.
211 struct GNUNET_TIME_Absolute timeout;
214 * How often have we tried to connect using this plugin? Used to
215 * discriminate against addresses that do not work well.
216 * FIXME: not yet used, but should be!
218 unsigned int connect_attempts;
221 * DV distance to this peer (1 if no DV is used).
222 * FIXME: need to set this from transport plugins!
232 * Have we ever estimated the latency of this address? Used to
233 * ensure that the first time we add an address, we immediately
239 * Are we currently connected via this address? The first time we
240 * successfully transmit or receive data to a peer via a particular
241 * address, we set this to GNUNET_YES. If we later get an error
242 * (disconnect notification, transmission failure, timeout), we set
243 * it back to GNUNET_NO.
248 * Is this plugin currently busy transmitting to the specific target?
249 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
250 * messages do not count as 'in transmit'.
255 * Has this address been validated yet?
263 * Entry in linked list of network addresses for ourselves. Also
264 * includes a cached signature for 'struct TransportPongMessage's.
266 struct OwnAddressList
269 * This is a linked list.
271 struct OwnAddressList *next;
274 * How long until we actually auto-expire this address (unless it is
275 * re-confirmed by the transport)?
277 struct GNUNET_TIME_Absolute expires;
280 * How long until the current signature expires? (ZERO if the
281 * signature was never created).
283 struct GNUNET_TIME_Absolute pong_sig_expires;
286 * Signature for a 'struct TransportPongMessage' for this address.
288 struct GNUNET_CRYPTO_RsaSignature pong_signature;
299 * Entry in linked list of all of our plugins.
301 struct TransportPlugin
305 * This is a linked list.
307 struct TransportPlugin *next;
310 * API of the transport as returned by the plugin's
311 * initialization function.
313 struct GNUNET_TRANSPORT_PluginFunctions *api;
316 * Short name for the plugin (i.e. "tcp").
321 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
326 * List of our known addresses for this transport.
328 struct OwnAddressList *addresses;
331 * Environment this transport service is using
334 struct GNUNET_TRANSPORT_PluginEnvironment env;
337 * ID of task that is used to clean up expired addresses.
339 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
342 * Set to GNUNET_YES if we need to scrap the existing list of
343 * "addresses" and start fresh when we receive the next address
344 * update from a transport. Set to GNUNET_NO if we should just add
345 * the new address to the list and wait for the commit call.
349 struct ATS_plugin * rc;
352 * Hashmap of blacklisted peers for this particular transport.
354 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
357 struct NeighbourList;
360 * For each neighbour we keep a list of messages
361 * that we still want to transmit to the neighbour.
367 * This is a doubly linked list.
369 struct MessageQueue *next;
372 * This is a doubly linked list.
374 struct MessageQueue *prev;
377 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
378 * stuck together in memory. Allocated at the end of this struct.
380 const char *message_buf;
383 * Size of the message buf
385 size_t message_buf_size;
388 * Client responsible for queueing the message;
389 * used to check that a client has no two messages
390 * pending for the same target. Can be NULL.
392 struct TransportClient *client;
395 * Using which specific address should we send this message?
397 struct ForeignAddressList *specific_address;
400 * Peer ID of the Neighbour this entry belongs to.
402 struct GNUNET_PeerIdentity neighbour_id;
405 * Plugin that we used for the transmission.
406 * NULL until we scheduled a transmission.
408 struct TransportPlugin *plugin;
411 * At what time should we fail?
413 struct GNUNET_TIME_Absolute timeout;
416 * Internal message of the transport system that should not be
417 * included in the usual SEND-SEND_OK transmission confirmation
418 * traffic management scheme. Typically, "internal_msg" will
419 * be set whenever "client" is NULL (but it is not strictly
425 * How important is the message?
427 unsigned int priority;
433 * For a given Neighbour, which plugins are available
434 * to talk to this peer and what are their costs?
439 * This is a linked list.
441 struct ReadyList *next;
444 * Which of our transport plugins does this entry
447 struct TransportPlugin *plugin;
450 * Transport addresses, latency, and readiness for
451 * this particular plugin.
453 struct ForeignAddressList *addresses;
456 * To which neighbour does this ready list belong to?
458 struct NeighbourList *neighbour;
463 * Entry in linked list of all of our current neighbours.
469 * This is a linked list.
471 struct NeighbourList *next;
474 * Which of our transports is connected to this peer
475 * and what is their status?
477 struct ReadyList *plugins;
480 * Head of list of messages we would like to send to this peer;
481 * must contain at most one message per client.
483 struct MessageQueue *messages_head;
486 * Tail of list of messages we would like to send to this peer; must
487 * contain at most one message per client.
489 struct MessageQueue *messages_tail;
492 * Buffer for at most one payload message used when we receive
493 * payload data before our PING-PONG has succeeded. We then
494 * store such messages in this intermediary buffer until the
495 * connection is fully up.
497 struct GNUNET_MessageHeader *pre_connect_message_buffer;
500 * Context for peerinfo iteration.
501 * NULL after we are done processing peerinfo's information.
503 struct GNUNET_PEERINFO_IteratorContext *piter;
506 * Public key for this peer. Valid only if the respective flag is set below.
508 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
511 * Identity of this neighbour.
513 struct GNUNET_PeerIdentity id;
516 * ID of task scheduled to run when this peer is about to
517 * time out (will free resources associated with the peer).
519 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
522 * ID of task scheduled to run when we should retry transmitting
523 * the head of the message queue. Actually triggered when the
524 * transmission is timing out (we trigger instantly when we have
525 * a chance of success).
527 GNUNET_SCHEDULER_TaskIdentifier retry_task;
530 * How long until we should consider this peer dead
531 * (if we don't receive another message in the
534 struct GNUNET_TIME_Absolute peer_timeout;
537 * Tracker for inbound bandwidth.
539 struct GNUNET_BANDWIDTH_Tracker in_tracker;
542 * The latency we have seen for this particular address for
543 * this particular peer. This latency may have been calculated
544 * over multiple transports. This value reflects how long it took
545 * us to receive a response when SENDING via this particular
546 * transport/neighbour/address combination!
548 * FIXME: we need to periodically send PINGs to update this
549 * latency (at least more often than the current "huge" (11h?)
552 struct GNUNET_TIME_Relative latency;
555 * How often has the other peer (recently) violated the
556 * inbound traffic limit? Incremented by 10 per violation,
557 * decremented by 1 per non-violation (for each
560 unsigned int quota_violation_count;
563 * DV distance to this peer (1 if no DV is used).
568 * Have we seen an PONG from this neighbour in the past (and
569 * not had a disconnect since)?
574 * Do we have a valid public key for this neighbour?
576 int public_key_valid;
579 * Performance data for the peer.
581 struct GNUNET_TRANSPORT_ATS_Information *ats;
584 * Identity of the neighbour.
586 struct GNUNET_PeerIdentity peer;
591 * Message used to ask a peer to validate receipt (to check an address
592 * from a HELLO). Followed by the address we are trying to validate,
593 * or an empty address if we are just sending a PING to confirm that a
594 * connection which the receiver (of the PING) initiated is still valid.
596 struct TransportPingMessage
600 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
602 struct GNUNET_MessageHeader header;
605 * Challenge code (to ensure fresh reply).
607 uint32_t challenge GNUNET_PACKED;
610 * Who is the intended recipient?
612 struct GNUNET_PeerIdentity target;
618 * Message used to validate a HELLO. The challenge is included in the
619 * confirmation to make matching of replies to requests possible. The
620 * signature signs our public key, an expiration time and our address.<p>
622 * This message is followed by our transport address that the PING tried
623 * to confirm (if we liked it). The address can be empty (zero bytes)
624 * if the PING had not address either (and we received the request via
625 * a connection that we initiated).
627 struct TransportPongMessage
631 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
633 struct GNUNET_MessageHeader header;
636 * Challenge code from PING (showing freshness). Not part of what
637 * is signed so that we can re-use signatures.
639 uint32_t challenge GNUNET_PACKED;
644 struct GNUNET_CRYPTO_RsaSignature signature;
647 * What are we signing and why? Two possible reason codes can be here:
648 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
649 * plausible address for this peer (pid is set to identity of signer); or
650 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
651 * an address we used to connect to the peer with the given pid.
653 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
656 * When does this signature expire?
658 struct GNUNET_TIME_AbsoluteNBO expiration;
661 * Either the identity of the peer Who signed this message, or the
662 * identity of the peer that we're connected to using the given
663 * address (depending on purpose.type).
665 struct GNUNET_PeerIdentity pid;
668 * Size of address appended to this message (part of what is
669 * being signed, hence not redundant).
677 * Linked list of messages to be transmitted to the client. Each
678 * entry is followed by the actual message.
680 struct ClientMessageQueueEntry
683 * This is a doubly-linked list.
685 struct ClientMessageQueueEntry *next;
688 * This is a doubly-linked list.
690 struct ClientMessageQueueEntry *prev;
695 * Client connected to the transport service.
697 struct TransportClient
701 * This is a linked list.
703 struct TransportClient *next;
706 * Handle to the client.
708 struct GNUNET_SERVER_Client *client;
711 * Linked list of messages yet to be transmitted to
714 struct ClientMessageQueueEntry *message_queue_head;
717 * Tail of linked list of messages yet to be transmitted to the
720 struct ClientMessageQueueEntry *message_queue_tail;
723 * Current transmit request handle.
725 struct GNUNET_CONNECTION_TransmitHandle *th;
728 * Is a call to "transmit_send_continuation" pending? If so, we
729 * must not free this struct (even if the corresponding client
730 * disconnects) and instead only remove it from the linked list and
731 * set the "client" field to NULL.
736 * Length of the list of messages pending for this client.
738 unsigned int message_count;
744 * Context of currently active requests to peerinfo
745 * for validation of HELLOs.
747 struct CheckHelloValidatedContext;
751 * Entry in map of all HELLOs awaiting validation.
753 struct ValidationEntry
757 * NULL if this entry is not part of a larger HELLO validation.
759 struct CheckHelloValidatedContext *chvc;
762 * The address, actually a pointer to the end
763 * of this struct. Do not free!
768 * Name of the transport.
770 char *transport_name;
773 * The public key of the peer.
775 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
778 * ID of task that will clean up this entry if we don't succeed
779 * with the validation first.
781 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
784 * At what time did we send this validation?
786 struct GNUNET_TIME_Absolute send_time;
789 * Session being validated (or NULL for none).
791 struct Session *session;
794 * Challenge number we used.
807 * Context of currently active requests to peerinfo
808 * for validation of HELLOs.
810 struct CheckHelloValidatedContext
814 * This is a doubly-linked list.
816 struct CheckHelloValidatedContext *next;
819 * This is a doubly-linked list.
821 struct CheckHelloValidatedContext *prev;
824 * Hello that we are validating.
826 const struct GNUNET_HELLO_Message *hello;
829 * Context for peerinfo iteration.
830 * NULL after we are done processing peerinfo's information.
832 struct GNUNET_PEERINFO_IteratorContext *piter;
835 * Was a HELLO known for this peer to peerinfo?
840 * Number of validation entries currently referring to this
843 unsigned int ve_count;
846 struct ATS_quality_metric
855 struct ATS_mechanism * prev;
856 struct ATS_mechanism * next;
857 struct ForeignAddressList * addr;
858 struct TransportPlugin * plugin;
859 struct ATS_peer * peer;
862 struct ATS_ressource_cost * rc;
868 struct GNUNET_PeerIdentity peer;
869 struct NeighbourList * n;
870 struct ATS_mechanism * m_head;
871 struct ATS_mechanism * m_tail;
873 /* preference value f */
893 struct ATS_ressource_entry
895 /* index in ressources array */
897 /* depending ATSi parameter to calculcate limits */
906 /* index in ressources array */
908 /* depending ATSi parameter to calculcate limits */
910 /* cfg option to load limits */
917 /* cofficients for the specific plugins */
927 static struct ATS_ressource ressources[] =
929 /* FIXME: the coefficients for the specific plugins */
930 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
931 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
932 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
934 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
935 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
936 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
937 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
940 static int available_ressources = 3;
948 * Time of last execution
950 struct GNUNET_TIME_Absolute last;
952 * Minimum intervall between two executions
954 struct GNUNET_TIME_Relative min_delta;
956 * Regular intervall when execution is triggered
958 struct GNUNET_TIME_Relative exec_intervall;
960 * Maximum execution time per calculation
962 struct GNUNET_TIME_Relative max_exec_duration;
964 * Maximum number of LP iterations per calculation
972 * Ressource costs or quality metrics changed, update matrix
974 int modified_resources;
977 * Ressource costs or quality metrics changed, update matrix
979 int modified_quality;
982 * Peers have connected or disconnected, problem has to be recreated
992 GNUNET_SCHEDULER_TaskIdentifier ats_task;
994 struct ATS_result res;
1002 * Our HELLO message.
1004 static struct GNUNET_HELLO_Message *our_hello;
1009 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
1014 static struct GNUNET_PeerIdentity my_identity;
1019 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
1022 * Our configuration.
1024 const struct GNUNET_CONFIGURATION_Handle *cfg;
1027 * Linked list of all clients to this service.
1029 static struct TransportClient *clients;
1032 * All loaded plugins.
1034 static struct TransportPlugin *plugins;
1037 * Handle to peerinfo service.
1039 static struct GNUNET_PEERINFO_Handle *peerinfo;
1042 * All known neighbours and their HELLOs.
1044 static struct NeighbourList *neighbours;
1047 * Number of neighbours we'd like to have.
1049 static uint32_t max_connect_per_transport;
1052 * Head of linked list.
1054 static struct CheckHelloValidatedContext *chvc_head;
1057 * Tail of linked list.
1059 static struct CheckHelloValidatedContext *chvc_tail;
1062 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1063 * of the given peer that we are currently validating).
1065 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1068 * Handle for reporting statistics.
1070 static struct GNUNET_STATISTICS_Handle *stats;
1073 * Handle for ats information
1075 static struct ATS_info *ats;
1077 struct ATS_quality_entry
1085 static struct ATS_quality_metric qm[] =
1087 {1, 1028, "QUALITY_NET_DISTANCE"},
1088 {2, 1034, "QUALITY_NET_DELAY"},
1090 static int available_quality_metrics = 2;
1094 * The peer specified by the given neighbour has timed-out or a plugin
1095 * has disconnected. We may either need to do nothing (other plugins
1096 * still up), or trigger a full disconnect and clean up. This
1097 * function updates our state and do the necessary notifications.
1098 * Also notifies our clients that the neighbour is now officially
1101 * @param n the neighbour list entry for the peer
1102 * @param check should we just check if all plugins
1103 * disconnected or must we ask all plugins to
1106 static void disconnect_neighbour (struct NeighbourList *n, int check);
1109 * Check the ready list for the given neighbour and if a plugin is
1110 * ready for transmission (and if we have a message), do so!
1112 * @param nexi target peer for which to transmit
1114 static void try_transmission_to_peer (struct NeighbourList *n);
1117 static void ats_init ();
1119 static void ats_shutdown ( );
1121 static void ats_notify_peer_connect (
1122 const struct GNUNET_PeerIdentity *peer,
1123 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1125 static void ats_notify_peer_disconnect (
1126 const struct GNUNET_PeerIdentity *peer);
1128 static void ats_notify_ats_data (
1129 const struct GNUNET_PeerIdentity *peer,
1130 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1132 struct ForeignAddressList * ats_get_preferred_address (
1133 struct NeighbourList *n);
1136 * Find an entry in the neighbour list for a particular peer.
1138 * @return NULL if not found.
1140 static struct NeighbourList *
1141 find_neighbour (const struct GNUNET_PeerIdentity *key)
1143 struct NeighbourList *head = neighbours;
1145 while ((head != NULL) &&
1146 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1151 static void update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1154 for (c1=0; c1<ats_count; c1++)
1156 for (c2=0; c2<available_quality_metrics; c2++)
1158 if (ntohl(ats_data[c1].type) == qm[c2].atis_index)
1160 fal->quality[c2].values[0] = fal->quality[c2].values[1];
1161 fal->quality[c2].values[1] = fal->quality[c2].values[2];
1162 fal->quality[c2].values[2] = ntohl(ats_data[c1].value);
1168 static void update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1171 for (c=0; c<available_quality_metrics; c++)
1173 if (ats_index == qm[c].atis_index)
1175 fal->quality[c].values[0] = fal->quality[c].values[1];
1176 fal->quality[c].values[1] = fal->quality[c].values[2];
1177 fal->quality[c].values[2] = value;
1183 * Find an entry in the transport list for a particular transport.
1185 * @return NULL if not found.
1187 static struct TransportPlugin *
1188 find_transport (const char *short_name)
1190 struct TransportPlugin *head = plugins;
1191 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1197 * Is a particular peer blacklisted for a particular transport?
1199 * @param peer the peer to check for
1200 * @param plugin the plugin used to connect to the peer
1202 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1205 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1208 if (plugin->blacklist != NULL)
1210 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214 "Peer `%s:%s' is blacklisted!\n",
1215 plugin->short_name, GNUNET_i2s (peer));
1218 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1228 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1230 struct TransportPlugin *plugin;
1232 plugin = find_transport(transport_name);
1233 if (plugin == NULL) /* Nothing to do */
1235 if (plugin->blacklist == NULL)
1236 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1237 GNUNET_assert(plugin->blacklist != NULL);
1238 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1240 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1245 * Read the blacklist file, containing transport:peer entries.
1246 * Provided the transport is loaded, set up hashmap with these
1247 * entries to blacklist peers by transport.
1251 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1258 struct GNUNET_PeerIdentity pid;
1260 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1261 unsigned int entries_found;
1262 char *transport_name;
1265 GNUNET_CONFIGURATION_get_value_filename (cfg,
1271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1272 "Option `%s' in section `%s' not specified!\n",
1278 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1279 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1280 | GNUNET_DISK_PERM_USER_WRITE);
1281 if (0 != STAT (fn, &frstat))
1283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1284 _("Could not read blacklist file `%s'\n"), fn);
1288 if (frstat.st_size == 0)
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1292 _("Blacklist file `%s' is empty.\n"),
1298 /* FIXME: use mmap */
1299 data = GNUNET_malloc_large (frstat.st_size);
1300 GNUNET_assert(data != NULL);
1301 if (frstat.st_size !=
1302 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1304 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1305 _("Failed to read blacklist from `%s'\n"), fn);
1312 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1314 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1315 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1318 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1321 if (colon_pos >= frstat.st_size)
1323 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1324 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1325 (unsigned long long) colon_pos);
1331 if (isspace( (unsigned char) data[colon_pos]))
1333 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1334 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1335 (unsigned long long) colon_pos);
1337 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1341 tsize = colon_pos - pos;
1342 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1344 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1345 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1346 (unsigned long long) colon_pos);
1355 transport_name = GNUNET_malloc(tsize + 1);
1356 memcpy(transport_name, &data[pos], tsize);
1357 pos = colon_pos + 1;
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1360 "Read transport name %s in blacklist file.\n",
1363 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1364 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1366 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1367 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1368 (unsigned long long) pos);
1370 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1372 GNUNET_free_non_null(transport_name);
1375 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1376 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1378 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1379 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1380 (unsigned long long) pos,
1385 if (0 != memcmp (&pid,
1387 sizeof (struct GNUNET_PeerIdentity)))
1390 add_peer_to_blacklist (&pid,
1395 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1396 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1400 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1401 GNUNET_free_non_null(transport_name);
1402 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1405 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1412 * Function called to notify a client about the socket being ready to
1413 * queue more data. "buf" will be NULL and "size" zero if the socket
1414 * was closed for writing in the meantime.
1416 * @param cls closure
1417 * @param size number of bytes available in buf
1418 * @param buf where the callee should write the message
1419 * @return number of bytes written to buf
1422 transmit_to_client_callback (void *cls, size_t size, void *buf)
1424 struct TransportClient *client = cls;
1425 struct ClientMessageQueueEntry *q;
1428 const struct GNUNET_MessageHeader *msg;
1435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1436 "Transmission to client failed, closing connection.\n");
1438 /* fatal error with client, free message queue! */
1439 while (NULL != (q = client->message_queue_head))
1441 GNUNET_STATISTICS_update (stats,
1442 gettext_noop ("# bytes discarded (could not transmit to client)"),
1443 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1445 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1446 client->message_queue_tail,
1450 client->message_count = 0;
1455 while (NULL != (q = client->message_queue_head))
1457 msg = (const struct GNUNET_MessageHeader *) &q[1];
1458 msize = ntohs (msg->size);
1459 if (msize + tsize > size)
1462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463 "Transmitting message of type %u to client.\n",
1466 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1467 client->message_queue_tail,
1469 memcpy (&cbuf[tsize], msg, msize);
1472 client->message_count--;
1476 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1477 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1479 GNUNET_TIME_UNIT_FOREVER_REL,
1480 &transmit_to_client_callback,
1482 GNUNET_assert (client->th != NULL);
1489 * Convert an address to a string.
1491 * @param plugin name of the plugin responsible for the address
1492 * @param addr binary address
1493 * @param addr_len number of bytes in addr
1494 * @return NULL on error, otherwise address string
1497 a2s (const char *plugin,
1501 struct TransportPlugin *p;
1505 p = find_transport (plugin);
1508 return p->api->address_to_string (p->api->cls,
1515 * Mark the given FAL entry as 'connected' (and hence preferred for
1516 * sending); also mark all others for the same peer as 'not connected'
1517 * (since only one can be preferred).
1519 * @param fal address to set to 'connected'
1522 mark_address_connected (struct ForeignAddressList *fal)
1524 struct ForeignAddressList *pos;
1527 GNUNET_assert (GNUNET_YES == fal->validated);
1528 if (fal->connected == GNUNET_YES)
1529 return; /* nothing to do */
1531 pos = fal->ready_list->addresses;
1534 if (GNUNET_YES == pos->connected)
1537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1538 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1539 a2s (pos->ready_list->plugin->short_name,
1543 GNUNET_break (cnt == GNUNET_YES);
1545 pos->connected = GNUNET_NO;
1546 GNUNET_STATISTICS_update (stats,
1547 gettext_noop ("# connected addresses"),
1553 fal->connected = GNUNET_YES;
1554 if (GNUNET_YES == cnt)
1556 GNUNET_STATISTICS_update (stats,
1557 gettext_noop ("# connected addresses"),
1565 * Send the specified message to the specified client. Since multiple
1566 * messages may be pending for the same client at a time, this code
1567 * makes sure that no message is lost.
1569 * @param client client to transmit the message to
1570 * @param msg the message to send
1571 * @param may_drop can this message be dropped if the
1572 * message queue for this client is getting far too large?
1575 transmit_to_client (struct TransportClient *client,
1576 const struct GNUNET_MessageHeader *msg, int may_drop)
1578 struct ClientMessageQueueEntry *q;
1581 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1583 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1585 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1588 client->message_count,
1590 GNUNET_STATISTICS_update (stats,
1591 gettext_noop ("# messages dropped due to slow client"),
1596 msize = ntohs (msg->size);
1597 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1598 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1599 memcpy (&q[1], msg, msize);
1600 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1601 client->message_queue_tail,
1602 client->message_queue_tail,
1604 client->message_count++;
1605 if (client->th == NULL)
1607 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1609 GNUNET_TIME_UNIT_FOREVER_REL,
1610 &transmit_to_client_callback,
1612 GNUNET_assert (client->th != NULL);
1618 * Transmit a 'SEND_OK' notification to the given client for the
1621 * @param client who to notify
1622 * @param n neighbour to notify about, can be NULL (on failure)
1623 * @param target target of the transmission
1624 * @param result status code for the transmission request
1627 transmit_send_ok (struct TransportClient *client,
1628 struct NeighbourList *n,
1629 const struct GNUNET_PeerIdentity *target,
1632 struct SendOkMessage send_ok_msg;
1634 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1635 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1636 send_ok_msg.success = htonl (result);
1638 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1640 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1641 send_ok_msg.peer = *target;
1642 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1647 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1648 * upon "completion" of a send request. This tells the API
1649 * that it is now legal to send another message to the given
1652 * @param cls closure, identifies the entry on the
1653 * message queue that was transmitted and the
1654 * client responsible for queuing the message
1655 * @param target the peer receiving the message
1656 * @param result GNUNET_OK on success, if the transmission
1657 * failed, we should not tell the client to transmit
1661 transmit_send_continuation (void *cls,
1662 const struct GNUNET_PeerIdentity *target,
1665 struct MessageQueue *mq = cls;
1666 struct NeighbourList *n;
1668 GNUNET_STATISTICS_update (stats,
1669 gettext_noop ("# bytes pending with plugins"),
1670 - (int64_t) mq->message_buf_size,
1672 if (result == GNUNET_OK)
1674 GNUNET_STATISTICS_update (stats,
1675 gettext_noop ("# bytes successfully transmitted by plugins"),
1676 mq->message_buf_size,
1681 GNUNET_STATISTICS_update (stats,
1682 gettext_noop ("# bytes with transmission failure by plugins"),
1683 mq->message_buf_size,
1686 if (mq->specific_address != NULL)
1688 if (result == GNUNET_OK)
1690 mq->specific_address->timeout =
1691 GNUNET_TIME_relative_to_absolute
1692 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1693 if (mq->specific_address->validated == GNUNET_YES)
1694 mark_address_connected (mq->specific_address);
1698 if (mq->specific_address->connected != GNUNET_NO)
1701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1703 a2s (mq->specific_address->ready_list->plugin->short_name,
1704 mq->specific_address->addr,
1705 mq->specific_address->addrlen));
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# connected addresses"),
1711 mq->specific_address->connected = GNUNET_NO;
1714 if (! mq->internal_msg)
1715 mq->specific_address->in_transmit = GNUNET_NO;
1717 n = find_neighbour(&mq->neighbour_id);
1718 if (mq->client != NULL)
1719 transmit_send_ok (mq->client, n, target, result);
1722 try_transmission_to_peer (n);
1727 * Find an address in any of the available transports for
1728 * the given neighbour that would be good for message
1729 * transmission. This is essentially the transport selection
1732 * @param neighbour for whom to select an address
1733 * @return selected address, NULL if we have none
1735 struct ForeignAddressList *
1736 find_ready_address(struct NeighbourList *neighbour)
1738 struct ReadyList *head = neighbour->plugins;
1739 struct ForeignAddressList *addresses;
1740 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1741 struct ForeignAddressList *best_address;
1743 /* Hack to prefer unix domain sockets */
1744 struct ForeignAddressList *unix_address = NULL;
1746 best_address = NULL;
1747 while (head != NULL)
1749 addresses = head->addresses;
1750 while (addresses != NULL)
1752 if ( (addresses->timeout.abs_value < now.abs_value) &&
1753 (addresses->connected == GNUNET_YES) )
1756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1757 "Marking long-time inactive connection to `%4s' as down.\n",
1758 GNUNET_i2s (&neighbour->id));
1760 GNUNET_STATISTICS_update (stats,
1761 gettext_noop ("# connected addresses"),
1764 addresses->connected = GNUNET_NO;
1766 addresses = addresses->next;
1769 addresses = head->addresses;
1770 while (addresses != NULL)
1772 #if DEBUG_TRANSPORT > 1
1773 if (addresses->addr != NULL)
1774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1775 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1776 a2s (head->plugin->short_name,
1778 addresses->addrlen),
1779 GNUNET_i2s (&neighbour->id),
1780 addresses->connected,
1781 addresses->in_transmit,
1782 addresses->validated,
1783 addresses->connect_attempts,
1784 (unsigned long long) addresses->timeout.abs_value,
1785 (unsigned int) addresses->distance);
1787 if (0==strcmp(head->plugin->short_name,"unix"))
1789 if ((unix_address == NULL) || ((unix_address != NULL) &&
1790 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1791 unix_address = addresses;
1793 if ( ( (best_address == NULL) ||
1794 (addresses->connected == GNUNET_YES) ||
1795 (best_address->connected == GNUNET_NO) ) &&
1796 (addresses->in_transmit == GNUNET_NO) &&
1797 ( (best_address == NULL) ||
1798 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1799 best_address = addresses;
1800 /* FIXME: also give lower-latency addresses that are not
1801 connected a chance some times... */
1802 addresses = addresses->next;
1804 if (unix_address != NULL)
1808 if (unix_address != NULL)
1810 best_address = unix_address;
1812 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1815 if (best_address != NULL)
1819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1820 "Best address found (`%s') has latency of %llu ms.\n",
1821 (best_address->addrlen > 0)
1822 ? a2s (best_address->ready_list->plugin->short_name,
1824 best_address->addrlen)
1826 best_address->latency.rel_value);
1831 GNUNET_STATISTICS_update (stats,
1832 gettext_noop ("# transmission attempts failed (no address)"),
1837 return best_address;
1843 * We should re-try transmitting to the given peer,
1844 * hopefully we've learned something in the meantime.
1847 retry_transmission_task (void *cls,
1848 const struct GNUNET_SCHEDULER_TaskContext *tc)
1850 struct NeighbourList *n = cls;
1852 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1853 try_transmission_to_peer (n);
1858 * Check the ready list for the given neighbour and if a plugin is
1859 * ready for transmission (and if we have a message), do so!
1861 * @param neighbour target peer for which to transmit
1864 try_transmission_to_peer (struct NeighbourList *n)
1866 struct ReadyList *rl;
1867 struct MessageQueue *mq;
1868 struct GNUNET_TIME_Relative timeout;
1872 if (n->messages_head == NULL)
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Transmission queue for `%4s' is empty\n",
1877 GNUNET_i2s (&n->id));
1879 return; /* nothing to do */
1882 mq = n->messages_head;
1883 force_address = GNUNET_YES;
1884 if (mq->specific_address == NULL)
1887 mq->specific_address = ats_get_preferred_address(n);
1888 GNUNET_STATISTICS_update (stats,
1889 gettext_noop ("# transport selected peer address freely"),
1892 force_address = GNUNET_NO;
1894 if (mq->specific_address == NULL)
1896 GNUNET_STATISTICS_update (stats,
1897 gettext_noop ("# transport failed to selected peer address"),
1900 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1901 if (timeout.rel_value == 0)
1904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1905 "No destination address available to transmit message of size %u to peer `%4s'\n",
1906 mq->message_buf_size,
1907 GNUNET_i2s (&mq->neighbour_id));
1909 GNUNET_STATISTICS_update (stats,
1910 gettext_noop ("# bytes in message queue for other peers"),
1911 - (int64_t) mq->message_buf_size,
1913 GNUNET_STATISTICS_update (stats,
1914 gettext_noop ("# bytes discarded (no destination address available)"),
1915 mq->message_buf_size,
1917 if (mq->client != NULL)
1918 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1919 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1923 return; /* nobody ready */
1925 GNUNET_STATISTICS_update (stats,
1926 gettext_noop ("# message delivery deferred (no address)"),
1929 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1930 GNUNET_SCHEDULER_cancel (n->retry_task);
1931 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1932 &retry_transmission_task,
1935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1936 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1937 mq->message_buf_size,
1938 GNUNET_i2s (&mq->neighbour_id),
1941 /* FIXME: might want to trigger peerinfo lookup here
1942 (unless that's already pending...) */
1945 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1948 if (mq->specific_address->connected == GNUNET_NO)
1949 mq->specific_address->connect_attempts++;
1950 rl = mq->specific_address->ready_list;
1951 mq->plugin = rl->plugin;
1952 if (!mq->internal_msg)
1953 mq->specific_address->in_transmit = GNUNET_YES;
1955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1956 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1957 mq->message_buf_size,
1958 GNUNET_i2s (&n->id),
1959 (mq->specific_address->addr != NULL)
1960 ? a2s (mq->plugin->short_name,
1961 mq->specific_address->addr,
1962 mq->specific_address->addrlen)
1964 rl->plugin->short_name);
1966 GNUNET_STATISTICS_update (stats,
1967 gettext_noop ("# bytes in message queue for other peers"),
1968 - (int64_t) mq->message_buf_size,
1970 GNUNET_STATISTICS_update (stats,
1971 gettext_noop ("# bytes pending with plugins"),
1972 mq->message_buf_size,
1974 ret = rl->plugin->api->send (rl->plugin->api->cls,
1977 mq->message_buf_size,
1979 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1980 mq->specific_address->session,
1981 mq->specific_address->addr,
1982 mq->specific_address->addrlen,
1984 &transmit_send_continuation, mq);
1987 /* failure, but 'send' would not call continuation in this case,
1988 so we need to do it here! */
1989 transmit_send_continuation (mq,
1997 * Send the specified message to the specified peer.
1999 * @param client source of the transmission request (can be NULL)
2000 * @param peer_address ForeignAddressList where we should send this message
2001 * @param priority how important is the message
2002 * @param timeout how long do we have to transmit?
2003 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
2004 * @param message_buf_size total size of all messages in message_buf
2005 * @param is_internal is this an internal message; these are pre-pended and
2006 * also do not count for plugins being "ready" to transmit
2007 * @param neighbour handle to the neighbour for transmission
2010 transmit_to_peer (struct TransportClient *client,
2011 struct ForeignAddressList *peer_address,
2012 unsigned int priority,
2013 struct GNUNET_TIME_Relative timeout,
2014 const char *message_buf,
2015 size_t message_buf_size,
2016 int is_internal, struct NeighbourList *neighbour)
2018 struct MessageQueue *mq;
2023 /* check for duplicate submission */
2024 mq = neighbour->messages_head;
2027 if (mq->client == client)
2029 /* client transmitted to same peer twice
2030 before getting SEND_OK! */
2038 GNUNET_STATISTICS_update (stats,
2039 gettext_noop ("# bytes in message queue for other peers"),
2042 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2043 mq->specific_address = peer_address;
2044 mq->client = client;
2045 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2046 memcpy (&mq[1], message_buf, message_buf_size);
2047 mq->message_buf = (const char*) &mq[1];
2048 mq->message_buf_size = message_buf_size;
2049 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2050 mq->internal_msg = is_internal;
2051 mq->priority = priority;
2052 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2054 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2055 neighbour->messages_tail,
2058 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2059 neighbour->messages_tail,
2060 neighbour->messages_tail,
2062 try_transmission_to_peer (neighbour);
2069 struct GeneratorContext
2071 struct TransportPlugin *plug_pos;
2072 struct OwnAddressList *addr_pos;
2073 struct GNUNET_TIME_Absolute expiration;
2081 address_generator (void *cls, size_t max, void *buf)
2083 struct GeneratorContext *gc = cls;
2086 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2088 gc->plug_pos = gc->plug_pos->next;
2089 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2091 if (NULL == gc->plug_pos)
2096 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2099 gc->addr_pos->addrlen, buf, max);
2100 gc->addr_pos = gc->addr_pos->next;
2106 * Construct our HELLO message from all of the addresses of
2107 * all of the transports.
2112 struct GNUNET_HELLO_Message *hello;
2113 struct TransportClient *cpos;
2114 struct NeighbourList *npos;
2115 struct GeneratorContext gc;
2117 gc.plug_pos = plugins;
2118 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2119 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2120 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2123 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2125 GNUNET_STATISTICS_update (stats,
2126 gettext_noop ("# refreshed my HELLO"),
2130 while (cpos != NULL)
2132 transmit_to_client (cpos,
2133 (const struct GNUNET_MessageHeader *) hello,
2138 GNUNET_free_non_null (our_hello);
2140 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2142 while (npos != NULL)
2145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2146 "Transmitting updated `%s' to neighbour `%4s'\n",
2147 "HELLO", GNUNET_i2s (&npos->id));
2149 GNUNET_STATISTICS_update (stats,
2150 gettext_noop ("# transmitted my HELLO to other peers"),
2153 transmit_to_peer (NULL, NULL, 0,
2154 HELLO_ADDRESS_EXPIRATION,
2155 (const char *) our_hello,
2156 GNUNET_HELLO_size(our_hello),
2164 * Task used to clean up expired addresses for a plugin.
2166 * @param cls closure
2170 expire_address_task (void *cls,
2171 const struct GNUNET_SCHEDULER_TaskContext *tc);
2175 * Update the list of addresses for this plugin,
2176 * expiring those that are past their expiration date.
2178 * @param plugin addresses of which plugin should be recomputed?
2179 * @param fresh set to GNUNET_YES if a new address was added
2180 * and we need to regenerate the HELLO even if nobody
2184 update_addresses (struct TransportPlugin *plugin,
2187 static struct GNUNET_TIME_Absolute last_update;
2188 struct GNUNET_TIME_Relative min_remaining;
2189 struct GNUNET_TIME_Relative remaining;
2190 struct GNUNET_TIME_Absolute now;
2191 struct OwnAddressList *pos;
2192 struct OwnAddressList *prev;
2193 struct OwnAddressList *next;
2196 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2197 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2198 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2199 now = GNUNET_TIME_absolute_get ();
2200 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2201 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2203 pos = plugin->addresses;
2207 if (pos->expires.abs_value < now.abs_value)
2209 expired = GNUNET_YES;
2211 plugin->addresses = pos->next;
2213 prev->next = pos->next;
2218 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2219 if (remaining.rel_value < min_remaining.rel_value)
2220 min_remaining = remaining;
2226 if (expired || fresh)
2231 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2232 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2234 plugin->address_update_task
2235 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2236 &expire_address_task, plugin);
2241 * Task used to clean up expired addresses for a plugin.
2243 * @param cls closure
2247 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2249 struct TransportPlugin *plugin = cls;
2251 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2252 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2253 update_addresses (plugin, GNUNET_NO);
2258 * Iterator over hash map entries that NULLs the session of validation
2259 * entries that match the given session.
2261 * @param cls closure (the 'struct Session*' to match against)
2262 * @param key current key code (peer ID, not used)
2263 * @param value value in the hash map ('struct ValidationEntry*')
2264 * @return GNUNET_YES (we should continue to iterate)
2267 remove_session_validations (void *cls,
2268 const GNUNET_HashCode * key,
2271 struct Session *session = cls;
2272 struct ValidationEntry *ve = value;
2274 if (session == ve->session)
2281 * We've been disconnected from the other peer (for some
2282 * connection-oriented transport). Either quickly
2283 * re-establish the connection or signal the disconnect
2286 * Only signal CORE level disconnect if ALL addresses
2287 * for the peer are exhausted.
2289 * @param p overall plugin context
2290 * @param nl neighbour that was disconnected
2293 try_fast_reconnect (struct TransportPlugin *p,
2294 struct NeighbourList *nl)
2296 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2297 /* Note: the idea here is to hide problems with transports (or
2298 switching between plugins) from the core to eliminate the need to
2299 re-negotiate session keys and the like; OTOH, we should tell core
2300 quickly (much faster than timeout) `if a connection was lost and
2301 could not be re-established (i.e. other peer went down or is
2302 unable / refuses to communicate);
2304 So we should consider:
2305 1) ideally: our own willingness / need to connect
2306 2) prior failures to connect to this peer (by plugin)
2307 3) ideally: reasons why other peer terminated (as far as knowable)
2309 Most importantly, it must be POSSIBLE for another peer to terminate
2310 a connection for a while (without us instantly re-establishing it).
2311 Similarly, if another peer is gone we should quickly notify CORE.
2312 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2313 on the other end), we should reconnect in such a way that BOTH CORE
2314 services never even notice.
2315 Furthermore, the same mechanism (or small variation) could be used
2316 to switch to a better-performing plugin (ATS).
2318 Finally, this needs to be tested throughly... */
2321 * GNUNET_NO in the call below makes transport disconnect the peer,
2322 * even if only a single address (out of say, six) went away. This
2323 * function must be careful to ONLY disconnect if the peer is gone,
2324 * not just a specifi address.
2326 * More specifically, half the places it was used had it WRONG.
2329 /* No reconnect, signal disconnect instead! */
2330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2332 "try_fast_reconnect");
2333 disconnect_neighbour (nl, GNUNET_YES);
2338 * Function that will be called whenever the plugin internally
2339 * cleans up a session pointer and hence the service needs to
2340 * discard all of those sessions as well. Plugins that do not
2341 * use sessions can simply omit calling this function and always
2342 * use NULL wherever a session pointer is needed.
2344 * @param cls closure
2345 * @param peer which peer was the session for
2346 * @param session which session is being destoyed
2349 plugin_env_session_end (void *cls,
2350 const struct GNUNET_PeerIdentity *peer,
2351 struct Session *session)
2353 struct TransportPlugin *p = cls;
2354 struct NeighbourList *nl;
2355 struct ReadyList *rl;
2356 struct ForeignAddressList *pos;
2357 struct ForeignAddressList *prev;
2359 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2360 &remove_session_validations,
2362 nl = find_neighbour (peer);
2364 return; /* was never marked as connected */
2368 if (rl->plugin == p)
2373 return; /* was never marked as connected */
2375 pos = rl->addresses;
2376 while ( (pos != NULL) &&
2377 (pos->session != session) )
2383 return; /* was never marked as connected */
2384 pos->session = NULL;
2385 if (pos->addrlen != 0)
2387 if (nl->received_pong != GNUNET_NO)
2388 try_fast_reconnect (p, nl);
2391 /* was inbound connection, free 'pos' */
2393 rl->addresses = pos->next;
2395 prev->next = pos->next;
2396 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2398 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2399 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2402 if (nl->received_pong == GNUNET_NO)
2403 return; /* nothing to do, never connected... */
2404 /* check if we have any validated addresses left */
2405 pos = rl->addresses;
2410 try_fast_reconnect (p, nl);
2415 /* no valid addresses left, signal disconnect! */
2417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2418 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2419 "plugin_env_session_end");
2420 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2421 * it means there aren't any left for this PLUGIN/PEER combination! So
2422 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2423 * when it isn't necessary. Using GNUNET_YES at least checks to see
2424 * if there are any addresses that work first, so as not to overdo it.
2427 disconnect_neighbour (nl, GNUNET_YES);
2432 * Function that must be called by each plugin to notify the
2433 * transport service about the addresses under which the transport
2434 * provided by the plugin can be reached.
2436 * @param cls closure
2437 * @param name name of the transport that generated the address
2438 * @param addr one of the addresses of the host, NULL for the last address
2439 * the specific address format depends on the transport
2440 * @param addrlen length of the address
2441 * @param expires when should this address automatically expire?
2444 plugin_env_notify_address (void *cls,
2448 struct GNUNET_TIME_Relative expires)
2450 struct TransportPlugin *p = cls;
2451 struct OwnAddressList *al;
2452 struct GNUNET_TIME_Absolute abex;
2454 GNUNET_assert (addr != NULL);
2455 abex = GNUNET_TIME_relative_to_absolute (expires);
2456 GNUNET_assert (p == find_transport (name));
2460 if ( (addrlen == al->addrlen) &&
2461 (0 == memcmp (addr, &al[1], addrlen)) )
2464 update_addresses (p, GNUNET_NO);
2469 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2470 al->next = p->addresses;
2473 al->addrlen = addrlen;
2474 memcpy (&al[1], addr, addrlen);
2475 update_addresses (p, GNUNET_YES);
2480 * Notify all of our clients about a peer connecting.
2483 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2484 struct GNUNET_TIME_Relative latency,
2487 struct ConnectInfoMessage * cim;
2488 struct TransportClient *cpos;
2493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2494 "Notifying clients about connection from `%s'\n",
2497 GNUNET_STATISTICS_update (stats,
2498 gettext_noop ("# peers connected"),
2503 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2504 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2508 cim = GNUNET_malloc (size);
2510 cim->header.size = htons (size);
2511 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2512 cim->ats_count = htonl(2);
2513 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2514 (&(cim->ats))[0].value = htonl (distance);
2515 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2516 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2517 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2518 (&(cim->ats))[2].value = htonl (0);
2519 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2521 /* notify ats about connecting peer */
2522 ats_notify_peer_connect (peer, &(cim->ats));
2525 while (cpos != NULL)
2527 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2536 * Notify all of our clients about a peer disconnecting.
2539 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2541 struct DisconnectInfoMessage dim;
2542 struct TransportClient *cpos;
2545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2546 "Notifying clients about lost connection to `%s'\n",
2549 GNUNET_STATISTICS_update (stats,
2550 gettext_noop ("# peers connected"),
2553 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2554 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2555 dim.reserved = htonl (0);
2556 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2558 /* notify ats about connecting peer */
2559 ats_notify_peer_disconnect (peer);
2562 while (cpos != NULL)
2564 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2571 * Find a ForeignAddressList entry for the given neighbour
2572 * that matches the given address and transport.
2574 * @param neighbour which peer we care about
2575 * @param tname name of the transport plugin
2576 * @param session session to look for, NULL for 'any'; otherwise
2577 * can be used for the service to "learn" this session ID
2579 * @param addr binary address
2580 * @param addrlen length of addr
2581 * @return NULL if no such entry exists
2583 static struct ForeignAddressList *
2584 find_peer_address(struct NeighbourList *neighbour,
2586 struct Session *session,
2590 struct ReadyList *head;
2591 struct ForeignAddressList *pos;
2593 head = neighbour->plugins;
2594 while (head != NULL)
2596 if (0 == strcmp (tname, head->plugin->short_name))
2602 pos = head->addresses;
2603 while ( (pos != NULL) &&
2604 ( (pos->addrlen != addrlen) ||
2605 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2607 if ( (session != NULL) &&
2608 (pos->session == session) )
2612 if ( (session != NULL) && (pos != NULL) )
2613 pos->session = session; /* learn it! */
2619 * Get the peer address struct for the given neighbour and
2620 * address. If it doesn't yet exist, create it.
2622 * @param neighbour which peer we care about
2623 * @param tname name of the transport plugin
2624 * @param session session of the plugin, or NULL for none
2625 * @param addr binary address
2626 * @param addrlen length of addr
2627 * @return NULL if we do not have a transport plugin for 'tname'
2629 static struct ForeignAddressList *
2630 add_peer_address (struct NeighbourList *neighbour,
2632 struct Session *session,
2636 struct ReadyList *head;
2637 struct ForeignAddressList *ret;
2640 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2643 head = neighbour->plugins;
2645 while (head != NULL)
2647 if (0 == strcmp (tname, head->plugin->short_name))
2653 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2654 ret->session = session;
2655 if ((addrlen > 0) && (addr != NULL))
2657 ret->addr = (const char*) &ret[1];
2658 memcpy (&ret[1], addr, addrlen);
2665 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2667 for (c=0; c<available_ressources; c++)
2669 struct ATS_ressource_entry *r = ret->ressources;
2671 r[c].atis_index = ressources[c].atis_index;
2672 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2674 r[c].c = ressources[c].c_unix;
2677 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2679 r[c].c = ressources[c].c_udp;
2682 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2684 r[c].c = ressources[c].c_tcp;
2687 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2689 r[c].c = ressources[c].c_http;
2692 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2694 r[c].c = ressources[c].c_https;
2697 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2699 r[c].c = ressources[c].c_wlan;
2705 r[c].c = ressources[c].c_default;
2706 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2707 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2711 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2712 ret->addrlen = addrlen;
2713 ret->expires = GNUNET_TIME_relative_to_absolute
2714 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2715 ret->latency = GNUNET_TIME_relative_get_forever();
2717 ret->timeout = GNUNET_TIME_relative_to_absolute
2718 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2719 ret->ready_list = head;
2720 ret->next = head->addresses;
2721 head->addresses = ret;
2727 * Closure for 'add_validated_address'.
2729 struct AddValidatedAddressContext
2732 * Entry that has been validated.
2734 const struct ValidationEntry *ve;
2737 * Flag set after we have added the address so
2738 * that we terminate the iteration next time.
2745 * Callback function used to fill a buffer of max bytes with a list of
2746 * addresses in the format used by HELLOs. Should use
2747 * "GNUNET_HELLO_add_address" as a helper function.
2749 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2750 * @param max maximum number of bytes that can be written to buf
2751 * @param buf where to write the address information
2752 * @return number of bytes written, 0 to signal the
2753 * end of the iteration.
2756 add_validated_address (void *cls,
2757 size_t max, void *buf)
2759 struct AddValidatedAddressContext *avac = cls;
2760 const struct ValidationEntry *ve = avac->ve;
2762 if (GNUNET_YES == avac->done)
2764 avac->done = GNUNET_YES;
2765 return GNUNET_HELLO_add_address (ve->transport_name,
2766 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2776 * Closure for 'check_address_exists'.
2778 struct CheckAddressExistsClosure
2781 * Address to check for.
2786 * Name of the transport.
2793 struct Session *session;
2796 * Set to GNUNET_YES if the address exists.
2809 * Iterator over hash map entries. Checks if the given
2810 * validation entry is for the same address as what is given
2813 * @param cls the 'struct CheckAddressExistsClosure*'
2814 * @param key current key code (ignored)
2815 * @param value value in the hash map ('struct ValidationEntry')
2816 * @return GNUNET_YES if we should continue to
2817 * iterate (mismatch), GNUNET_NO if not (entry matched)
2820 check_address_exists (void *cls,
2821 const GNUNET_HashCode * key,
2824 struct CheckAddressExistsClosure *caec = cls;
2825 struct ValidationEntry *ve = value;
2827 if ( (0 == strcmp (caec->tname,
2828 ve->transport_name)) &&
2829 (caec->addrlen == ve->addrlen) &&
2830 (0 == memcmp (caec->addr,
2834 caec->exists = GNUNET_YES;
2837 if ( (ve->session != NULL) &&
2838 (caec->session == ve->session) )
2840 caec->exists = GNUNET_YES;
2849 * Iterator to free entries in the validation_map.
2851 * @param cls closure (unused)
2852 * @param key current key code
2853 * @param value value in the hash map (validation to abort)
2854 * @return GNUNET_YES (always)
2857 abort_validation (void *cls,
2858 const GNUNET_HashCode * key,
2861 struct ValidationEntry *va = value;
2863 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2864 GNUNET_SCHEDULER_cancel (va->timeout_task);
2865 GNUNET_free (va->transport_name);
2866 if (va->chvc != NULL)
2868 va->chvc->ve_count--;
2869 if (va->chvc->ve_count == 0)
2871 GNUNET_CONTAINER_DLL_remove (chvc_head,
2874 GNUNET_free (va->chvc);
2884 * HELLO validation cleanup task (validation failed).
2886 * @param cls the 'struct ValidationEntry' that failed
2887 * @param tc scheduler context (unused)
2890 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2892 struct ValidationEntry *va = cls;
2893 struct GNUNET_PeerIdentity pid;
2895 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2896 GNUNET_STATISTICS_update (stats,
2897 gettext_noop ("# address validation timeouts"),
2900 GNUNET_CRYPTO_hash (&va->publicKey,
2902 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2904 GNUNET_break (GNUNET_OK ==
2905 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2908 abort_validation (NULL, NULL, va);
2913 neighbour_timeout_task (void *cls,
2914 const struct GNUNET_SCHEDULER_TaskContext *tc)
2916 struct NeighbourList *n = cls;
2919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2920 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2922 GNUNET_STATISTICS_update (stats,
2923 gettext_noop ("# disconnects due to timeout"),
2926 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2927 disconnect_neighbour (n, GNUNET_NO);
2932 * Schedule the job that will cause us to send a PING to the
2933 * foreign address to evaluate its validity and latency.
2935 * @param fal address to PING
2938 schedule_next_ping (struct ForeignAddressList *fal);
2942 * Add the given address to the list of foreign addresses
2943 * available for the given peer (check for duplicates).
2945 * @param cls the respective 'struct NeighbourList' to update
2946 * @param tname name of the transport
2947 * @param expiration expiration time
2948 * @param addr the address
2949 * @param addrlen length of the address
2950 * @return GNUNET_OK (always)
2953 add_to_foreign_address_list (void *cls,
2955 struct GNUNET_TIME_Absolute expiration,
2959 struct NeighbourList *n = cls;
2960 struct ForeignAddressList *fal;
2963 GNUNET_STATISTICS_update (stats,
2964 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2968 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2971 #if DEBUG_TRANSPORT_HELLO
2972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2973 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2974 a2s (tname, addr, addrlen),
2976 GNUNET_i2s (&n->id),
2977 expiration.abs_value);
2979 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2982 GNUNET_STATISTICS_update (stats,
2983 gettext_noop ("# previously validated addresses lacking transport"),
2989 fal->expires = GNUNET_TIME_absolute_max (expiration,
2991 schedule_next_ping (fal);
2997 fal->expires = GNUNET_TIME_absolute_max (expiration,
3002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3003 "Failed to add new address for `%4s'\n",
3004 GNUNET_i2s (&n->id));
3007 if (fal->validated == GNUNET_NO)
3009 fal->validated = GNUNET_YES;
3010 GNUNET_STATISTICS_update (stats,
3011 gettext_noop ("# peer addresses considered valid"),
3015 if (try == GNUNET_YES)
3017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3018 "Have new addresses, will try to trigger transmissions.\n");
3019 try_transmission_to_peer (n);
3026 * Add addresses in validated HELLO "h" to the set of addresses
3027 * we have for this peer.
3029 * @param cls closure ('struct NeighbourList*')
3030 * @param peer id of the peer, NULL for last call
3031 * @param h hello message for the peer (can be NULL)
3032 * @param err_msg NULL if successful, otherwise contains error message
3035 add_hello_for_peer (void *cls,
3036 const struct GNUNET_PeerIdentity *peer,
3037 const struct GNUNET_HELLO_Message *h,
3038 const char *err_msg)
3040 struct NeighbourList *n = cls;
3042 if (err_msg != NULL)
3044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3045 _("Error in communication with PEERINFO service\n"));
3050 GNUNET_STATISTICS_update (stats,
3051 gettext_noop ("# outstanding peerinfo iterate requests"),
3058 return; /* no HELLO available */
3060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3061 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3065 if (GNUNET_YES != n->public_key_valid)
3067 GNUNET_HELLO_get_key (h, &n->publicKey);
3068 n->public_key_valid = GNUNET_YES;
3070 GNUNET_HELLO_iterate_addresses (h,
3072 &add_to_foreign_address_list,
3078 * Create a fresh entry in our neighbour list for the given peer.
3079 * Will try to transmit our current HELLO to the new neighbour.
3080 * Do not call this function directly, use 'setup_peer_check_blacklist.
3082 * @param peer the peer for which we create the entry
3083 * @param do_hello should we schedule transmitting a HELLO
3084 * @return the new neighbour list entry
3086 static struct NeighbourList *
3087 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3090 struct NeighbourList *n;
3091 struct TransportPlugin *tp;
3092 struct ReadyList *rl;
3095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3096 "Setting up state for neighbour `%4s'\n",
3099 GNUNET_assert (our_hello != NULL);
3100 GNUNET_STATISTICS_update (stats,
3101 gettext_noop ("# active neighbours"),
3104 n = GNUNET_malloc (sizeof (struct NeighbourList));
3105 n->next = neighbours;
3109 GNUNET_TIME_relative_to_absolute
3110 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3111 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3112 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3113 MAX_BANDWIDTH_CARRY_S);
3117 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3119 rl = GNUNET_malloc (sizeof (struct ReadyList));
3121 rl->next = n->plugins;
3124 rl->addresses = NULL;
3128 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3130 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3131 &neighbour_timeout_task, n);
3134 GNUNET_STATISTICS_update (stats,
3135 gettext_noop ("# peerinfo new neighbor iterate requests"),
3138 GNUNET_STATISTICS_update (stats,
3139 gettext_noop ("# outstanding peerinfo iterate requests"),
3142 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3143 GNUNET_TIME_UNIT_FOREVER_REL,
3144 &add_hello_for_peer, n);
3146 GNUNET_STATISTICS_update (stats,
3147 gettext_noop ("# HELLO's sent to new neighbors"),
3150 transmit_to_peer (NULL, NULL, 0,
3151 HELLO_ADDRESS_EXPIRATION,
3152 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3160 * Function called after we have checked if communicating
3161 * with a given peer is acceptable.
3163 * @param cls closure
3164 * @param n NULL if communication is not acceptable
3166 typedef void (*SetupContinuation)(void *cls,
3167 struct NeighbourList *n);
3171 * Information kept for each client registered to perform
3177 * This is a linked list.
3179 struct Blacklisters *next;
3182 * This is a linked list.
3184 struct Blacklisters *prev;
3187 * Client responsible for this entry.
3189 struct GNUNET_SERVER_Client *client;
3192 * Blacklist check that we're currently performing.
3194 struct BlacklistCheck *bc;
3200 * Head of DLL of blacklisting clients.
3202 static struct Blacklisters *bl_head;
3205 * Tail of DLL of blacklisting clients.
3207 static struct Blacklisters *bl_tail;
3211 * Context we use when performing a blacklist check.
3213 struct BlacklistCheck
3217 * This is a linked list.
3219 struct BlacklistCheck *next;
3222 * This is a linked list.
3224 struct BlacklistCheck *prev;
3227 * Peer being checked.
3229 struct GNUNET_PeerIdentity peer;
3232 * Option for setup neighbour afterwards.
3237 * Continuation to call with the result.
3239 SetupContinuation cont;
3247 * Current transmission request handle for this client, or NULL if no
3248 * request is pending.
3250 struct GNUNET_CONNECTION_TransmitHandle *th;
3253 * Our current position in the blacklisters list.
3255 struct Blacklisters *bl_pos;
3258 * Current task performing the check.
3260 GNUNET_SCHEDULER_TaskIdentifier task;
3265 * Head of DLL of active blacklisting queries.
3267 static struct BlacklistCheck *bc_head;
3270 * Tail of DLL of active blacklisting queries.
3272 static struct BlacklistCheck *bc_tail;
3276 * Perform next action in the blacklist check.
3278 * @param cls the 'struct BlacklistCheck*'
3282 do_blacklist_check (void *cls,
3283 const struct GNUNET_SCHEDULER_TaskContext *tc);
3286 * Transmit blacklist query to the client.
3288 * @param cls the 'struct BlacklistCheck'
3289 * @param size number of bytes allowed
3290 * @param buf where to copy the message
3291 * @return number of bytes copied to buf
3294 transmit_blacklist_message (void *cls,
3298 struct BlacklistCheck *bc = cls;
3299 struct Blacklisters *bl;
3300 struct BlacklistMessage bm;
3305 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3306 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3311 bm.header.size = htons (sizeof (struct BlacklistMessage));
3312 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3313 bm.is_allowed = htonl (0);
3315 memcpy (buf, &bm, sizeof (bm));
3316 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3322 * Perform next action in the blacklist check.
3324 * @param cls the 'struct BlacklistCheck*'
3328 do_blacklist_check (void *cls,
3329 const struct GNUNET_SCHEDULER_TaskContext *tc)
3331 struct BlacklistCheck *bc = cls;
3332 struct Blacklisters *bl;
3334 bc->task = GNUNET_SCHEDULER_NO_TASK;
3338 bc->cont (bc->cont_cls,
3339 setup_new_neighbour (&bc->peer, bc->do_hello));
3346 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3347 sizeof (struct BlacklistMessage),
3348 GNUNET_TIME_UNIT_FOREVER_REL,
3349 &transmit_blacklist_message,
3356 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3357 * does not yet exist, check the blacklist. If the blacklist says creating
3358 * one is acceptable, create one and call the continuation; otherwise
3359 * call the continuation with NULL.
3361 * @param peer peer to setup or look up a struct NeighbourList for
3362 * @param do_hello should we also schedule sending our HELLO to the peer
3363 * if this is a new record
3364 * @param cont function to call with the 'struct NeigbhbourList*'
3365 * @param cont_cls closure for cont
3368 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3370 SetupContinuation cont,
3373 struct NeighbourList *n;
3374 struct BlacklistCheck *bc;
3376 n = find_neighbour(peer);
3383 if (bl_head == NULL)
3386 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3388 setup_new_neighbour(peer, do_hello);
3391 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3392 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3394 bc->do_hello = do_hello;
3396 bc->cont_cls = cont_cls;
3397 bc->bl_pos = bl_head;
3398 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3404 * Function called with the result of querying a new blacklister about
3405 * it being allowed (or not) to continue to talk to an existing neighbour.
3407 * @param cls the original 'struct NeighbourList'
3408 * @param n NULL if we need to disconnect
3411 confirm_or_drop_neighbour (void *cls,
3412 struct NeighbourList *n)
3414 struct NeighbourList * orig = cls;
3418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3419 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3420 "confirm_or_drop_neighboUr");
3421 disconnect_neighbour (orig, GNUNET_NO);
3427 * Handle a request to start a blacklist.
3429 * @param cls closure (always NULL)
3430 * @param client identification of the client
3431 * @param message the actual message
3434 handle_blacklist_init (void *cls,
3435 struct GNUNET_SERVER_Client *client,
3436 const struct GNUNET_MessageHeader *message)
3438 struct Blacklisters *bl;
3439 struct BlacklistCheck *bc;
3440 struct NeighbourList *n;
3445 if (bl->client == client)
3448 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3453 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3454 bl->client = client;
3455 GNUNET_SERVER_client_keep (client);
3456 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3457 /* confirm that all existing connections are OK! */
3461 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3462 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3464 bc->do_hello = GNUNET_NO;
3465 bc->cont = &confirm_or_drop_neighbour;
3468 if (n == neighbours) /* all would wait for the same client, no need to
3469 create more than just the first task right now */
3470 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3478 * Handle a request to blacklist a peer.
3480 * @param cls closure (always NULL)
3481 * @param client identification of the client
3482 * @param message the actual message
3485 handle_blacklist_reply (void *cls,
3486 struct GNUNET_SERVER_Client *client,
3487 const struct GNUNET_MessageHeader *message)
3489 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3490 struct Blacklisters *bl;
3491 struct BlacklistCheck *bc;
3494 while ( (bl != NULL) &&
3495 (bl->client != client) )
3499 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3504 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3506 bc->cont (bc->cont_cls, NULL);
3507 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3512 bc->bl_pos = bc->bl_pos->next;
3513 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3516 /* check if any other bc's are waiting for this blacklister */
3520 if ( (bc->bl_pos == bl) &&
3521 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3522 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3530 * Send periodic PING messages to a given foreign address.
3532 * @param cls our 'struct PeriodicValidationContext*'
3533 * @param tc task context
3536 send_periodic_ping (void *cls,
3537 const struct GNUNET_SCHEDULER_TaskContext *tc)
3539 struct ForeignAddressList *peer_address = cls;
3540 struct TransportPlugin *tp;
3541 struct ValidationEntry *va;
3542 struct NeighbourList *neighbour;
3543 struct TransportPingMessage ping;
3544 struct CheckAddressExistsClosure caec;
3546 uint16_t hello_size;
3550 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3551 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3553 tp = peer_address->ready_list->plugin;
3554 neighbour = peer_address->ready_list->neighbour;
3555 if (GNUNET_YES != neighbour->public_key_valid)
3557 /* no public key yet, try again later */
3558 schedule_next_ping (peer_address);
3561 caec.addr = peer_address->addr;
3562 caec.addrlen = peer_address->addrlen;
3563 caec.tname = tp->short_name;
3564 caec.session = peer_address->session;
3565 caec.exists = GNUNET_NO;
3566 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3567 &check_address_exists,
3569 if (caec.exists == GNUNET_YES)
3571 /* During validation attempts we will likely trigger the other
3572 peer trying to validate our address which in turn will cause
3573 it to send us its HELLO, so we expect to hit this case rather
3574 frequently. Only print something if we are very verbose. */
3575 #if DEBUG_TRANSPORT > 1
3576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3577 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3578 (peer_address->addr != NULL)
3579 ? a2s (tp->short_name,
3581 peer_address->addrlen)
3584 GNUNET_i2s (&neighbour->id));
3586 schedule_next_ping (peer_address);
3589 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3590 va->transport_name = GNUNET_strdup (tp->short_name);
3591 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3593 va->send_time = GNUNET_TIME_absolute_get();
3594 va->session = peer_address->session;
3595 if (peer_address->addr != NULL)
3597 va->addr = (const void*) &va[1];
3598 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3599 va->addrlen = peer_address->addrlen;
3601 memcpy(&va->publicKey,
3602 &neighbour->publicKey,
3603 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3605 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3606 &timeout_hello_validation,
3608 GNUNET_CONTAINER_multihashmap_put (validation_map,
3609 &neighbour->id.hashPubKey,
3611 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3613 if (peer_address->validated != GNUNET_YES)
3614 hello_size = GNUNET_HELLO_size(our_hello);
3618 tsize = sizeof(struct TransportPingMessage) + hello_size;
3620 if (peer_address->addr != NULL)
3622 slen = strlen (tp->short_name) + 1;
3623 tsize += slen + peer_address->addrlen;
3627 slen = 0; /* make gcc happy */
3629 message_buf = GNUNET_malloc(tsize);
3630 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3631 ping.challenge = htonl(va->challenge);
3632 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3633 if (peer_address->validated != GNUNET_YES)
3635 memcpy(message_buf, our_hello, hello_size);
3638 if (peer_address->addr != NULL)
3640 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3641 peer_address->addrlen +
3643 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3646 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3648 peer_address->addrlen);
3652 ping.header.size = htons(sizeof(struct TransportPingMessage));
3655 memcpy(&message_buf[hello_size],
3657 sizeof(struct TransportPingMessage));
3659 #if DEBUG_TRANSPORT_REVALIDATION
3660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3661 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3662 (peer_address->addr != NULL)
3663 ? a2s (peer_address->plugin->short_name,
3665 peer_address->addrlen)
3668 GNUNET_i2s (&neighbour->id),
3669 "HELLO", hello_size,
3672 if (peer_address->validated != GNUNET_YES)
3673 GNUNET_STATISTICS_update (stats,
3674 gettext_noop ("# PING with HELLO messages sent"),
3678 GNUNET_STATISTICS_update (stats,
3679 gettext_noop ("# PING without HELLO messages sent"),
3682 GNUNET_STATISTICS_update (stats,
3683 gettext_noop ("# PING messages sent for re-validation"),
3686 transmit_to_peer (NULL, peer_address,
3687 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3688 HELLO_VERIFICATION_TIMEOUT,
3690 GNUNET_YES, neighbour);
3691 GNUNET_free(message_buf);
3692 schedule_next_ping (peer_address);
3697 * Schedule the job that will cause us to send a PING to the
3698 * foreign address to evaluate its validity and latency.
3700 * @param fal address to PING
3703 schedule_next_ping (struct ForeignAddressList *fal)
3705 struct GNUNET_TIME_Relative delay;
3707 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3709 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3710 delay.rel_value /= 2; /* do before expiration */
3711 delay = GNUNET_TIME_relative_min (delay,
3712 LATENCY_EVALUATION_MAX_DELAY);
3713 if (GNUNET_YES != fal->estimated)
3715 delay = GNUNET_TIME_UNIT_ZERO;
3716 fal->estimated = GNUNET_YES;
3718 if (GNUNET_YES == fal->connected)
3720 delay = GNUNET_TIME_relative_min (delay,
3721 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3723 /* FIXME: also adjust delay based on how close the last
3724 observed latency is to the latency of the best alternative */
3725 /* bound how fast we can go */
3726 delay = GNUNET_TIME_relative_max (delay,
3727 GNUNET_TIME_UNIT_SECONDS);
3728 /* randomize a bit (to avoid doing all at the same time) */
3729 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3730 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3731 &send_periodic_ping,
3739 * Function that will be called if we receive some payload
3740 * from another peer.
3742 * @param message the payload
3743 * @param n peer who claimed to be the sender
3746 handle_payload_message (const struct GNUNET_MessageHeader *message,
3747 struct NeighbourList *n)
3749 struct InboundMessage *im;
3750 struct TransportClient *cpos;
3753 msize = ntohs (message->size);
3754 if (n->received_pong == GNUNET_NO)
3756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3757 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3758 ntohs (message->type),
3759 ntohs (message->size),
3760 GNUNET_i2s (&n->id));
3761 GNUNET_free_non_null (n->pre_connect_message_buffer);
3762 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3763 memcpy (n->pre_connect_message_buffer, message, msize);
3768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3769 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3770 ntohs (message->type),
3771 ntohs (message->size),
3772 GNUNET_i2s (&n->id));
3774 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3777 n->quota_violation_count++;
3779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3780 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3781 n->in_tracker.available_bytes_per_s__,
3782 n->quota_violation_count);
3784 /* Discount 32k per violation */
3785 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3790 if (n->quota_violation_count > 0)
3792 /* try to add 32k back */
3793 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3795 n->quota_violation_count--;
3798 GNUNET_STATISTICS_update (stats,
3799 gettext_noop ("# payload received from other peers"),
3802 /* transmit message to all clients */
3803 uint32_t ats_count = 2;
3804 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3805 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3808 im = GNUNET_malloc (size);
3809 im->header.size = htons (size);
3810 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3812 im->ats_count = htonl(ats_count);
3813 /* Setting ATS data */
3814 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3815 (&(im->ats))[0].value = htonl (n->distance);
3816 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3817 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3818 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3819 (&(im->ats))[ats_count].value = htonl (0);
3821 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3823 while (cpos != NULL)
3825 transmit_to_client (cpos, &im->header, GNUNET_YES);
3833 * Iterator over hash map entries. Checks if the given validation
3834 * entry is for the same challenge as what is given in the PONG.
3836 * @param cls the 'struct TransportPongMessage*'
3837 * @param key peer identity
3838 * @param value value in the hash map ('struct ValidationEntry')
3839 * @return GNUNET_YES if we should continue to
3840 * iterate (mismatch), GNUNET_NO if not (entry matched)
3843 check_pending_validation (void *cls,
3844 const GNUNET_HashCode * key,
3847 const struct TransportPongMessage *pong = cls;
3848 struct ValidationEntry *ve = value;
3849 struct AddValidatedAddressContext avac;
3850 unsigned int challenge = ntohl(pong->challenge);
3851 struct GNUNET_HELLO_Message *hello;
3852 struct GNUNET_PeerIdentity target;
3853 struct NeighbourList *n;
3854 struct ForeignAddressList *fal;
3855 struct OwnAddressList *oal;
3856 struct TransportPlugin *tp;
3857 struct GNUNET_MessageHeader *prem;
3863 ps = ntohs (pong->header.size);
3864 if (ps < sizeof (struct TransportPongMessage))
3866 GNUNET_break_op (0);
3869 addr = (const char*) &pong[1];
3870 slen = strlen (ve->transport_name) + 1;
3871 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3872 (ve->challenge != challenge) ||
3873 (addr[slen-1] != '\0') ||
3874 (0 != strcmp (addr, ve->transport_name)) ||
3875 (ntohl (pong->purpose.size)
3876 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3878 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3879 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3884 alen = ps - sizeof (struct TransportPongMessage) - slen;
3885 switch (ntohl (pong->purpose.purpose))
3887 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3888 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3889 (0 != memcmp (&addr[slen],
3893 return GNUNET_YES; /* different entry, keep trying! */
3895 if (0 != memcmp (&pong->pid,
3897 sizeof (struct GNUNET_PeerIdentity)))
3899 GNUNET_break_op (0);
3903 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3908 GNUNET_break_op (0);
3913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3914 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3916 a2s (ve->transport_name,
3917 (const struct sockaddr *) ve->addr,
3919 ve->transport_name);
3922 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3923 if (0 != memcmp (&pong->pid,
3925 sizeof (struct GNUNET_PeerIdentity)))
3927 GNUNET_break_op (0);
3930 if (ve->addrlen != 0)
3932 /* must have been for a different validation entry */
3935 tp = find_transport (ve->transport_name);
3941 oal = tp->addresses;
3944 if ( (oal->addrlen == alen) &&
3945 (0 == memcmp (&oal[1],
3953 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3954 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3955 a2s (ve->transport_name,
3961 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3966 GNUNET_break_op (0);
3971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3972 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3974 a2s (ve->transport_name,
3977 ve->transport_name);
3981 GNUNET_break_op (0);
3984 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3986 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3987 _("Received expired signature. Check system time.\n"));
3990 GNUNET_STATISTICS_update (stats,
3991 gettext_noop ("# address validation successes"),
3994 /* create the updated HELLO */
3995 GNUNET_CRYPTO_hash (&ve->publicKey,
3996 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3997 &target.hashPubKey);
3998 if (ve->addr != NULL)
4000 avac.done = GNUNET_NO;
4002 hello = GNUNET_HELLO_create (&ve->publicKey,
4003 &add_validated_address,
4005 GNUNET_PEERINFO_add_peer (peerinfo,
4007 GNUNET_free (hello);
4009 n = find_neighbour (&target);
4012 n->publicKey = ve->publicKey;
4013 n->public_key_valid = GNUNET_YES;
4014 fal = add_peer_address (n,
4019 GNUNET_assert (fal != NULL);
4020 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4021 fal->validated = GNUNET_YES;
4022 mark_address_connected (fal);
4023 GNUNET_STATISTICS_update (stats,
4024 gettext_noop ("# peer addresses considered valid"),
4027 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4028 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4030 schedule_next_ping (fal);
4031 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4032 n->latency = fal->latency;
4034 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4036 n->distance = fal->distance;
4037 if (GNUNET_NO == n->received_pong)
4039 n->received_pong = GNUNET_YES;
4041 notify_clients_connect (&target, n->latency, n->distance);
4042 if (NULL != (prem = n->pre_connect_message_buffer))
4044 n->pre_connect_message_buffer = NULL;
4045 handle_payload_message (prem, n);
4049 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4051 GNUNET_SCHEDULER_cancel (n->retry_task);
4052 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4053 try_transmission_to_peer (n);
4057 /* clean up validation entry */
4058 GNUNET_assert (GNUNET_YES ==
4059 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4062 abort_validation (NULL, NULL, ve);
4068 * Function that will be called if we receive a validation
4069 * of an address challenge that we transmitted to another
4070 * peer. Note that the validation should only be considered
4071 * acceptable if the challenge matches AND if the sender
4072 * address is at least a plausible address for this peer
4073 * (otherwise we may be seeing a MiM attack).
4075 * @param cls closure
4076 * @param message the pong message
4077 * @param peer who responded to our challenge
4078 * @param sender_address string describing our sender address (as observed
4079 * by the other peer in binary format)
4080 * @param sender_address_len number of bytes in 'sender_address'
4083 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4084 const struct GNUNET_PeerIdentity *peer,
4085 const char *sender_address,
4086 size_t sender_address_len)
4088 #if DEBUG_TRANSPORT > 1
4089 /* we get tons of these that just get discarded, only log
4090 if we are quite verbose */
4091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4092 "Receiving `%s' message from `%4s'.\n", "PONG",
4095 GNUNET_STATISTICS_update (stats,
4096 gettext_noop ("# PONG messages received"),
4099 if (GNUNET_SYSERR !=
4100 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4102 &check_pending_validation,
4105 /* This is *expected* to happen a lot since we send
4106 PONGs to *all* known addresses of the sender of
4107 the PING, so most likely we get multiple PONGs
4108 per PING, and all but the first PONG will end up
4109 here. So really we should not print anything here
4110 unless we want to be very, very verbose... */
4111 #if DEBUG_TRANSPORT > 2
4112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4113 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4125 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4127 * @param cls the 'struct ValidationEntry*'
4128 * @param neighbour neighbour to validate, NULL if validation failed
4131 transmit_hello_and_ping (void *cls,
4132 struct NeighbourList *neighbour)
4134 struct ValidationEntry *va = cls;
4135 struct ForeignAddressList *peer_address;
4136 struct TransportPingMessage ping;
4137 uint16_t hello_size;
4140 struct GNUNET_PeerIdentity id;
4143 GNUNET_CRYPTO_hash (&va->publicKey,
4144 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4146 if (neighbour == NULL)
4148 /* FIXME: stats... */
4149 GNUNET_break (GNUNET_OK ==
4150 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4153 abort_validation (NULL, NULL, va);
4156 neighbour->publicKey = va->publicKey;
4157 neighbour->public_key_valid = GNUNET_YES;
4158 peer_address = add_peer_address (neighbour,
4159 va->transport_name, NULL,
4160 (const void*) &va[1],
4162 if (peer_address == NULL)
4164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4165 "Failed to add peer `%4s' for plugin `%s'\n",
4166 GNUNET_i2s (&neighbour->id),
4167 va->transport_name);
4168 GNUNET_break (GNUNET_OK ==
4169 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4172 abort_validation (NULL, NULL, va);
4175 hello_size = GNUNET_HELLO_size(our_hello);
4176 slen = strlen(va->transport_name) + 1;
4177 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4178 message_buf = GNUNET_malloc(tsize);
4179 ping.challenge = htonl(va->challenge);
4180 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4181 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4182 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4183 memcpy(message_buf, our_hello, hello_size);
4184 memcpy(&message_buf[hello_size],
4186 sizeof(struct TransportPingMessage));
4187 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4190 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4195 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4198 : a2s (va->transport_name,
4199 (const void*) &va[1], va->addrlen),
4201 GNUNET_i2s (&neighbour->id),
4202 "HELLO", hello_size,
4203 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4206 GNUNET_STATISTICS_update (stats,
4207 gettext_noop ("# PING messages sent for initial validation"),
4210 transmit_to_peer (NULL, peer_address,
4211 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4212 HELLO_VERIFICATION_TIMEOUT,
4214 GNUNET_YES, neighbour);
4215 GNUNET_free(message_buf);
4220 * Check if the given address is already being validated; if not,
4221 * append the given address to the list of entries that are being be
4222 * validated and initiate validation.
4224 * @param cls closure ('struct CheckHelloValidatedContext *')
4225 * @param tname name of the transport
4226 * @param expiration expiration time
4227 * @param addr the address
4228 * @param addrlen length of the address
4229 * @return GNUNET_OK (always)
4232 run_validation (void *cls,
4234 struct GNUNET_TIME_Absolute expiration,
4238 struct CheckHelloValidatedContext *chvc = cls;
4239 struct GNUNET_PeerIdentity id;
4240 struct TransportPlugin *tp;
4241 struct ValidationEntry *va;
4242 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4243 struct CheckAddressExistsClosure caec;
4244 struct OwnAddressList *oal;
4246 GNUNET_assert (addr != NULL);
4248 GNUNET_STATISTICS_update (stats,
4249 gettext_noop ("# peer addresses scheduled for validation"),
4252 tp = find_transport (tname);
4255 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4256 GNUNET_ERROR_TYPE_BULK,
4258 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4260 GNUNET_STATISTICS_update (stats,
4261 gettext_noop ("# peer addresses not validated (plugin not available)"),
4266 /* check if this is one of our own addresses */
4267 oal = tp->addresses;
4270 if ( (oal->addrlen == addrlen) &&
4271 (0 == memcmp (&oal[1],
4275 /* not plausible, this address is equivalent to our own address! */
4276 GNUNET_STATISTICS_update (stats,
4277 gettext_noop ("# peer addresses not validated (loopback)"),
4284 GNUNET_HELLO_get_key (chvc->hello, &pk);
4285 GNUNET_CRYPTO_hash (&pk,
4287 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4290 if (is_blacklisted(&id, tp))
4293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4294 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4302 caec.addrlen = addrlen;
4303 caec.session = NULL;
4305 caec.exists = GNUNET_NO;
4306 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4307 &check_address_exists,
4309 if (caec.exists == GNUNET_YES)
4311 /* During validation attempts we will likely trigger the other
4312 peer trying to validate our address which in turn will cause
4313 it to send us its HELLO, so we expect to hit this case rather
4314 frequently. Only print something if we are very verbose. */
4315 #if DEBUG_TRANSPORT > 1
4316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4317 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4318 a2s (tname, addr, addrlen),
4322 GNUNET_STATISTICS_update (stats,
4323 gettext_noop ("# peer addresses not validated (in progress)"),
4328 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4331 va->transport_name = GNUNET_strdup (tname);
4332 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4334 va->send_time = GNUNET_TIME_absolute_get();
4335 va->addr = (const void*) &va[1];
4336 memcpy (&va[1], addr, addrlen);
4337 va->addrlen = addrlen;
4338 GNUNET_HELLO_get_key (chvc->hello,
4340 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4341 &timeout_hello_validation,
4343 GNUNET_CONTAINER_multihashmap_put (validation_map,
4346 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4347 setup_peer_check_blacklist (&id, GNUNET_NO,
4348 &transmit_hello_and_ping,
4355 * Check if addresses in validated hello "h" overlap with
4356 * those in "chvc->hello" and validate the rest.
4358 * @param cls closure
4359 * @param peer id of the peer, NULL for last call
4360 * @param h hello message for the peer (can be NULL)
4361 * @param err_msg NULL if successful, otherwise contains error message
4364 check_hello_validated (void *cls,
4365 const struct GNUNET_PeerIdentity *peer,
4366 const struct GNUNET_HELLO_Message *h,
4367 const char *err_msg)
4369 struct CheckHelloValidatedContext *chvc = cls;
4370 struct GNUNET_HELLO_Message *plain_hello;
4371 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4372 struct GNUNET_PeerIdentity target;
4373 struct NeighbourList *n;
4375 if (err_msg != NULL)
4377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4378 _("Error in communication with PEERINFO service\n"));
4384 GNUNET_STATISTICS_update (stats,
4385 gettext_noop ("# outstanding peerinfo iterate requests"),
4389 if (GNUNET_NO == chvc->hello_known)
4391 /* notify PEERINFO about the peer now, so that we at least
4392 have the public key if some other component needs it */
4393 GNUNET_HELLO_get_key (chvc->hello, &pk);
4394 GNUNET_CRYPTO_hash (&pk,
4395 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4396 &target.hashPubKey);
4397 plain_hello = GNUNET_HELLO_create (&pk,
4400 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4401 GNUNET_free (plain_hello);
4402 #if DEBUG_TRANSPORT_HELLO
4403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4404 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4406 GNUNET_i2s (&target));
4408 GNUNET_STATISTICS_update (stats,
4409 gettext_noop ("# new HELLOs requiring full validation"),
4412 GNUNET_HELLO_iterate_addresses (chvc->hello,
4419 GNUNET_STATISTICS_update (stats,
4420 gettext_noop ("# duplicate HELLO (peer known)"),
4425 if (chvc->ve_count == 0)
4427 GNUNET_CONTAINER_DLL_remove (chvc_head,
4436 #if DEBUG_TRANSPORT_HELLO
4437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4438 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4442 chvc->hello_known = GNUNET_YES;
4443 n = find_neighbour (peer);
4446 #if DEBUG_TRANSPORT_HELLO
4447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4448 "Calling hello_iterate_addresses for %s!\n",
4451 GNUNET_HELLO_iterate_addresses (h,
4453 &add_to_foreign_address_list,
4455 try_transmission_to_peer (n);
4459 #if DEBUG_TRANSPORT_HELLO
4460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4461 "No existing neighbor record for %s!\n",
4464 GNUNET_STATISTICS_update (stats,
4465 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4469 GNUNET_STATISTICS_update (stats,
4470 gettext_noop ("# HELLO validations (update case)"),
4473 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4475 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4482 * Process HELLO-message.
4484 * @param plugin transport involved, may be NULL
4485 * @param message the actual message
4486 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4489 process_hello (struct TransportPlugin *plugin,
4490 const struct GNUNET_MessageHeader *message)
4493 struct GNUNET_PeerIdentity target;
4494 const struct GNUNET_HELLO_Message *hello;
4495 struct CheckHelloValidatedContext *chvc;
4496 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4497 #if DEBUG_TRANSPORT_HELLO > 2
4500 hsize = ntohs (message->size);
4501 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4502 (hsize < sizeof (struct GNUNET_MessageHeader)))
4505 return GNUNET_SYSERR;
4507 GNUNET_STATISTICS_update (stats,
4508 gettext_noop ("# HELLOs received for validation"),
4512 /* first, check if load is too high */
4513 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4515 GNUNET_STATISTICS_update (stats,
4516 gettext_noop ("# HELLOs ignored due to high load"),
4519 #if DEBUG_TRANSPORT_HELLO
4520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4521 "Ignoring `%s' for `%4s', load too high.\n",
4523 GNUNET_i2s (&target));
4527 hello = (const struct GNUNET_HELLO_Message *) message;
4528 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4530 #if DEBUG_TRANSPORT_HELLO
4531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4532 "Unable to get public key from `%s' for `%4s'!\n",
4534 GNUNET_i2s (&target));
4536 GNUNET_break_op (0);
4537 return GNUNET_SYSERR;
4540 GNUNET_CRYPTO_hash (&publicKey,
4541 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4542 &target.hashPubKey);
4544 #if DEBUG_TRANSPORT_HELLO
4545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4546 "Received `%s' message for `%4s'\n",
4548 GNUNET_i2s (&target));
4551 if (0 == memcmp (&my_identity,
4553 sizeof (struct GNUNET_PeerIdentity)))
4555 GNUNET_STATISTICS_update (stats,
4556 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4562 while (NULL != chvc)
4564 if (GNUNET_HELLO_equals (hello,
4566 GNUNET_TIME_absolute_get ()).abs_value > 0)
4568 #if DEBUG_TRANSPORT_HELLO > 2
4569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4570 "Received duplicate `%s' message for `%4s'; ignored\n",
4572 GNUNET_i2s (&target));
4574 return GNUNET_OK; /* validation already pending */
4576 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4577 GNUNET_break (0 != memcmp (hello, chvc->hello,
4578 GNUNET_HELLO_size(hello)));
4583 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4584 if ((NULL != temp_neighbor))
4586 fprintf(stderr, "Already know peer, ignoring hello\n");
4591 #if DEBUG_TRANSPORT_HELLO > 2
4594 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4596 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4599 GNUNET_i2s (&target),
4601 GNUNET_HELLO_size(hello));
4605 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4607 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4608 memcpy (&chvc[1], hello, hsize);
4609 GNUNET_CONTAINER_DLL_insert (chvc_head,
4612 /* finally, check if HELLO was previously validated
4613 (continuation will then schedule actual validation) */
4614 GNUNET_STATISTICS_update (stats,
4615 gettext_noop ("# peerinfo process hello iterate requests"),
4618 GNUNET_STATISTICS_update (stats,
4619 gettext_noop ("# outstanding peerinfo iterate requests"),
4622 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4624 HELLO_VERIFICATION_TIMEOUT,
4625 &check_hello_validated, chvc);
4631 * The peer specified by the given neighbour has timed-out or a plugin
4632 * has disconnected. We may either need to do nothing (other plugins
4633 * still up), or trigger a full disconnect and clean up. This
4634 * function updates our state and does the necessary notifications.
4635 * Also notifies our clients that the neighbour is now officially
4638 * @param n the neighbour list entry for the peer
4639 * @param check GNUNET_YES to check if ALL addresses for this peer
4640 * are gone, GNUNET_NO to force a disconnect of the peer
4641 * regardless of whether other addresses exist.
4644 disconnect_neighbour (struct NeighbourList *n, int check)
4646 struct ReadyList *rpos;
4647 struct NeighbourList *npos;
4648 struct NeighbourList *nprev;
4649 struct MessageQueue *mq;
4650 struct ForeignAddressList *peer_addresses;
4651 struct ForeignAddressList *peer_pos;
4653 if (GNUNET_YES == check)
4656 while (NULL != rpos)
4658 peer_addresses = rpos->addresses;
4659 while (peer_addresses != NULL)
4661 if (GNUNET_YES == peer_addresses->connected)
4663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4664 "NOT Disconnecting from `%4s', still have live addresses!\n",
4665 GNUNET_i2s (&n->id));
4666 return; /* still connected */
4668 peer_addresses = peer_addresses->next;
4674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4675 "Disconnecting from `%4s'\n",
4676 GNUNET_i2s (&n->id));
4678 /* remove n from neighbours list */
4681 while ((npos != NULL) && (npos != n))
4686 GNUNET_assert (npos != NULL);
4688 neighbours = n->next;
4690 nprev->next = n->next;
4692 /* notify all clients about disconnect */
4693 if (GNUNET_YES == n->received_pong)
4694 notify_clients_disconnect (&n->id);
4696 /* clean up all plugins, cancel connections and pending transmissions */
4697 while (NULL != (rpos = n->plugins))
4699 n->plugins = rpos->next;
4700 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4701 while (rpos->addresses != NULL)
4703 peer_pos = rpos->addresses;
4704 rpos->addresses = peer_pos->next;
4705 if (peer_pos->connected == GNUNET_YES)
4706 GNUNET_STATISTICS_update (stats,
4707 gettext_noop ("# connected addresses"),
4710 if (GNUNET_YES == peer_pos->validated)
4711 GNUNET_STATISTICS_update (stats,
4712 gettext_noop ("# peer addresses considered valid"),
4715 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4717 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4718 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4720 GNUNET_free(peer_pos->ressources);
4721 GNUNET_free(peer_pos->quality);
4722 GNUNET_free(peer_pos);
4727 /* free all messages on the queue */
4728 while (NULL != (mq = n->messages_head))
4730 GNUNET_STATISTICS_update (stats,
4731 gettext_noop ("# bytes in message queue for other peers"),
4732 - (int64_t) mq->message_buf_size,
4734 GNUNET_STATISTICS_update (stats,
4735 gettext_noop ("# bytes discarded due to disconnect"),
4736 mq->message_buf_size,
4738 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4741 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4743 sizeof(struct GNUNET_PeerIdentity)));
4746 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4748 GNUNET_SCHEDULER_cancel (n->timeout_task);
4749 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4751 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4753 GNUNET_SCHEDULER_cancel (n->retry_task);
4754 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4756 if (n->piter != NULL)
4758 GNUNET_PEERINFO_iterate_cancel (n->piter);
4759 GNUNET_STATISTICS_update (stats,
4760 gettext_noop ("# outstanding peerinfo iterate requests"),
4765 /* finally, free n itself */
4766 GNUNET_STATISTICS_update (stats,
4767 gettext_noop ("# active neighbours"),
4770 GNUNET_free_non_null (n->pre_connect_message_buffer);
4776 * We have received a PING message from someone. Need to send a PONG message
4777 * in response to the peer by any means necessary.
4780 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4781 const struct GNUNET_PeerIdentity *peer,
4782 struct Session *session,
4783 const char *sender_address,
4784 uint16_t sender_address_len)
4786 struct TransportPlugin *plugin = cls;
4787 struct SessionHeader *session_header = (struct SessionHeader*) session;
4788 struct TransportPingMessage *ping;
4789 struct TransportPongMessage *pong;
4790 struct NeighbourList *n;
4791 struct ReadyList *rl;
4792 struct ForeignAddressList *fal;
4793 struct OwnAddressList *oal;
4798 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4800 GNUNET_break_op (0);
4801 return GNUNET_SYSERR;
4804 ping = (struct TransportPingMessage *) message;
4805 if (0 != memcmp (&ping->target,
4806 plugin->env.my_identity,
4807 sizeof (struct GNUNET_PeerIdentity)))
4809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4810 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4812 (sender_address != NULL)
4813 ? a2s (plugin->short_name,
4814 (const struct sockaddr *)sender_address,
4817 GNUNET_i2s (&ping->target));
4818 return GNUNET_SYSERR;
4821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4822 "Processing `%s' from `%s'\n",
4824 (sender_address != NULL)
4825 ? a2s (plugin->short_name,
4826 (const struct sockaddr *)sender_address,
4830 GNUNET_STATISTICS_update (stats,
4831 gettext_noop ("# PING messages received"),
4834 addr = (const char*) &ping[1];
4835 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4836 slen = strlen (plugin->short_name) + 1;
4839 /* peer wants to confirm that we have an outbound connection to him */
4840 if (session == NULL)
4842 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4843 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4845 return GNUNET_SYSERR;
4847 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4848 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4849 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4850 pong->purpose.size =
4851 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4853 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4854 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4855 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4856 pong->challenge = ping->challenge;
4857 pong->addrlen = htonl(sender_address_len + slen);
4860 sizeof(struct GNUNET_PeerIdentity));
4864 if ((sender_address!=NULL) && (sender_address_len > 0))
4865 memcpy (&((char*)&pong[1])[slen],
4867 sender_address_len);
4868 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4870 /* create / update cached sig */
4872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4873 "Creating PONG signature to indicate active connection.\n");
4875 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4876 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4877 GNUNET_assert (GNUNET_OK ==
4878 GNUNET_CRYPTO_rsa_sign (my_private_key,
4880 &session_header->pong_signature));
4884 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4886 memcpy (&pong->signature,
4887 &session_header->pong_signature,
4888 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4894 /* peer wants to confirm that this is one of our addresses */
4898 plugin->api->check_address (plugin->api->cls,
4902 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4903 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4904 a2s (plugin->short_name,
4909 oal = plugin->addresses;
4912 if ( (oal->addrlen == alen) &&
4919 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4920 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4921 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4922 pong->purpose.size =
4923 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4925 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4926 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4927 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4928 pong->challenge = ping->challenge;
4929 pong->addrlen = htonl(alen + slen);
4932 sizeof(struct GNUNET_PeerIdentity));
4933 memcpy (&pong[1], plugin->short_name, slen);
4934 memcpy (&((char*)&pong[1])[slen], addr, alen);
4935 if ( (oal != NULL) &&
4936 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4938 /* create / update cached sig */
4940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4941 "Creating PONG signature to indicate ownership.\n");
4943 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4944 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4945 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4946 GNUNET_assert (GNUNET_OK ==
4947 GNUNET_CRYPTO_rsa_sign (my_private_key,
4949 &oal->pong_signature));
4950 memcpy (&pong->signature,
4951 &oal->pong_signature,
4952 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4954 else if (oal == NULL)
4956 /* not using cache (typically DV-only) */
4957 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4958 GNUNET_assert (GNUNET_OK ==
4959 GNUNET_CRYPTO_rsa_sign (my_private_key,
4965 /* can used cached version */
4966 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4967 memcpy (&pong->signature,
4968 &oal->pong_signature,
4969 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4972 n = find_neighbour(peer);
4973 GNUNET_assert (n != NULL);
4974 /* first try reliable response transmission */
4978 fal = rl->addresses;
4981 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4984 ntohs (pong->header.size),
4985 TRANSPORT_PONG_PRIORITY,
4986 HELLO_VERIFICATION_TIMEOUT,
4994 GNUNET_STATISTICS_update (stats,
4995 gettext_noop ("# PONGs unicast via reliable transport"),
5005 /* no reliable method found, do multicast */
5006 GNUNET_STATISTICS_update (stats,
5007 gettext_noop ("# PONGs multicast to all available addresses"),
5013 fal = rl->addresses;
5016 transmit_to_peer(NULL, fal,
5017 TRANSPORT_PONG_PRIORITY,
5018 HELLO_VERIFICATION_TIMEOUT,
5020 ntohs(pong->header.size),
5036 * Function called by the plugin for each received message.
5037 * Update data volumes, possibly notify plugins about
5038 * reducing the rate at which they read from the socket
5039 * and generally forward to our receive callback.
5041 * @param cls the "struct TransportPlugin *" we gave to the plugin
5042 * @param peer (claimed) identity of the other peer
5043 * @param message the message, NULL if we only care about
5044 * learning about the delay until we should receive again
5045 * @param ats_data information for automatic transport selection
5046 * @param ats_count number of elements in ats not including 0-terminator
5047 * @param session identifier used for this session (can be NULL)
5048 * @param sender_address binary address of the sender (if observed)
5049 * @param sender_address_len number of bytes in sender_address
5050 * @return how long in ms the plugin should wait until receiving more data
5051 * (plugins that do not support this, can ignore the return value)
5053 static struct GNUNET_TIME_Relative
5054 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5055 const struct GNUNET_MessageHeader *message,
5056 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5058 struct Session *session,
5059 const char *sender_address,
5060 uint16_t sender_address_len)
5062 struct TransportPlugin *plugin = cls;
5063 struct ReadyList *service_context;
5064 struct ForeignAddressList *peer_address;
5066 struct NeighbourList *n;
5067 struct GNUNET_TIME_Relative ret;
5068 if (is_blacklisted (peer, plugin))
5069 return GNUNET_TIME_UNIT_FOREVER_REL;
5073 n = find_neighbour (peer);
5075 n = setup_new_neighbour (peer, GNUNET_YES);
5076 service_context = n->plugins;
5077 while ((service_context != NULL) && (plugin != service_context->plugin))
5078 service_context = service_context->next;
5079 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5080 peer_address = NULL;
5083 for (c=0; c<ats_count; c++)
5085 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5087 distance = ntohl(ats_data[c].value);
5090 /* notify ATS about incoming data */
5091 //ats_notify_ats_data(peer, ats_data);
5093 if (message != NULL)
5095 if ( (session != NULL) ||
5096 (sender_address != NULL) )
5097 peer_address = add_peer_address (n,
5101 sender_address_len);
5102 if (peer_address != NULL)
5105 update_addr_ats(peer_address, ats_data, ats_count);
5106 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5108 peer_address->distance = distance;
5109 if (GNUNET_YES == peer_address->validated)
5110 mark_address_connected (peer_address);
5111 peer_address->timeout
5113 GNUNET_TIME_relative_to_absolute
5114 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5115 schedule_next_ping (peer_address);
5117 /* update traffic received amount ... */
5118 msize = ntohs (message->size);
5119 GNUNET_STATISTICS_update (stats,
5120 gettext_noop ("# bytes received from other peers"),
5123 n->distance = distance;
5125 GNUNET_TIME_relative_to_absolute
5126 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5127 GNUNET_SCHEDULER_cancel (n->timeout_task);
5129 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5130 &neighbour_timeout_task, n);
5131 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5133 /* dropping message due to frequent inbound volume violations! */
5134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5135 GNUNET_ERROR_TYPE_BULK,
5137 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5138 n->in_tracker.available_bytes_per_s__,
5139 n->quota_violation_count);
5140 GNUNET_STATISTICS_update (stats,
5141 gettext_noop ("# bandwidth quota violations by other peers"),
5144 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5149 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5150 ntohs (message->type),
5151 ntohs (message->size),
5154 switch (ntohs (message->type))
5156 case GNUNET_MESSAGE_TYPE_HELLO:
5157 GNUNET_STATISTICS_update (stats,
5158 gettext_noop ("# HELLO messages received from other peers"),
5161 process_hello (plugin, message);
5163 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5164 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5166 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5167 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5170 handle_payload_message (message, n);
5174 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5175 if (ret.rel_value > 0)
5177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5178 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5179 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5180 (unsigned int) n->in_tracker.available_bytes_per_s__,
5181 (unsigned long long) ret.rel_value);
5182 GNUNET_STATISTICS_update (stats,
5183 gettext_noop ("# ms throttling suggested"),
5184 (int64_t) ret.rel_value,
5191 * Handle START-message. This is the first message sent to us
5192 * by any client which causes us to add it to our list.
5194 * @param cls closure (always NULL)
5195 * @param client identification of the client
5196 * @param message the actual message
5199 handle_start (void *cls,
5200 struct GNUNET_SERVER_Client *client,
5201 const struct GNUNET_MessageHeader *message)
5203 const struct StartMessage *start;
5204 struct TransportClient *c;
5205 struct ConnectInfoMessage * cim;
5206 struct NeighbourList *n;
5210 start = (const struct StartMessage*) message;
5212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5213 "Received `%s' request from client\n", "START");
5218 if (c->client == client)
5220 /* client already on our list! */
5222 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5227 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5228 (0 != memcmp (&start->self,
5230 sizeof (struct GNUNET_PeerIdentity))) )
5232 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5233 _("Rejecting control connection from peer `%s', which is not me!\n"),
5234 GNUNET_i2s (&start->self));
5235 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5238 c = GNUNET_malloc (sizeof (struct TransportClient));
5242 if (our_hello != NULL)
5245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5246 "Sending our own `%s' to new client\n", "HELLO");
5248 transmit_to_client (c,
5249 (const struct GNUNET_MessageHeader *) our_hello,
5251 /* tell new client about all existing connections */
5253 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5254 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5258 cim = GNUNET_malloc (size);
5259 cim->header.size = htons (size);
5260 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5261 cim->ats_count = htonl(ats_count);
5262 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5263 (&(cim->ats))[2].value = htonl (0);
5267 if (GNUNET_YES == n->received_pong)
5269 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5270 (&(cim->ats))[0].value = htonl (n->distance);
5271 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5272 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5274 transmit_to_client (c, &cim->header, GNUNET_NO);
5280 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5285 * Handle HELLO-message.
5287 * @param cls closure (always NULL)
5288 * @param client identification of the client
5289 * @param message the actual message
5292 handle_hello (void *cls,
5293 struct GNUNET_SERVER_Client *client,
5294 const struct GNUNET_MessageHeader *message)
5298 GNUNET_STATISTICS_update (stats,
5299 gettext_noop ("# HELLOs received from clients"),
5302 ret = process_hello (NULL, message);
5303 GNUNET_SERVER_receive_done (client, ret);
5308 * Closure for 'transmit_client_message'; followed by
5309 * 'msize' bytes of the actual message.
5311 struct TransmitClientMessageContext
5314 * Client on whom's behalf we are sending.
5316 struct GNUNET_SERVER_Client *client;
5319 * Timeout for the transmission.
5321 struct GNUNET_TIME_Absolute timeout;
5329 * Size of the message in bytes.
5336 * Schedule transmission of a message we got from a client to a peer.
5338 * @param cls the 'struct TransmitClientMessageContext*'
5339 * @param n destination, or NULL on error (in that case, drop the message)
5342 transmit_client_message (void *cls,
5343 struct NeighbourList *n)
5345 struct TransmitClientMessageContext *tcmc = cls;
5346 struct TransportClient *tc;
5349 while ((tc != NULL) && (tc->client != tcmc->client))
5354 transmit_to_peer (tc, NULL, tcmc->priority,
5355 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5357 tcmc->msize, GNUNET_NO, n);
5359 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5360 GNUNET_SERVER_client_drop (tcmc->client);
5366 * Handle SEND-message.
5368 * @param cls closure (always NULL)
5369 * @param client identification of the client
5370 * @param message the actual message
5373 handle_send (void *cls,
5374 struct GNUNET_SERVER_Client *client,
5375 const struct GNUNET_MessageHeader *message)
5377 const struct OutboundMessage *obm;
5378 const struct GNUNET_MessageHeader *obmm;
5379 struct TransmitClientMessageContext *tcmc;
5383 size = ntohs (message->size);
5385 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5388 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5391 GNUNET_STATISTICS_update (stats,
5392 gettext_noop ("# payload received for other peers"),
5395 obm = (const struct OutboundMessage *) message;
5396 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5397 msize = size - sizeof (struct OutboundMessage);
5399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5400 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5401 "SEND", GNUNET_i2s (&obm->peer),
5405 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5406 tcmc->client = client;
5407 tcmc->priority = ntohl (obm->priority);
5408 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5409 tcmc->msize = msize;
5410 /* FIXME: this memcpy can be up to 7% of our total runtime */
5411 memcpy (&tcmc[1], obmm, msize);
5412 GNUNET_SERVER_client_keep (client);
5413 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5414 &transmit_client_message,
5420 * Handle request connect message
5422 * @param cls closure (always NULL)
5423 * @param client identification of the client
5424 * @param message the actual message
5427 handle_request_connect (void *cls,
5428 struct GNUNET_SERVER_Client *client,
5429 const struct GNUNET_MessageHeader *message)
5431 const struct TransportRequestConnectMessage *trcm =
5432 (const struct TransportRequestConnectMessage *) message;
5434 GNUNET_STATISTICS_update (stats,
5435 gettext_noop ("# REQUEST CONNECT messages received"),
5438 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5439 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5441 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5445 * Handle SET_QUOTA-message.
5447 * @param cls closure (always NULL)
5448 * @param client identification of the client
5449 * @param message the actual message
5452 handle_set_quota (void *cls,
5453 struct GNUNET_SERVER_Client *client,
5454 const struct GNUNET_MessageHeader *message)
5456 const struct QuotaSetMessage *qsm =
5457 (const struct QuotaSetMessage *) message;
5458 struct NeighbourList *n;
5460 GNUNET_STATISTICS_update (stats,
5461 gettext_noop ("# SET QUOTA messages received"),
5464 n = find_neighbour (&qsm->peer);
5467 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5468 GNUNET_STATISTICS_update (stats,
5469 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5476 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5478 (unsigned int) ntohl (qsm->quota.value__),
5479 (unsigned int) n->in_tracker.available_bytes_per_s__,
5480 GNUNET_i2s (&qsm->peer));
5482 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5484 if (0 == ntohl (qsm->quota.value__))
5486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5487 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5489 disconnect_neighbour (n, GNUNET_NO);
5491 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5496 * Take the given address and append it to the set of results sent back to
5499 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5500 * @param address the resolved name, NULL to indicate the last response
5503 transmit_address_to_client (void *cls, const char *address)
5505 struct GNUNET_SERVER_TransmitContext *tc = cls;
5508 if (NULL == address)
5511 slen = strlen (address) + 1;
5513 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5514 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5515 if (NULL == address)
5516 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5521 * Handle AddressLookup-message.
5523 * @param cls closure (always NULL)
5524 * @param client identification of the client
5525 * @param message the actual message
5528 handle_address_lookup (void *cls,
5529 struct GNUNET_SERVER_Client *client,
5530 const struct GNUNET_MessageHeader *message)
5532 const struct AddressLookupMessage *alum;
5533 struct TransportPlugin *lsPlugin;
5534 const char *nameTransport;
5535 const char *address;
5537 struct GNUNET_SERVER_TransmitContext *tc;
5538 struct GNUNET_TIME_Absolute timeout;
5539 struct GNUNET_TIME_Relative rtimeout;
5542 size = ntohs (message->size);
5543 if (size < sizeof (struct AddressLookupMessage))
5545 GNUNET_break_op (0);
5546 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5549 alum = (const struct AddressLookupMessage *) message;
5550 uint32_t addressLen = ntohl (alum->addrlen);
5551 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5553 GNUNET_break_op (0);
5554 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5557 address = (const char *) &alum[1];
5558 nameTransport = (const char *) &address[addressLen];
5560 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5562 GNUNET_break_op (0);
5563 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5566 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5567 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5568 numeric = ntohl (alum->numeric_only);
5569 lsPlugin = find_transport (nameTransport);
5570 if (NULL == lsPlugin)
5572 tc = GNUNET_SERVER_transmit_context_create (client);
5573 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5574 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5575 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5578 tc = GNUNET_SERVER_transmit_context_create (client);
5579 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5581 address, addressLen,
5584 &transmit_address_to_client, tc);
5589 * Setup the environment for this plugin.
5592 create_environment (struct TransportPlugin *plug)
5594 plug->env.cfg = cfg;
5595 plug->env.my_identity = &my_identity;
5596 plug->env.our_hello = &our_hello;
5597 plug->env.cls = plug;
5598 plug->env.receive = &plugin_env_receive;
5599 plug->env.notify_address = &plugin_env_notify_address;
5600 plug->env.session_end = &plugin_env_session_end;
5601 plug->env.max_connections = max_connect_per_transport;
5602 plug->env.stats = stats;
5607 * Start the specified transport (load the plugin).
5610 start_transport (struct GNUNET_SERVER_Handle *server,
5613 struct TransportPlugin *plug;
5616 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5617 _("Loading `%s' transport plugin\n"), name);
5618 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5619 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5620 create_environment (plug);
5621 plug->short_name = GNUNET_strdup (name);
5622 plug->lib_name = libname;
5623 plug->next = plugins;
5625 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5626 if (plug->api == NULL)
5628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5629 _("Failed to load transport plugin for `%s'\n"), name);
5630 GNUNET_free (plug->short_name);
5631 plugins = plug->next;
5632 GNUNET_free (libname);
5639 * Called whenever a client is disconnected. Frees our
5640 * resources associated with that client.
5642 * @param cls closure
5643 * @param client identification of the client
5646 client_disconnect_notification (void *cls,
5647 struct GNUNET_SERVER_Client *client)
5649 struct TransportClient *pos;
5650 struct TransportClient *prev;
5651 struct ClientMessageQueueEntry *mqe;
5652 struct Blacklisters *bl;
5653 struct BlacklistCheck *bc;
5658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5659 "Client disconnected, cleaning up.\n");
5661 /* clean up blacklister */
5665 if (bl->client == client)
5670 if (bc->bl_pos == bl)
5672 bc->bl_pos = bl->next;
5675 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5678 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5679 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5685 GNUNET_CONTAINER_DLL_remove (bl_head,
5688 GNUNET_SERVER_client_drop (bl->client);
5694 /* clean up 'normal' clients */
5697 while ((pos != NULL) && (pos->client != client))
5704 while (NULL != (mqe = pos->message_queue_head))
5706 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5707 pos->message_queue_tail,
5709 pos->message_count--;
5713 clients = pos->next;
5715 prev->next = pos->next;
5716 if (GNUNET_YES == pos->tcs_pending)
5721 if (pos->th != NULL)
5723 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5726 GNUNET_break (0 == pos->message_count);
5732 * Function called when the service shuts down. Unloads our plugins
5733 * and cancels pending validations.
5735 * @param cls closure, unused
5736 * @param tc task context (unused)
5739 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5741 struct TransportPlugin *plug;
5742 struct OwnAddressList *al;
5743 struct CheckHelloValidatedContext *chvc;
5745 while (neighbours != NULL)
5747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5748 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5750 disconnect_neighbour (neighbours, GNUNET_NO);
5753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5754 "Transport service is unloading plugins...\n");
5756 while (NULL != (plug = plugins))
5758 plugins = plug->next;
5759 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5761 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5762 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5764 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5765 GNUNET_free (plug->lib_name);
5766 GNUNET_free (plug->short_name);
5767 while (NULL != (al = plug->addresses))
5769 plug->addresses = al->next;
5774 if (my_private_key != NULL)
5775 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5776 GNUNET_free_non_null (our_hello);
5778 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5781 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5782 validation_map = NULL;
5786 /* free 'chvc' data structure */
5787 while (NULL != (chvc = chvc_head))
5789 chvc_head = chvc->next;
5790 if (chvc->piter != NULL)
5792 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5793 GNUNET_STATISTICS_update (stats,
5794 gettext_noop ("# outstanding peerinfo iterate requests"),
5800 GNUNET_assert (chvc->ve_count == 0);
5807 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5810 if (peerinfo != NULL)
5812 GNUNET_PEERINFO_disconnect (peerinfo);
5815 /* Can we assume those are gone by now, or do we need to clean up
5817 GNUNET_break (bl_head == NULL);
5818 GNUNET_break (bc_head == NULL);
5822 static int ats_evaluate_results (int result, int solution, char * problem)
5824 int cont = GNUNET_NO;
5825 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5827 error_kind = GNUNET_ERROR_TYPE_ERROR;
5831 case GLP_ESTOP : /* search terminated by application */
5832 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5834 case GLP_EITLIM : /* iteration limit exceeded */
5835 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5838 case GLP_ETMLIM : /* time limit exceeded */
5839 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5841 case GLP_ENOPFS : /* no primal feasible solution */
5842 case GLP_ENODFS : /* no dual feasible solution */
5843 GNUNET_log (error_kind, "%s No feasible solution", problem);
5846 case GLP_EBADB : /* invalid basis */
5847 case GLP_ESING : /* singular matrix */
5848 case GLP_ECOND : /* ill-conditioned matrix */
5849 case GLP_EBOUND : /* invalid bounds */
5850 case GLP_EFAIL : /* solver failed */
5851 case GLP_EOBJLL : /* objective lower limit reached */
5852 case GLP_EOBJUL : /* objective upper limit reached */
5853 case GLP_EROOT : /* root LP optimum not provided */
5854 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5858 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5864 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
5867 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
5871 GNUNET_log (error_kind, "%s solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n", problem);
5875 GNUNET_log (error_kind, "%s problem has no integer feasible solution\n", problem);
5886 static void ats_solve_problem (unsigned int max_it, unsigned int max_dur, unsigned int c_peers, unsigned int c_mechs, struct ATS_result *res)
5892 glp_prob *prob = ats->prob;
5895 glp_init_smcp(&opt_lp);
5897 opt_lp.msg_lev = GLP_MSG_ALL;
5899 opt_lp.msg_lev = GLP_MSG_OFF;
5901 //opt_lp.presolve = GLP_ON;
5902 result = glp_simplex(prob, &opt_lp);
5903 solution = glp_get_status (prob);
5905 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
5909 glp_init_iocp(&opt_mlp);
5910 /* maximum duration */
5911 //opt_mlp.presolve = GLP_ON;
5912 opt_mlp.tm_lim = max_dur;
5915 opt_mlp.msg_lev = GLP_MSG_ALL;
5917 opt_mlp.msg_lev = GLP_MSG_OFF;
5919 result = glp_intopt (prob, &opt_mlp);
5920 solution = glp_mip_status (prob);
5921 res->solution = solution;
5922 res->valid = GNUNET_NO;
5923 if (ats_evaluate_results(result, solution, "MLP") == GNUNET_YES)
5924 res->valid = GNUNET_YES;
5928 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
5931 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5932 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5933 glp_write_lp (prob, NULL, filename);
5934 GNUNET_free (filename);
5936 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
5939 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
5940 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
5941 glp_print_sol (prob, filename);
5942 GNUNET_free (filename);
5947 int error = GNUNET_NO;
5949 struct ATS_mechanism *t = NULL;
5950 for (c=1; c<= (c_peers); c++ )
5953 t = peers[c].m_head;
5956 bw = glp_get_col_prim(prob, t->col_index);
5960 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);
5962 if (check ==GNUNET_YES)
5964 glp_write_sol(prob, "invalid_solution.mlp");
5965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
5966 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
5969 if (check ==GNUNET_NO)
5977 for (c=1; c<= available_quality_metrics; c++ )
5979 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));
5981 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));
5982 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));
5983 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));
5990 /** solve the bandwidth distribution problem
5991 * @param max_it maximum iterations
5992 * @param max_dur maximum duration in ms
5993 * @param D weight for diversity
5994 * @param U weight for utility
5995 * @param R weight for relativity
5996 * @param v_b_min minimal bandwidth per peer
5997 * @param v_n_min minimum number of connections
5998 * @param res result struct
5999 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6001 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
6004 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
6005 return GNUNET_SYSERR;
6008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
6011 if (ats->prob != NULL)
6012 glp_delete_prob(ats->prob);
6014 ats->prob = glp_create_prob();
6020 int c_c_ressources = available_ressources;
6021 int c_q_metrics = available_quality_metrics;
6023 double M = VERY_BIG_DOUBLE_VALUE;
6024 double Q[c_q_metrics+1];
6025 for (c=1; c<=c_q_metrics; c++)
6030 struct NeighbourList *next = neighbours;
6033 struct ReadyList *r_next = next->plugins;
6034 while (r_next != NULL)
6036 struct ForeignAddressList * a_next = r_next->addresses;
6037 while (a_next != NULL)
6040 a_next = a_next->next;
6042 r_next = r_next->next;
6051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6053 res->valid = GNUNET_NO;
6054 return GNUNET_SYSERR;
6057 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6058 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6065 peers[c_peers].peer = next->id;
6066 peers[c_peers].m_head = NULL;
6067 peers[c_peers].m_tail = NULL;
6069 peers[c_peers].f = 1.0 / c_mechs;
6071 struct ReadyList *r_next = next->plugins;
6072 while (r_next != NULL)
6074 struct ForeignAddressList * a_next = r_next->addresses;
6075 while (a_next != NULL)
6077 mechanisms[c_mechs].addr = a_next;
6078 mechanisms[c_mechs].col_index = c_mechs;
6079 mechanisms[c_mechs].peer = &peers[c_peers];
6080 mechanisms[c_mechs].next = NULL;
6081 mechanisms[c_mechs].plugin = r_next->plugin;
6083 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6085 a_next = a_next->next;
6087 r_next = r_next->next;
6095 if (v_n_min > c_peers)
6099 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);
6102 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6105 int * ia = GNUNET_malloc (size * sizeof (int));
6106 int * ja = GNUNET_malloc (size * sizeof (int));
6107 double * ar = GNUNET_malloc(size* sizeof (double));
6109 glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6110 glp_set_obj_dir(ats->prob, GLP_MAX);
6112 /* adding columns */
6114 glp_add_cols(ats->prob, 2 * c_mechs);
6115 /* adding b_t cols */
6116 for (c=1; c <= c_mechs; c++)
6119 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6120 glp_set_col_name(ats->prob, c, name);
6122 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6123 glp_set_obj_coef(ats->prob, c, 1);
6126 /* adding n_t cols */
6127 for (c=c_mechs+1; c <= 2*c_mechs; c++)
6129 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6130 glp_set_col_name(ats->prob, c, name);
6132 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6133 glp_set_col_kind(ats->prob, c, GLP_IV);
6134 glp_set_obj_coef(ats->prob, c, 0);
6137 /* feasibility constraints */
6138 /* Constraint 1: one address per peer*/
6140 glp_add_rows(ats->prob, c_peers);
6141 for (c=1; c<=c_peers; c++)
6143 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6145 struct ATS_mechanism *m = peers[c].m_head;
6148 ia[array_index] = row_index;
6149 ja[array_index] = (c_mechs + m->col_index);
6150 ar[array_index] = 1;
6152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6160 /* Constraint 2: only active mechanism gets bandwidth assigned */
6161 glp_add_rows(ats->prob, c_mechs);
6162 for (c=1; c<=c_mechs; c++)
6164 /* b_t - n_t * M <= 0 */
6166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6168 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6170 ia[array_index] = row_index;
6171 ja[array_index] = mechanisms[c].col_index;
6172 ar[array_index] = 1;
6174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6177 ia[array_index] = row_index;
6178 ja[array_index] = c_mechs + mechanisms[c].col_index;
6179 ar[array_index] = -M;
6181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6187 /* Constraint 3: minimum bandwidth*/
6188 glp_add_rows(ats->prob, c_mechs);
6189 for (c=1; c<=c_mechs; c++)
6191 /* b_t - n_t * b_min <= 0 */
6193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6195 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6197 ia[array_index] = row_index;
6198 ja[array_index] = mechanisms[c].col_index;
6199 ar[array_index] = 1;
6201 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6204 ia[array_index] = row_index;
6205 ja[array_index] = c_mechs + mechanisms[c].col_index;
6206 ar[array_index] = -v_b_min;
6208 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6214 /* Constraint 4: max ressource capacity */
6215 /* V cr: bt * ct_r <= cr_max
6217 glp_add_rows(ats->prob, available_ressources);
6218 double ct_max = VERY_BIG_DOUBLE_VALUE;
6219 double ct_min = 0.0;
6221 res->begin_cr = array_index;
6223 for (c=0; c<available_ressources; c++)
6225 ct_max = ressources[c].c_max;
6226 ct_min = ressources[c].c_min;
6228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6230 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6232 for (c2=1; c2<=c_mechs; c2++)
6235 ia[array_index] = row_index;
6236 ja[array_index] = c2;
6237 value = mechanisms[c2].addr->ressources[c].c;
6238 ar[array_index] = value;
6240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6246 res->end_cr = array_index--;
6248 /* Constraint 5: min number of connections*/
6249 glp_add_rows(ats->prob, 1);
6250 for (c=1; c<=c_mechs; c++)
6252 // b_t - n_t * b_min >= 0
6254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6256 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6258 ia[array_index] = row_index;
6259 ja[array_index] = c_mechs + mechanisms[c].col_index;
6260 ar[array_index] = 1;
6262 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6268 /* optimisation constraints*/
6270 /* adding columns */
6271 glp_add_cols(ats->prob, 3 + c_q_metrics);
6273 glp_set_col_name(ats->prob, (2*c_mechs) + 1, "d");
6274 glp_set_obj_coef(ats->prob, (2*c_mechs) + 1, D);
6275 glp_set_col_bnds(ats->prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6276 glp_set_col_name(ats->prob, (2*c_mechs) + 2, "u");
6277 glp_set_obj_coef(ats->prob, (2*c_mechs) + 2, U);
6278 glp_set_col_bnds(ats->prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6279 glp_set_col_name(ats->prob, (2*c_mechs) + 3, "r");
6280 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3, R);
6281 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6283 for (c=1; c<= c_q_metrics; c++)
6285 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6286 glp_set_col_name(ats->prob, (2*c_mechs) + 3 + c, name);
6287 glp_set_col_bnds(ats->prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6289 glp_set_obj_coef(ats->prob, (2*c_mechs) + 3 + c, Q[c]);
6292 // Constraint 6: optimize for diversity
6293 glp_add_rows(ats->prob, 1);
6295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6297 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6298 for (c=1; c<=c_mechs; c++)
6300 // b_t - n_t * b_min >= 0
6301 ia[array_index] = row_index;
6302 ja[array_index] = c_mechs + mechanisms[c].col_index;
6303 ar[array_index] = 1;
6305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6309 ia[array_index] = row_index;
6310 ja[array_index] = (2*c_mechs) + 1;
6311 ar[array_index] = -1;
6313 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6319 // Constraint 7: optimize for quality
6320 glp_add_rows(ats->prob, available_quality_metrics);
6321 res->begin_qm = array_index;
6322 for (c=1; c <= c_q_metrics; c++)
6325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6327 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6329 for (c2=1; c2<=c_mechs; c2++)
6332 ia[array_index] = row_index;
6333 ja[array_index] = c2;
6334 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6337 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6338 if (v1 < 1) v0 = 0.1;
6339 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6340 if (v1 < 1) v0 = 0.1;
6341 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6342 if (v1 < 1) v0 = 0.1;
6343 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6345 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6348 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6350 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6352 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6354 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6356 value = (double) 10 / value;
6360 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6362 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]);
6367 ia[array_index] = row_index;
6368 ja[array_index] = (2*c_mechs) + 3 +c;
6369 ar[array_index] = -1;
6371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6376 res->end_qm = array_index--;
6378 // Constraint 8: optimize bandwidth utility
6379 glp_add_rows(ats->prob, 1);
6381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6383 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6384 for (c=1; c<=c_mechs; c++)
6386 ia[array_index] = row_index;
6387 ja[array_index] = c;
6388 ar[array_index] = mechanisms[c].peer->f;
6390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6394 ia[array_index] = row_index;
6395 ja[array_index] = (2*c_mechs) + 2;
6396 ar[array_index] = -1;
6398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6404 // Constraint 9: optimize relativity
6405 glp_add_rows(ats->prob, c_peers);
6406 for (c=1; c<=c_peers; c++)
6408 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6410 struct ATS_mechanism *m = peers[c].m_head;
6413 ia[array_index] = row_index;
6414 ja[array_index] = m->col_index;
6415 ar[array_index] = 1;
6417 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6422 ia[array_index] = row_index;
6423 ja[array_index] = (2*c_mechs) + 3;
6424 ar[array_index] = -1;
6426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6432 /* Loading the matrix */
6433 glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6435 res->c_mechs = c_mechs;
6436 res->c_peers = c_peers;
6438 res->valid = GNUNET_YES;
6446 for (c=0; c<c_mechs; c++)
6447 GNUNET_free_non_null (mechanisms[c].rc);
6449 GNUNET_free(mechanisms);
6456 void ats_calculate_bandwidth_distribution ()
6459 struct GNUNET_TIME_Absolute start;
6460 struct GNUNET_TIME_Relative duration;
6462 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6463 if (delta.rel_value < ats->min_delta.rel_value)
6466 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6472 if (INT_MAX < ats->max_exec_duration.rel_value)
6475 dur = (int) ats->max_exec_duration.rel_value;
6479 start = GNUNET_TIME_absolute_get();
6480 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... have to recreate problem\n");
6485 ats->modified_addr = GNUNET_NO;
6486 ats->res.c_mechs = 0;
6487 ats->res.c_peers = 0;
6488 ats->res.solution = 0;
6489 ats->res.valid = GNUNET_NO;
6490 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->res);
6492 else if (ats->modified_resources)
6494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "RESSOURCE...modified problem\n");
6497 else if (ats->modified_quality)
6499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "RESSOURCE...quality problem\n");
6503 else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6506 if (ats->res.valid == GNUNET_YES)
6508 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->res.c_peers, ats->res.c_mechs, &ats->res);
6511 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6513 if ((ats->res.valid == GNUNET_YES))
6516 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu %llu \n", res, duration.rel_value, ats->res.solution);
6518 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6519 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->res.c_mechs, GNUNET_NO);
6520 GNUNET_STATISTICS_set (stats, "ATS peers", ats->res.c_peers, GNUNET_NO);
6521 GNUNET_STATISTICS_set (stats, "ATS solution", ats->res.solution, GNUNET_NO);
6522 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6527 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6530 ats->last = GNUNET_TIME_absolute_get();
6532 ats->modified_addr = GNUNET_NO;
6533 ats->modified_resources = GNUNET_NO;
6534 ats->modified_quality = GNUNET_NO;
6542 ats_schedule_calculation (void *cls,
6543 const struct GNUNET_SCHEDULER_TaskContext *tc)
6545 struct ATS_info *ats = (struct ATS_info *) cls;
6549 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6550 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6557 ats_calculate_bandwidth_distribution (ats);
6559 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6560 &ats_schedule_calculation, ats);
6565 ats = GNUNET_malloc(sizeof (struct ATS_info));
6567 ats->min_delta = ATS_MIN_INTERVAL;
6568 ats->exec_intervall = ATS_EXEC_INTERVAL;
6569 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6570 ats->max_iterations = ATS_MAX_ITERATIONS;
6571 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6574 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active");
6581 ats->v_b_min = 64000;
6588 unsigned long long value;
6590 /* loading cost ressources */
6591 for (c=0; c<available_ressources; c++)
6593 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6594 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6596 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6599 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6601 ressources[c].c_max = value;
6604 GNUNET_free (section);
6605 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6606 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6608 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6613 ressources[c].c_min = value;
6616 GNUNET_free (section);
6619 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6620 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6622 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6623 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6625 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6629 static void ats_shutdown ()
6632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6634 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6635 GNUNET_SCHEDULER_cancel(ats->ats_task);
6636 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6638 if (ats->prob != NULL)
6640 glp_delete_prob(ats->prob);
6648 void ats_notify_peer_connect (
6649 const struct GNUNET_PeerIdentity *peer,
6650 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6656 while (ntohl(ats_data[c].type)!=0)
6659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6664 ats->modified_addr = GNUNET_YES;
6666 ats_calculate_bandwidth_distribution(ats);
6669 void ats_notify_peer_disconnect (
6670 const struct GNUNET_PeerIdentity *peer)
6673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6676 ats->modified_addr = GNUNET_YES;
6678 ats_calculate_bandwidth_distribution (ats);
6682 void ats_notify_ats_data (
6683 const struct GNUNET_PeerIdentity *peer,
6684 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6687 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6689 ats_calculate_bandwidth_distribution(ats);
6693 struct ForeignAddressList * ats_get_preferred_address (
6694 struct NeighbourList *n)
6697 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6699 struct ReadyList *next = n->plugins;
6700 while (next != NULL)
6703 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6707 return find_ready_address(n);
6711 * Initiate transport service.
6713 * @param cls closure
6714 * @param server the initialized server
6715 * @param c configuration to use
6719 struct GNUNET_SERVER_Handle *server,
6720 const struct GNUNET_CONFIGURATION_Handle *c)
6722 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6723 {&handle_start, NULL,
6724 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6725 {&handle_hello, NULL,
6726 GNUNET_MESSAGE_TYPE_HELLO, 0},
6727 {&handle_send, NULL,
6728 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6729 {&handle_request_connect, NULL,
6730 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6731 {&handle_set_quota, NULL,
6732 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6733 {&handle_address_lookup, NULL,
6734 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6736 {&handle_blacklist_init, NULL,
6737 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6738 {&handle_blacklist_reply, NULL,
6739 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6745 unsigned long long tneigh;
6749 stats = GNUNET_STATISTICS_create ("transport", cfg);
6750 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6751 /* parse configuration */
6753 GNUNET_CONFIGURATION_get_value_number (c,
6758 GNUNET_CONFIGURATION_get_value_filename (c,
6760 "HOSTKEY", &keyfile)))
6762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6764 ("Transport service is lacking key configuration settings. Exiting.\n"));
6765 GNUNET_SCHEDULER_shutdown ();
6768 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6771 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6772 validation_map = NULL;
6776 max_connect_per_transport = (uint32_t) tneigh;
6777 peerinfo = GNUNET_PEERINFO_connect (cfg);
6778 if (peerinfo == NULL)
6780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6781 _("Could not access PEERINFO service. Exiting.\n"));
6782 GNUNET_SCHEDULER_shutdown ();
6785 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6788 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6789 validation_map = NULL;
6790 GNUNET_free (keyfile);
6793 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6794 GNUNET_free (keyfile);
6795 if (my_private_key == NULL)
6797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6799 ("Transport service could not access hostkey. Exiting.\n"));
6800 GNUNET_SCHEDULER_shutdown ();
6803 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6806 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6807 validation_map = NULL;
6810 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6811 GNUNET_CRYPTO_hash (&my_public_key,
6812 sizeof (my_public_key), &my_identity.hashPubKey);
6813 /* setup notification */
6814 GNUNET_SERVER_disconnect_notify (server,
6815 &client_disconnect_notification, NULL);
6816 /* load plugins... */
6819 GNUNET_CONFIGURATION_get_value_string (c,
6820 "TRANSPORT", "PLUGINS", &plugs))
6822 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6823 _("Starting transport plugins `%s'\n"), plugs);
6824 pos = strtok (plugs, " ");
6827 start_transport (server, pos);
6829 pos = strtok (NULL, " ");
6831 GNUNET_free (plugs);
6833 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6834 &shutdown_task, NULL);
6841 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6843 /* If we have a blacklist file, read from it */
6844 read_blacklist_file(cfg);
6845 /* process client requests */
6846 GNUNET_SERVER_add_handlers (server, handlers);
6851 * The main function for the transport service.
6853 * @param argc number of arguments from the command line
6854 * @param argv command line arguments
6855 * @return 0 ok, 1 on error
6858 main (int argc, char *const *argv)
6860 a2s (NULL, NULL, 0); /* make compiler happy */
6861 return (GNUNET_OK ==
6862 GNUNET_SERVICE_run (argc,
6865 GNUNET_SERVICE_OPTION_NONE,
6866 &run, NULL)) ? 0 : 1;
6869 /* end of gnunet-service-transport.c */