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
52 * Should we do some additional checks (to validate behavior
55 #define EXTRA_CHECKS GNUNET_YES
58 * How many messages can we have pending for a given client process
59 * before we start to drop incoming messages? We typically should
60 * have only one client and so this would be the primary buffer for
61 * messages, so the number should be chosen rather generously.
63 * The expectation here is that most of the time the queue is large
64 * enough so that a drop is virtually never required. Note that
65 * this value must be about as large as 'TOTAL_MSGS' in the
66 * 'test_transport_api_reliability.c', otherwise that testcase may
69 #define MAX_PENDING (128 * 1024)
72 * Size of the per-transport blacklist hash maps.
74 #define TRANSPORT_BLACKLIST_HT_SIZE 16
77 * How often should we try to reconnect to a peer using a particular
78 * transport plugin before giving up? Note that the plugin may be
79 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
81 #define MAX_CONNECT_RETRY 3
84 * Limit on the number of ready-to-run tasks when validating
85 * HELLOs. If more tasks are ready to run, we will drop
86 * HELLOs instead of validating them.
88 #define MAX_HELLO_LOAD 4
91 * How often must a peer violate bandwidth quotas before we start
92 * to simply drop its messages?
94 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
97 * How long until a HELLO verification attempt should time out?
98 * Must be rather small, otherwise a partially successful HELLO
99 * validation (some addresses working) might not be available
100 * before a client's request for a connection fails for good.
101 * Besides, if a single request to an address takes a long time,
102 * then the peer is unlikely worthwhile anyway.
104 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
107 * How long is a PONG signature valid? We'll recycle a signature until
108 * 1/4 of this time is remaining. PONGs should expire so that if our
109 * external addresses change an adversary cannot replay them indefinitely.
110 * OTOH, we don't want to spend too much time generating PONG signatures,
111 * so they must have some lifetime to reduce our CPU usage.
113 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
116 * Priority to use for PONG messages.
118 #define TRANSPORT_PONG_PRIORITY 4
121 * How often do we re-add (cheaper) plugins to our list of plugins
122 * to try for a given connected peer?
124 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
127 * After how long do we expire an address in a HELLO that we just
128 * validated? This value is also used for our own addresses when we
131 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
135 * How long before an existing address expires should we again try to
136 * validate it? Must be (significantly) smaller than
137 * HELLO_ADDRESS_EXPIRATION.
139 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
142 * Maximum frequency for re-evaluating latencies for all transport addresses.
144 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
147 * Maximum frequency for re-evaluating latencies for connected addresses.
149 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
151 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
154 * List of addresses of other peers
156 struct ForeignAddressList
159 * This is a linked list.
161 struct ForeignAddressList *next;
164 * Which ready list does this entry belong to.
166 struct ReadyList *ready_list;
169 * How long until we auto-expire this address (unless it is
170 * re-confirmed by the transport)?
172 struct GNUNET_TIME_Absolute expires;
175 * Task used to re-validate addresses, updates latencies and
178 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
186 * Session (or NULL if no valid session currently exists or if the
187 * plugin does not use sessions).
189 struct Session *session;
191 struct ATS_ressource_cost * ressources;
194 * What was the last latency observed for this address, plugin and peer?
196 struct GNUNET_TIME_Relative latency;
199 * If we did not successfully transmit a message to the given peer
200 * via this connection during the specified time, we should consider
201 * the connection to be dead. This is used in the case that a TCP
202 * transport simply stalls writing to the stream but does not
203 * formerly get a signal that the other peer died.
205 struct GNUNET_TIME_Absolute timeout;
208 * How often have we tried to connect using this plugin? Used to
209 * discriminate against addresses that do not work well.
210 * FIXME: not yet used, but should be!
212 unsigned int connect_attempts;
215 * DV distance to this peer (1 if no DV is used).
216 * FIXME: need to set this from transport plugins!
226 * Have we ever estimated the latency of this address? Used to
227 * ensure that the first time we add an address, we immediately
233 * Are we currently connected via this address? The first time we
234 * successfully transmit or receive data to a peer via a particular
235 * address, we set this to GNUNET_YES. If we later get an error
236 * (disconnect notification, transmission failure, timeout), we set
237 * it back to GNUNET_NO.
242 * Is this plugin currently busy transmitting to the specific target?
243 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
244 * messages do not count as 'in transmit'.
249 * Has this address been validated yet?
257 * Entry in linked list of network addresses for ourselves. Also
258 * includes a cached signature for 'struct TransportPongMessage's.
260 struct OwnAddressList
263 * This is a linked list.
265 struct OwnAddressList *next;
268 * How long until we actually auto-expire this address (unless it is
269 * re-confirmed by the transport)?
271 struct GNUNET_TIME_Absolute expires;
274 * How long until the current signature expires? (ZERO if the
275 * signature was never created).
277 struct GNUNET_TIME_Absolute pong_sig_expires;
280 * Signature for a 'struct TransportPongMessage' for this address.
282 struct GNUNET_CRYPTO_RsaSignature pong_signature;
293 * Entry in linked list of all of our plugins.
295 struct TransportPlugin
299 * This is a linked list.
301 struct TransportPlugin *next;
304 * API of the transport as returned by the plugin's
305 * initialization function.
307 struct GNUNET_TRANSPORT_PluginFunctions *api;
310 * Short name for the plugin (i.e. "tcp").
315 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
320 * List of our known addresses for this transport.
322 struct OwnAddressList *addresses;
325 * Environment this transport service is using
328 struct GNUNET_TRANSPORT_PluginEnvironment env;
331 * ID of task that is used to clean up expired addresses.
333 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
336 * Set to GNUNET_YES if we need to scrap the existing list of
337 * "addresses" and start fresh when we receive the next address
338 * update from a transport. Set to GNUNET_NO if we should just add
339 * the new address to the list and wait for the commit call.
343 struct ATS_plugin * rc;
346 * Hashmap of blacklisted peers for this particular transport.
348 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
351 struct NeighbourList;
354 * For each neighbour we keep a list of messages
355 * that we still want to transmit to the neighbour.
361 * This is a doubly linked list.
363 struct MessageQueue *next;
366 * This is a doubly linked list.
368 struct MessageQueue *prev;
371 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
372 * stuck together in memory. Allocated at the end of this struct.
374 const char *message_buf;
377 * Size of the message buf
379 size_t message_buf_size;
382 * Client responsible for queueing the message;
383 * used to check that a client has no two messages
384 * pending for the same target. Can be NULL.
386 struct TransportClient *client;
389 * Using which specific address should we send this message?
391 struct ForeignAddressList *specific_address;
394 * Peer ID of the Neighbour this entry belongs to.
396 struct GNUNET_PeerIdentity neighbour_id;
399 * Plugin that we used for the transmission.
400 * NULL until we scheduled a transmission.
402 struct TransportPlugin *plugin;
405 * At what time should we fail?
407 struct GNUNET_TIME_Absolute timeout;
410 * Internal message of the transport system that should not be
411 * included in the usual SEND-SEND_OK transmission confirmation
412 * traffic management scheme. Typically, "internal_msg" will
413 * be set whenever "client" is NULL (but it is not strictly
419 * How important is the message?
421 unsigned int priority;
427 * For a given Neighbour, which plugins are available
428 * to talk to this peer and what are their costs?
433 * This is a linked list.
435 struct ReadyList *next;
438 * Which of our transport plugins does this entry
441 struct TransportPlugin *plugin;
444 * Transport addresses, latency, and readiness for
445 * this particular plugin.
447 struct ForeignAddressList *addresses;
450 * To which neighbour does this ready list belong to?
452 struct NeighbourList *neighbour;
457 * Entry in linked list of all of our current neighbours.
463 * This is a linked list.
465 struct NeighbourList *next;
468 * Which of our transports is connected to this peer
469 * and what is their status?
471 struct ReadyList *plugins;
474 * Head of list of messages we would like to send to this peer;
475 * must contain at most one message per client.
477 struct MessageQueue *messages_head;
480 * Tail of list of messages we would like to send to this peer; must
481 * contain at most one message per client.
483 struct MessageQueue *messages_tail;
486 * Buffer for at most one payload message used when we receive
487 * payload data before our PING-PONG has succeeded. We then
488 * store such messages in this intermediary buffer until the
489 * connection is fully up.
491 struct GNUNET_MessageHeader *pre_connect_message_buffer;
494 * Context for peerinfo iteration.
495 * NULL after we are done processing peerinfo's information.
497 struct GNUNET_PEERINFO_IteratorContext *piter;
500 * Public key for this peer. Valid only if the respective flag is set below.
502 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
505 * Identity of this neighbour.
507 struct GNUNET_PeerIdentity id;
510 * ID of task scheduled to run when this peer is about to
511 * time out (will free resources associated with the peer).
513 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
516 * ID of task scheduled to run when we should retry transmitting
517 * the head of the message queue. Actually triggered when the
518 * transmission is timing out (we trigger instantly when we have
519 * a chance of success).
521 GNUNET_SCHEDULER_TaskIdentifier retry_task;
524 * How long until we should consider this peer dead
525 * (if we don't receive another message in the
528 struct GNUNET_TIME_Absolute peer_timeout;
531 * Tracker for inbound bandwidth.
533 struct GNUNET_BANDWIDTH_Tracker in_tracker;
536 * The latency we have seen for this particular address for
537 * this particular peer. This latency may have been calculated
538 * over multiple transports. This value reflects how long it took
539 * us to receive a response when SENDING via this particular
540 * transport/neighbour/address combination!
542 * FIXME: we need to periodically send PINGs to update this
543 * latency (at least more often than the current "huge" (11h?)
546 struct GNUNET_TIME_Relative latency;
549 * How often has the other peer (recently) violated the
550 * inbound traffic limit? Incremented by 10 per violation,
551 * decremented by 1 per non-violation (for each
554 unsigned int quota_violation_count;
557 * DV distance to this peer (1 if no DV is used).
562 * Have we seen an PONG from this neighbour in the past (and
563 * not had a disconnect since)?
568 * Do we have a valid public key for this neighbour?
570 int public_key_valid;
573 * Performance data for the peer.
575 struct GNUNET_TRANSPORT_ATS_Information *ats;
578 * Identity of the neighbour.
580 struct GNUNET_PeerIdentity peer;
585 * Message used to ask a peer to validate receipt (to check an address
586 * from a HELLO). Followed by the address we are trying to validate,
587 * or an empty address if we are just sending a PING to confirm that a
588 * connection which the receiver (of the PING) initiated is still valid.
590 struct TransportPingMessage
594 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
596 struct GNUNET_MessageHeader header;
599 * Challenge code (to ensure fresh reply).
601 uint32_t challenge GNUNET_PACKED;
604 * Who is the intended recipient?
606 struct GNUNET_PeerIdentity target;
612 * Message used to validate a HELLO. The challenge is included in the
613 * confirmation to make matching of replies to requests possible. The
614 * signature signs our public key, an expiration time and our address.<p>
616 * This message is followed by our transport address that the PING tried
617 * to confirm (if we liked it). The address can be empty (zero bytes)
618 * if the PING had not address either (and we received the request via
619 * a connection that we initiated).
621 struct TransportPongMessage
625 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
627 struct GNUNET_MessageHeader header;
630 * Challenge code from PING (showing freshness). Not part of what
631 * is signed so that we can re-use signatures.
633 uint32_t challenge GNUNET_PACKED;
638 struct GNUNET_CRYPTO_RsaSignature signature;
641 * What are we signing and why? Two possible reason codes can be here:
642 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
643 * plausible address for this peer (pid is set to identity of signer); or
644 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
645 * an address we used to connect to the peer with the given pid.
647 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
650 * When does this signature expire?
652 struct GNUNET_TIME_AbsoluteNBO expiration;
655 * Either the identity of the peer Who signed this message, or the
656 * identity of the peer that we're connected to using the given
657 * address (depending on purpose.type).
659 struct GNUNET_PeerIdentity pid;
662 * Size of address appended to this message (part of what is
663 * being signed, hence not redundant).
671 * Linked list of messages to be transmitted to the client. Each
672 * entry is followed by the actual message.
674 struct ClientMessageQueueEntry
677 * This is a doubly-linked list.
679 struct ClientMessageQueueEntry *next;
682 * This is a doubly-linked list.
684 struct ClientMessageQueueEntry *prev;
689 * Client connected to the transport service.
691 struct TransportClient
695 * This is a linked list.
697 struct TransportClient *next;
700 * Handle to the client.
702 struct GNUNET_SERVER_Client *client;
705 * Linked list of messages yet to be transmitted to
708 struct ClientMessageQueueEntry *message_queue_head;
711 * Tail of linked list of messages yet to be transmitted to the
714 struct ClientMessageQueueEntry *message_queue_tail;
717 * Current transmit request handle.
719 struct GNUNET_CONNECTION_TransmitHandle *th;
722 * Is a call to "transmit_send_continuation" pending? If so, we
723 * must not free this struct (even if the corresponding client
724 * disconnects) and instead only remove it from the linked list and
725 * set the "client" field to NULL.
730 * Length of the list of messages pending for this client.
732 unsigned int message_count;
738 * Context of currently active requests to peerinfo
739 * for validation of HELLOs.
741 struct CheckHelloValidatedContext;
745 * Entry in map of all HELLOs awaiting validation.
747 struct ValidationEntry
751 * NULL if this entry is not part of a larger HELLO validation.
753 struct CheckHelloValidatedContext *chvc;
756 * The address, actually a pointer to the end
757 * of this struct. Do not free!
762 * Name of the transport.
764 char *transport_name;
767 * The public key of the peer.
769 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
772 * ID of task that will clean up this entry if we don't succeed
773 * with the validation first.
775 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
778 * At what time did we send this validation?
780 struct GNUNET_TIME_Absolute send_time;
783 * Session being validated (or NULL for none).
785 struct Session *session;
788 * Challenge number we used.
801 * Context of currently active requests to peerinfo
802 * for validation of HELLOs.
804 struct CheckHelloValidatedContext
808 * This is a doubly-linked list.
810 struct CheckHelloValidatedContext *next;
813 * This is a doubly-linked list.
815 struct CheckHelloValidatedContext *prev;
818 * Hello that we are validating.
820 const struct GNUNET_HELLO_Message *hello;
823 * Context for peerinfo iteration.
824 * NULL after we are done processing peerinfo's information.
826 struct GNUNET_PEERINFO_IteratorContext *piter;
829 * Was a HELLO known for this peer to peerinfo?
834 * Number of validation entries currently referring to this
837 unsigned int ve_count;
840 struct ATS_ressource_cost
844 struct ATS_ressource_cost * prev;
845 struct ATS_ressource_cost * next;
851 struct ATS_plugin * prev;
852 struct ATS_plugin * next;
854 struct ATS_ressource_cost * head;
855 struct ATS_ressource_cost * tail;
858 struct ATS_quality_metric
870 static struct GNUNET_HELLO_Message *our_hello;
875 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
880 static struct GNUNET_PeerIdentity my_identity;
885 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
890 const struct GNUNET_CONFIGURATION_Handle *cfg;
893 * Linked list of all clients to this service.
895 static struct TransportClient *clients;
898 * All loaded plugins.
900 static struct TransportPlugin *plugins;
903 * Handle to peerinfo service.
905 static struct GNUNET_PEERINFO_Handle *peerinfo;
908 * All known neighbours and their HELLOs.
910 static struct NeighbourList *neighbours;
913 * Number of neighbours we'd like to have.
915 static uint32_t max_connect_per_transport;
918 * Head of linked list.
920 static struct CheckHelloValidatedContext *chvc_head;
923 * Tail of linked list.
925 static struct CheckHelloValidatedContext *chvc_tail;
928 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
929 * of the given peer that we are currently validating).
931 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
934 * Handle for reporting statistics.
936 static struct GNUNET_STATISTICS_Handle *stats;
939 * Handle for ats information
941 static struct ATS_info *ats;
944 static struct ATS_quality_metric qm[] =
946 {1, 1028, "QUALITY_NET_DISTANCE"},
947 {2, 1034, "QUALITY_NET_DELAY"},
949 static int available_quality_metrics = 2;
953 * The peer specified by the given neighbour has timed-out or a plugin
954 * has disconnected. We may either need to do nothing (other plugins
955 * still up), or trigger a full disconnect and clean up. This
956 * function updates our state and do the necessary notifications.
957 * Also notifies our clients that the neighbour is now officially
960 * @param n the neighbour list entry for the peer
961 * @param check should we just check if all plugins
962 * disconnected or must we ask all plugins to
965 static void disconnect_neighbour (struct NeighbourList *n, int check);
968 * Check the ready list for the given neighbour and if a plugin is
969 * ready for transmission (and if we have a message), do so!
971 * @param nexi target peer for which to transmit
973 static void try_transmission_to_peer (struct NeighbourList *n);
978 void ats_shutdown ( );
980 void ats_notify_peer_connect (
981 const struct GNUNET_PeerIdentity *peer,
982 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
984 void ats_notify_peer_disconnect (
985 const struct GNUNET_PeerIdentity *peer);
987 void ats_notify_ats_data (
988 const struct GNUNET_PeerIdentity *peer,
989 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
991 struct ForeignAddressList * ats_get_preferred_address (
992 struct NeighbourList *n);
995 * Find an entry in the neighbour list for a particular peer.
997 * @return NULL if not found.
999 static struct NeighbourList *
1000 find_neighbour (const struct GNUNET_PeerIdentity *key)
1002 struct NeighbourList *head = neighbours;
1004 while ((head != NULL) &&
1005 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1012 * Find an entry in the transport list for a particular transport.
1014 * @return NULL if not found.
1016 static struct TransportPlugin *
1017 find_transport (const char *short_name)
1019 struct TransportPlugin *head = plugins;
1020 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1026 * Is a particular peer blacklisted for a particular transport?
1028 * @param peer the peer to check for
1029 * @param plugin the plugin used to connect to the peer
1031 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1034 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1037 if (plugin->blacklist != NULL)
1039 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043 "Peer `%s:%s' is blacklisted!\n",
1044 plugin->short_name, GNUNET_i2s (peer));
1047 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1057 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1059 struct TransportPlugin *plugin;
1061 plugin = find_transport(transport_name);
1062 if (plugin == NULL) /* Nothing to do */
1064 if (plugin->blacklist == NULL)
1065 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1066 GNUNET_assert(plugin->blacklist != NULL);
1067 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1069 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1074 * Read the blacklist file, containing transport:peer entries.
1075 * Provided the transport is loaded, set up hashmap with these
1076 * entries to blacklist peers by transport.
1080 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1087 struct GNUNET_PeerIdentity pid;
1089 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1090 unsigned int entries_found;
1091 char *transport_name;
1094 GNUNET_CONFIGURATION_get_value_filename (cfg,
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Option `%s' in section `%s' not specified!\n",
1107 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1108 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1109 | GNUNET_DISK_PERM_USER_WRITE);
1110 if (0 != STAT (fn, &frstat))
1112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1113 _("Could not read blacklist file `%s'\n"), fn);
1117 if (frstat.st_size == 0)
1120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1121 _("Blacklist file `%s' is empty.\n"),
1127 /* FIXME: use mmap */
1128 data = GNUNET_malloc_large (frstat.st_size);
1129 GNUNET_assert(data != NULL);
1130 if (frstat.st_size !=
1131 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1134 _("Failed to read blacklist from `%s'\n"), fn);
1141 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1143 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1144 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1147 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1150 if (colon_pos >= frstat.st_size)
1152 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1153 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1154 (unsigned long long) colon_pos);
1160 if (isspace( (unsigned char) data[colon_pos]))
1162 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1163 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1164 (unsigned long long) colon_pos);
1166 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1170 tsize = colon_pos - pos;
1171 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1173 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1174 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1175 (unsigned long long) colon_pos);
1184 transport_name = GNUNET_malloc(tsize + 1);
1185 memcpy(transport_name, &data[pos], tsize);
1186 pos = colon_pos + 1;
1188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1189 "Read transport name %s in blacklist file.\n",
1192 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1193 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1195 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1196 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1197 (unsigned long long) pos);
1199 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1201 GNUNET_free_non_null(transport_name);
1204 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1205 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1207 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1208 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1209 (unsigned long long) pos,
1214 if (0 != memcmp (&pid,
1216 sizeof (struct GNUNET_PeerIdentity)))
1219 add_peer_to_blacklist (&pid,
1224 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1225 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1229 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1230 GNUNET_free_non_null(transport_name);
1231 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1234 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1241 * Function called to notify a client about the socket being ready to
1242 * queue more data. "buf" will be NULL and "size" zero if the socket
1243 * was closed for writing in the meantime.
1245 * @param cls closure
1246 * @param size number of bytes available in buf
1247 * @param buf where the callee should write the message
1248 * @return number of bytes written to buf
1251 transmit_to_client_callback (void *cls, size_t size, void *buf)
1253 struct TransportClient *client = cls;
1254 struct ClientMessageQueueEntry *q;
1257 const struct GNUNET_MessageHeader *msg;
1264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1265 "Transmission to client failed, closing connection.\n");
1267 /* fatal error with client, free message queue! */
1268 while (NULL != (q = client->message_queue_head))
1270 GNUNET_STATISTICS_update (stats,
1271 gettext_noop ("# bytes discarded (could not transmit to client)"),
1272 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1274 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1275 client->message_queue_tail,
1279 client->message_count = 0;
1284 while (NULL != (q = client->message_queue_head))
1286 msg = (const struct GNUNET_MessageHeader *) &q[1];
1287 msize = ntohs (msg->size);
1288 if (msize + tsize > size)
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1292 "Transmitting message of type %u to client.\n",
1295 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1296 client->message_queue_tail,
1298 memcpy (&cbuf[tsize], msg, msize);
1301 client->message_count--;
1305 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1306 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1308 GNUNET_TIME_UNIT_FOREVER_REL,
1309 &transmit_to_client_callback,
1311 GNUNET_assert (client->th != NULL);
1318 * Convert an address to a string.
1320 * @param plugin name of the plugin responsible for the address
1321 * @param addr binary address
1322 * @param addr_len number of bytes in addr
1323 * @return NULL on error, otherwise address string
1326 a2s (const char *plugin,
1330 struct TransportPlugin *p;
1334 p = find_transport (plugin);
1337 return p->api->address_to_string (p->api->cls,
1344 * Mark the given FAL entry as 'connected' (and hence preferred for
1345 * sending); also mark all others for the same peer as 'not connected'
1346 * (since only one can be preferred).
1348 * @param fal address to set to 'connected'
1351 mark_address_connected (struct ForeignAddressList *fal)
1353 struct ForeignAddressList *pos;
1356 GNUNET_assert (GNUNET_YES == fal->validated);
1357 if (fal->connected == GNUNET_YES)
1358 return; /* nothing to do */
1360 pos = fal->ready_list->addresses;
1363 if (GNUNET_YES == pos->connected)
1366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1367 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1368 a2s (pos->ready_list->plugin->short_name,
1372 GNUNET_break (cnt == GNUNET_YES);
1374 pos->connected = GNUNET_NO;
1375 GNUNET_STATISTICS_update (stats,
1376 gettext_noop ("# connected addresses"),
1382 fal->connected = GNUNET_YES;
1383 if (GNUNET_YES == cnt)
1385 GNUNET_STATISTICS_update (stats,
1386 gettext_noop ("# connected addresses"),
1394 * Send the specified message to the specified client. Since multiple
1395 * messages may be pending for the same client at a time, this code
1396 * makes sure that no message is lost.
1398 * @param client client to transmit the message to
1399 * @param msg the message to send
1400 * @param may_drop can this message be dropped if the
1401 * message queue for this client is getting far too large?
1404 transmit_to_client (struct TransportClient *client,
1405 const struct GNUNET_MessageHeader *msg, int may_drop)
1407 struct ClientMessageQueueEntry *q;
1410 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1412 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1414 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1417 client->message_count,
1419 GNUNET_STATISTICS_update (stats,
1420 gettext_noop ("# messages dropped due to slow client"),
1425 msize = ntohs (msg->size);
1426 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1427 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1428 memcpy (&q[1], msg, msize);
1429 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1430 client->message_queue_tail,
1431 client->message_queue_tail,
1433 client->message_count++;
1434 if (client->th == NULL)
1436 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1438 GNUNET_TIME_UNIT_FOREVER_REL,
1439 &transmit_to_client_callback,
1441 GNUNET_assert (client->th != NULL);
1447 * Transmit a 'SEND_OK' notification to the given client for the
1450 * @param client who to notify
1451 * @param n neighbour to notify about, can be NULL (on failure)
1452 * @param target target of the transmission
1453 * @param result status code for the transmission request
1456 transmit_send_ok (struct TransportClient *client,
1457 struct NeighbourList *n,
1458 const struct GNUNET_PeerIdentity *target,
1461 struct SendOkMessage send_ok_msg;
1463 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1464 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1465 send_ok_msg.success = htonl (result);
1467 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1469 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1470 send_ok_msg.peer = *target;
1471 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1476 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1477 * upon "completion" of a send request. This tells the API
1478 * that it is now legal to send another message to the given
1481 * @param cls closure, identifies the entry on the
1482 * message queue that was transmitted and the
1483 * client responsible for queuing the message
1484 * @param target the peer receiving the message
1485 * @param result GNUNET_OK on success, if the transmission
1486 * failed, we should not tell the client to transmit
1490 transmit_send_continuation (void *cls,
1491 const struct GNUNET_PeerIdentity *target,
1494 struct MessageQueue *mq = cls;
1495 struct NeighbourList *n;
1497 GNUNET_STATISTICS_update (stats,
1498 gettext_noop ("# bytes pending with plugins"),
1499 - (int64_t) mq->message_buf_size,
1501 if (result == GNUNET_OK)
1503 GNUNET_STATISTICS_update (stats,
1504 gettext_noop ("# bytes successfully transmitted by plugins"),
1505 mq->message_buf_size,
1510 GNUNET_STATISTICS_update (stats,
1511 gettext_noop ("# bytes with transmission failure by plugins"),
1512 mq->message_buf_size,
1515 if (mq->specific_address != NULL)
1517 if (result == GNUNET_OK)
1519 mq->specific_address->timeout =
1520 GNUNET_TIME_relative_to_absolute
1521 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1522 if (mq->specific_address->validated == GNUNET_YES)
1523 mark_address_connected (mq->specific_address);
1527 if (mq->specific_address->connected != GNUNET_NO)
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1531 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1532 a2s (mq->specific_address->ready_list->plugin->short_name,
1533 mq->specific_address->addr,
1534 mq->specific_address->addrlen));
1536 GNUNET_STATISTICS_update (stats,
1537 gettext_noop ("# connected addresses"),
1540 mq->specific_address->connected = GNUNET_NO;
1543 if (! mq->internal_msg)
1544 mq->specific_address->in_transmit = GNUNET_NO;
1546 n = find_neighbour(&mq->neighbour_id);
1547 if (mq->client != NULL)
1548 transmit_send_ok (mq->client, n, target, result);
1551 try_transmission_to_peer (n);
1556 * Find an address in any of the available transports for
1557 * the given neighbour that would be good for message
1558 * transmission. This is essentially the transport selection
1561 * @param neighbour for whom to select an address
1562 * @return selected address, NULL if we have none
1564 struct ForeignAddressList *
1565 find_ready_address(struct NeighbourList *neighbour)
1567 struct ReadyList *head = neighbour->plugins;
1568 struct ForeignAddressList *addresses;
1569 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1570 struct ForeignAddressList *best_address;
1572 /* Hack to prefer unix domain sockets */
1573 struct ForeignAddressList *unix_address = NULL;
1575 best_address = NULL;
1576 while (head != NULL)
1578 addresses = head->addresses;
1579 while (addresses != NULL)
1581 if ( (addresses->timeout.abs_value < now.abs_value) &&
1582 (addresses->connected == GNUNET_YES) )
1585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1586 "Marking long-time inactive connection to `%4s' as down.\n",
1587 GNUNET_i2s (&neighbour->id));
1589 GNUNET_STATISTICS_update (stats,
1590 gettext_noop ("# connected addresses"),
1593 addresses->connected = GNUNET_NO;
1595 addresses = addresses->next;
1598 addresses = head->addresses;
1599 while (addresses != NULL)
1601 #if DEBUG_TRANSPORT > 1
1602 if (addresses->addr != NULL)
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1605 a2s (head->plugin->short_name,
1607 addresses->addrlen),
1608 GNUNET_i2s (&neighbour->id),
1609 addresses->connected,
1610 addresses->in_transmit,
1611 addresses->validated,
1612 addresses->connect_attempts,
1613 (unsigned long long) addresses->timeout.abs_value,
1614 (unsigned int) addresses->distance);
1616 if (0==strcmp(head->plugin->short_name,"unix"))
1618 if ((unix_address == NULL) || ((unix_address != NULL) &&
1619 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1620 unix_address = addresses;
1622 if ( ( (best_address == NULL) ||
1623 (addresses->connected == GNUNET_YES) ||
1624 (best_address->connected == GNUNET_NO) ) &&
1625 (addresses->in_transmit == GNUNET_NO) &&
1626 ( (best_address == NULL) ||
1627 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1628 best_address = addresses;
1629 /* FIXME: also give lower-latency addresses that are not
1630 connected a chance some times... */
1631 addresses = addresses->next;
1633 if (unix_address != NULL)
1637 if (unix_address != NULL)
1639 best_address = unix_address;
1641 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1644 if (best_address != NULL)
1648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1649 "Best address found (`%s') has latency of %llu ms.\n",
1650 (best_address->addrlen > 0)
1651 ? a2s (best_address->ready_list->plugin->short_name,
1653 best_address->addrlen)
1655 best_address->latency.rel_value);
1660 GNUNET_STATISTICS_update (stats,
1661 gettext_noop ("# transmission attempts failed (no address)"),
1666 return best_address;
1672 * We should re-try transmitting to the given peer,
1673 * hopefully we've learned something in the meantime.
1676 retry_transmission_task (void *cls,
1677 const struct GNUNET_SCHEDULER_TaskContext *tc)
1679 struct NeighbourList *n = cls;
1681 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1682 try_transmission_to_peer (n);
1687 * Check the ready list for the given neighbour and if a plugin is
1688 * ready for transmission (and if we have a message), do so!
1690 * @param neighbour target peer for which to transmit
1693 try_transmission_to_peer (struct NeighbourList *n)
1695 struct ReadyList *rl;
1696 struct MessageQueue *mq;
1697 struct GNUNET_TIME_Relative timeout;
1701 if (n->messages_head == NULL)
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "Transmission queue for `%4s' is empty\n",
1706 GNUNET_i2s (&neighbour->id));
1708 return; /* nothing to do */
1711 mq = n->messages_head;
1712 force_address = GNUNET_YES;
1713 if (mq->specific_address == NULL)
1716 mq->specific_address = ats_get_preferred_address(n);
1717 GNUNET_STATISTICS_update (stats,
1718 gettext_noop ("# transport selected peer address freely"),
1721 force_address = GNUNET_NO;
1723 if (mq->specific_address == NULL)
1725 GNUNET_STATISTICS_update (stats,
1726 gettext_noop ("# transport failed to selected peer address"),
1729 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1730 if (timeout.rel_value == 0)
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734 "No destination address available to transmit message of size %u to peer `%4s'\n",
1735 mq->message_buf_size,
1736 GNUNET_i2s (&mq->neighbour_id));
1738 GNUNET_STATISTICS_update (stats,
1739 gettext_noop ("# bytes in message queue for other peers"),
1740 - (int64_t) mq->message_buf_size,
1742 GNUNET_STATISTICS_update (stats,
1743 gettext_noop ("# bytes discarded (no destination address available)"),
1744 mq->message_buf_size,
1746 if (mq->client != NULL)
1747 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1748 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1752 return; /* nobody ready */
1754 GNUNET_STATISTICS_update (stats,
1755 gettext_noop ("# message delivery deferred (no address)"),
1758 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1759 GNUNET_SCHEDULER_cancel (n->retry_task);
1760 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1761 &retry_transmission_task,
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1766 mq->message_buf_size,
1767 GNUNET_i2s (&mq->neighbour_id),
1770 /* FIXME: might want to trigger peerinfo lookup here
1771 (unless that's already pending...) */
1774 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1777 if (mq->specific_address->connected == GNUNET_NO)
1778 mq->specific_address->connect_attempts++;
1779 rl = mq->specific_address->ready_list;
1780 mq->plugin = rl->plugin;
1781 if (!mq->internal_msg)
1782 mq->specific_address->in_transmit = GNUNET_YES;
1784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1786 mq->message_buf_size,
1787 GNUNET_i2s (&neighbour->id),
1788 (mq->specific_address->addr != NULL)
1789 ? a2s (mq->plugin->short_name,
1790 mq->specific_address->addr,
1791 mq->specific_address->addrlen)
1793 rl->plugin->short_name);
1795 GNUNET_STATISTICS_update (stats,
1796 gettext_noop ("# bytes in message queue for other peers"),
1797 - (int64_t) mq->message_buf_size,
1799 GNUNET_STATISTICS_update (stats,
1800 gettext_noop ("# bytes pending with plugins"),
1801 mq->message_buf_size,
1803 ret = rl->plugin->api->send (rl->plugin->api->cls,
1806 mq->message_buf_size,
1808 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1809 mq->specific_address->session,
1810 mq->specific_address->addr,
1811 mq->specific_address->addrlen,
1813 &transmit_send_continuation, mq);
1816 /* failure, but 'send' would not call continuation in this case,
1817 so we need to do it here! */
1818 transmit_send_continuation (mq,
1826 * Send the specified message to the specified peer.
1828 * @param client source of the transmission request (can be NULL)
1829 * @param peer_address ForeignAddressList where we should send this message
1830 * @param priority how important is the message
1831 * @param timeout how long do we have to transmit?
1832 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1833 * @param message_buf_size total size of all messages in message_buf
1834 * @param is_internal is this an internal message; these are pre-pended and
1835 * also do not count for plugins being "ready" to transmit
1836 * @param neighbour handle to the neighbour for transmission
1839 transmit_to_peer (struct TransportClient *client,
1840 struct ForeignAddressList *peer_address,
1841 unsigned int priority,
1842 struct GNUNET_TIME_Relative timeout,
1843 const char *message_buf,
1844 size_t message_buf_size,
1845 int is_internal, struct NeighbourList *neighbour)
1847 struct MessageQueue *mq;
1852 /* check for duplicate submission */
1853 mq = neighbour->messages_head;
1856 if (mq->client == client)
1858 /* client transmitted to same peer twice
1859 before getting SEND_OK! */
1867 GNUNET_STATISTICS_update (stats,
1868 gettext_noop ("# bytes in message queue for other peers"),
1871 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1872 mq->specific_address = peer_address;
1873 mq->client = client;
1874 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1875 memcpy (&mq[1], message_buf, message_buf_size);
1876 mq->message_buf = (const char*) &mq[1];
1877 mq->message_buf_size = message_buf_size;
1878 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1879 mq->internal_msg = is_internal;
1880 mq->priority = priority;
1881 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1883 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1884 neighbour->messages_tail,
1887 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1888 neighbour->messages_tail,
1889 neighbour->messages_tail,
1891 try_transmission_to_peer (neighbour);
1898 struct GeneratorContext
1900 struct TransportPlugin *plug_pos;
1901 struct OwnAddressList *addr_pos;
1902 struct GNUNET_TIME_Absolute expiration;
1910 address_generator (void *cls, size_t max, void *buf)
1912 struct GeneratorContext *gc = cls;
1915 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1917 gc->plug_pos = gc->plug_pos->next;
1918 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1920 if (NULL == gc->plug_pos)
1925 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1928 gc->addr_pos->addrlen, buf, max);
1929 gc->addr_pos = gc->addr_pos->next;
1935 * Construct our HELLO message from all of the addresses of
1936 * all of the transports.
1941 struct GNUNET_HELLO_Message *hello;
1942 struct TransportClient *cpos;
1943 struct NeighbourList *npos;
1944 struct GeneratorContext gc;
1946 gc.plug_pos = plugins;
1947 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1948 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1949 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1952 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1954 GNUNET_STATISTICS_update (stats,
1955 gettext_noop ("# refreshed my HELLO"),
1959 while (cpos != NULL)
1961 transmit_to_client (cpos,
1962 (const struct GNUNET_MessageHeader *) hello,
1967 GNUNET_free_non_null (our_hello);
1969 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1971 while (npos != NULL)
1974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1975 "Transmitting updated `%s' to neighbour `%4s'\n",
1976 "HELLO", GNUNET_i2s (&npos->id));
1978 GNUNET_STATISTICS_update (stats,
1979 gettext_noop ("# transmitted my HELLO to other peers"),
1982 transmit_to_peer (NULL, NULL, 0,
1983 HELLO_ADDRESS_EXPIRATION,
1984 (const char *) our_hello,
1985 GNUNET_HELLO_size(our_hello),
1993 * Task used to clean up expired addresses for a plugin.
1995 * @param cls closure
1999 expire_address_task (void *cls,
2000 const struct GNUNET_SCHEDULER_TaskContext *tc);
2004 * Update the list of addresses for this plugin,
2005 * expiring those that are past their expiration date.
2007 * @param plugin addresses of which plugin should be recomputed?
2008 * @param fresh set to GNUNET_YES if a new address was added
2009 * and we need to regenerate the HELLO even if nobody
2013 update_addresses (struct TransportPlugin *plugin,
2016 static struct GNUNET_TIME_Absolute last_update;
2017 struct GNUNET_TIME_Relative min_remaining;
2018 struct GNUNET_TIME_Relative remaining;
2019 struct GNUNET_TIME_Absolute now;
2020 struct OwnAddressList *pos;
2021 struct OwnAddressList *prev;
2022 struct OwnAddressList *next;
2025 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2026 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2027 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2028 now = GNUNET_TIME_absolute_get ();
2029 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2030 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2032 pos = plugin->addresses;
2036 if (pos->expires.abs_value < now.abs_value)
2038 expired = GNUNET_YES;
2040 plugin->addresses = pos->next;
2042 prev->next = pos->next;
2047 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2048 if (remaining.rel_value < min_remaining.rel_value)
2049 min_remaining = remaining;
2055 if (expired || fresh)
2060 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2061 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2063 plugin->address_update_task
2064 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2065 &expire_address_task, plugin);
2070 * Task used to clean up expired addresses for a plugin.
2072 * @param cls closure
2076 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2078 struct TransportPlugin *plugin = cls;
2080 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2081 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2082 update_addresses (plugin, GNUNET_NO);
2087 * Iterator over hash map entries that NULLs the session of validation
2088 * entries that match the given session.
2090 * @param cls closure (the 'struct Session*' to match against)
2091 * @param key current key code (peer ID, not used)
2092 * @param value value in the hash map ('struct ValidationEntry*')
2093 * @return GNUNET_YES (we should continue to iterate)
2096 remove_session_validations (void *cls,
2097 const GNUNET_HashCode * key,
2100 struct Session *session = cls;
2101 struct ValidationEntry *ve = value;
2103 if (session == ve->session)
2110 * We've been disconnected from the other peer (for some
2111 * connection-oriented transport). Either quickly
2112 * re-establish the connection or signal the disconnect
2115 * Only signal CORE level disconnect if ALL addresses
2116 * for the peer are exhausted.
2118 * @param p overall plugin context
2119 * @param nl neighbour that was disconnected
2122 try_fast_reconnect (struct TransportPlugin *p,
2123 struct NeighbourList *nl)
2125 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2126 /* Note: the idea here is to hide problems with transports (or
2127 switching between plugins) from the core to eliminate the need to
2128 re-negotiate session keys and the like; OTOH, we should tell core
2129 quickly (much faster than timeout) `if a connection was lost and
2130 could not be re-established (i.e. other peer went down or is
2131 unable / refuses to communicate);
2133 So we should consider:
2134 1) ideally: our own willingness / need to connect
2135 2) prior failures to connect to this peer (by plugin)
2136 3) ideally: reasons why other peer terminated (as far as knowable)
2138 Most importantly, it must be POSSIBLE for another peer to terminate
2139 a connection for a while (without us instantly re-establishing it).
2140 Similarly, if another peer is gone we should quickly notify CORE.
2141 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2142 on the other end), we should reconnect in such a way that BOTH CORE
2143 services never even notice.
2144 Furthermore, the same mechanism (or small variation) could be used
2145 to switch to a better-performing plugin (ATS).
2147 Finally, this needs to be tested throughly... */
2150 * GNUNET_NO in the call below makes transport disconnect the peer,
2151 * even if only a single address (out of say, six) went away. This
2152 * function must be careful to ONLY disconnect if the peer is gone,
2153 * not just a specifi address.
2155 * More specifically, half the places it was used had it WRONG.
2158 /* No reconnect, signal disconnect instead! */
2159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2160 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2161 "try_fast_reconnect");
2162 disconnect_neighbour (nl, GNUNET_YES);
2167 * Function that will be called whenever the plugin internally
2168 * cleans up a session pointer and hence the service needs to
2169 * discard all of those sessions as well. Plugins that do not
2170 * use sessions can simply omit calling this function and always
2171 * use NULL wherever a session pointer is needed.
2173 * @param cls closure
2174 * @param peer which peer was the session for
2175 * @param session which session is being destoyed
2178 plugin_env_session_end (void *cls,
2179 const struct GNUNET_PeerIdentity *peer,
2180 struct Session *session)
2182 struct TransportPlugin *p = cls;
2183 struct NeighbourList *nl;
2184 struct ReadyList *rl;
2185 struct ForeignAddressList *pos;
2186 struct ForeignAddressList *prev;
2188 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2189 &remove_session_validations,
2191 nl = find_neighbour (peer);
2193 return; /* was never marked as connected */
2197 if (rl->plugin == p)
2202 return; /* was never marked as connected */
2204 pos = rl->addresses;
2205 while ( (pos != NULL) &&
2206 (pos->session != session) )
2212 return; /* was never marked as connected */
2213 pos->session = NULL;
2214 if (pos->addrlen != 0)
2216 if (nl->received_pong != GNUNET_NO)
2217 try_fast_reconnect (p, nl);
2220 /* was inbound connection, free 'pos' */
2222 rl->addresses = pos->next;
2224 prev->next = pos->next;
2225 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2227 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2228 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2231 if (nl->received_pong == GNUNET_NO)
2232 return; /* nothing to do, never connected... */
2233 /* check if we have any validated addresses left */
2234 pos = rl->addresses;
2239 try_fast_reconnect (p, nl);
2244 /* no valid addresses left, signal disconnect! */
2246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2247 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2248 "plugin_env_session_end");
2249 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2250 * it means there aren't any left for this PLUGIN/PEER combination! So
2251 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2252 * when it isn't necessary. Using GNUNET_YES at least checks to see
2253 * if there are any addresses that work first, so as not to overdo it.
2256 disconnect_neighbour (nl, GNUNET_YES);
2261 * Function that must be called by each plugin to notify the
2262 * transport service about the addresses under which the transport
2263 * provided by the plugin can be reached.
2265 * @param cls closure
2266 * @param name name of the transport that generated the address
2267 * @param addr one of the addresses of the host, NULL for the last address
2268 * the specific address format depends on the transport
2269 * @param addrlen length of the address
2270 * @param expires when should this address automatically expire?
2273 plugin_env_notify_address (void *cls,
2277 struct GNUNET_TIME_Relative expires)
2279 struct TransportPlugin *p = cls;
2280 struct OwnAddressList *al;
2281 struct GNUNET_TIME_Absolute abex;
2283 GNUNET_assert (addr != NULL);
2284 abex = GNUNET_TIME_relative_to_absolute (expires);
2285 GNUNET_assert (p == find_transport (name));
2289 if ( (addrlen == al->addrlen) &&
2290 (0 == memcmp (addr, &al[1], addrlen)) )
2293 update_addresses (p, GNUNET_NO);
2298 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2299 al->next = p->addresses;
2302 al->addrlen = addrlen;
2303 memcpy (&al[1], addr, addrlen);
2304 update_addresses (p, GNUNET_YES);
2309 * Notify all of our clients about a peer connecting.
2312 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2313 struct GNUNET_TIME_Relative latency,
2316 struct ConnectInfoMessage * cim;
2317 struct TransportClient *cpos;
2322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2323 "Notifying clients about connection from `%s'\n",
2326 GNUNET_STATISTICS_update (stats,
2327 gettext_noop ("# peers connected"),
2332 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2333 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2337 cim = GNUNET_malloc (size);
2339 cim->header.size = htons (size);
2340 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2341 cim->ats_count = htonl(2);
2342 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2343 (&(cim->ats))[0].value = htonl (distance);
2344 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2345 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2346 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2347 (&(cim->ats))[2].value = htonl (0);
2348 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2350 /* notify ats about connecting peer */
2351 ats_notify_peer_connect (peer, &(cim->ats));
2354 while (cpos != NULL)
2356 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2365 * Notify all of our clients about a peer disconnecting.
2368 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2370 struct DisconnectInfoMessage dim;
2371 struct TransportClient *cpos;
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "Notifying clients about lost connection to `%s'\n",
2378 GNUNET_STATISTICS_update (stats,
2379 gettext_noop ("# peers connected"),
2382 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2383 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2384 dim.reserved = htonl (0);
2385 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2387 /* notify ats about connecting peer */
2388 ats_notify_peer_disconnect (peer);
2391 while (cpos != NULL)
2393 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2400 * Find a ForeignAddressList entry for the given neighbour
2401 * that matches the given address and transport.
2403 * @param neighbour which peer we care about
2404 * @param tname name of the transport plugin
2405 * @param session session to look for, NULL for 'any'; otherwise
2406 * can be used for the service to "learn" this session ID
2408 * @param addr binary address
2409 * @param addrlen length of addr
2410 * @return NULL if no such entry exists
2412 static struct ForeignAddressList *
2413 find_peer_address(struct NeighbourList *neighbour,
2415 struct Session *session,
2419 struct ReadyList *head;
2420 struct ForeignAddressList *pos;
2422 head = neighbour->plugins;
2423 while (head != NULL)
2425 if (0 == strcmp (tname, head->plugin->short_name))
2431 pos = head->addresses;
2432 while ( (pos != NULL) &&
2433 ( (pos->addrlen != addrlen) ||
2434 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2436 if ( (session != NULL) &&
2437 (pos->session == session) )
2441 if ( (session != NULL) && (pos != NULL) )
2442 pos->session = session; /* learn it! */
2448 * Get the peer address struct for the given neighbour and
2449 * address. If it doesn't yet exist, create it.
2451 * @param neighbour which peer we care about
2452 * @param tname name of the transport plugin
2453 * @param session session of the plugin, or NULL for none
2454 * @param addr binary address
2455 * @param addrlen length of addr
2456 * @return NULL if we do not have a transport plugin for 'tname'
2458 static struct ForeignAddressList *
2459 add_peer_address (struct NeighbourList *neighbour,
2461 struct Session *session,
2465 struct ReadyList *head;
2466 struct ForeignAddressList *ret;
2468 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2471 head = neighbour->plugins;
2473 while (head != NULL)
2475 if (0 == strcmp (tname, head->plugin->short_name))
2481 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2482 ret->session = session;
2485 ret->addr = (const char*) &ret[1];
2486 memcpy (&ret[1], addr, addrlen);
2492 ret->ressources = NULL;
2493 ret->addrlen = addrlen;
2494 ret->expires = GNUNET_TIME_relative_to_absolute
2495 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2496 ret->latency = GNUNET_TIME_relative_get_forever();
2498 ret->timeout = GNUNET_TIME_relative_to_absolute
2499 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2500 ret->ready_list = head;
2501 ret->next = head->addresses;
2502 head->addresses = ret;
2508 * Closure for 'add_validated_address'.
2510 struct AddValidatedAddressContext
2513 * Entry that has been validated.
2515 const struct ValidationEntry *ve;
2518 * Flag set after we have added the address so
2519 * that we terminate the iteration next time.
2526 * Callback function used to fill a buffer of max bytes with a list of
2527 * addresses in the format used by HELLOs. Should use
2528 * "GNUNET_HELLO_add_address" as a helper function.
2530 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2531 * @param max maximum number of bytes that can be written to buf
2532 * @param buf where to write the address information
2533 * @return number of bytes written, 0 to signal the
2534 * end of the iteration.
2537 add_validated_address (void *cls,
2538 size_t max, void *buf)
2540 struct AddValidatedAddressContext *avac = cls;
2541 const struct ValidationEntry *ve = avac->ve;
2543 if (GNUNET_YES == avac->done)
2545 avac->done = GNUNET_YES;
2546 return GNUNET_HELLO_add_address (ve->transport_name,
2547 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2557 * Closure for 'check_address_exists'.
2559 struct CheckAddressExistsClosure
2562 * Address to check for.
2567 * Name of the transport.
2574 struct Session *session;
2577 * Set to GNUNET_YES if the address exists.
2590 * Iterator over hash map entries. Checks if the given
2591 * validation entry is for the same address as what is given
2594 * @param cls the 'struct CheckAddressExistsClosure*'
2595 * @param key current key code (ignored)
2596 * @param value value in the hash map ('struct ValidationEntry')
2597 * @return GNUNET_YES if we should continue to
2598 * iterate (mismatch), GNUNET_NO if not (entry matched)
2601 check_address_exists (void *cls,
2602 const GNUNET_HashCode * key,
2605 struct CheckAddressExistsClosure *caec = cls;
2606 struct ValidationEntry *ve = value;
2608 if ( (0 == strcmp (caec->tname,
2609 ve->transport_name)) &&
2610 (caec->addrlen == ve->addrlen) &&
2611 (0 == memcmp (caec->addr,
2615 caec->exists = GNUNET_YES;
2618 if ( (ve->session != NULL) &&
2619 (caec->session == ve->session) )
2621 caec->exists = GNUNET_YES;
2630 * Iterator to free entries in the validation_map.
2632 * @param cls closure (unused)
2633 * @param key current key code
2634 * @param value value in the hash map (validation to abort)
2635 * @return GNUNET_YES (always)
2638 abort_validation (void *cls,
2639 const GNUNET_HashCode * key,
2642 struct ValidationEntry *va = value;
2644 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2645 GNUNET_SCHEDULER_cancel (va->timeout_task);
2646 GNUNET_free (va->transport_name);
2647 if (va->chvc != NULL)
2649 va->chvc->ve_count--;
2650 if (va->chvc->ve_count == 0)
2652 GNUNET_CONTAINER_DLL_remove (chvc_head,
2655 GNUNET_free (va->chvc);
2665 * HELLO validation cleanup task (validation failed).
2667 * @param cls the 'struct ValidationEntry' that failed
2668 * @param tc scheduler context (unused)
2671 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2673 struct ValidationEntry *va = cls;
2674 struct GNUNET_PeerIdentity pid;
2676 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2677 GNUNET_STATISTICS_update (stats,
2678 gettext_noop ("# address validation timeouts"),
2681 GNUNET_CRYPTO_hash (&va->publicKey,
2683 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2685 GNUNET_break (GNUNET_OK ==
2686 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2689 abort_validation (NULL, NULL, va);
2694 neighbour_timeout_task (void *cls,
2695 const struct GNUNET_SCHEDULER_TaskContext *tc)
2697 struct NeighbourList *n = cls;
2700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2701 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2703 GNUNET_STATISTICS_update (stats,
2704 gettext_noop ("# disconnects due to timeout"),
2707 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2708 disconnect_neighbour (n, GNUNET_NO);
2713 * Schedule the job that will cause us to send a PING to the
2714 * foreign address to evaluate its validity and latency.
2716 * @param fal address to PING
2719 schedule_next_ping (struct ForeignAddressList *fal);
2723 * Add the given address to the list of foreign addresses
2724 * available for the given peer (check for duplicates).
2726 * @param cls the respective 'struct NeighbourList' to update
2727 * @param tname name of the transport
2728 * @param expiration expiration time
2729 * @param addr the address
2730 * @param addrlen length of the address
2731 * @return GNUNET_OK (always)
2734 add_to_foreign_address_list (void *cls,
2736 struct GNUNET_TIME_Absolute expiration,
2740 struct NeighbourList *n = cls;
2741 struct ForeignAddressList *fal;
2744 GNUNET_STATISTICS_update (stats,
2745 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2749 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2752 #if DEBUG_TRANSPORT_HELLO
2753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2754 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2755 a2s (tname, addr, addrlen),
2757 GNUNET_i2s (&n->id),
2758 expiration.abs_value);
2760 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2763 GNUNET_STATISTICS_update (stats,
2764 gettext_noop ("# previously validated addresses lacking transport"),
2770 fal->expires = GNUNET_TIME_absolute_max (expiration,
2772 schedule_next_ping (fal);
2778 fal->expires = GNUNET_TIME_absolute_max (expiration,
2783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2784 "Failed to add new address for `%4s'\n",
2785 GNUNET_i2s (&n->id));
2788 if (fal->validated == GNUNET_NO)
2790 fal->validated = GNUNET_YES;
2791 GNUNET_STATISTICS_update (stats,
2792 gettext_noop ("# peer addresses considered valid"),
2796 if (try == GNUNET_YES)
2798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2799 "Have new addresses, will try to trigger transmissions.\n");
2800 try_transmission_to_peer (n);
2807 * Add addresses in validated HELLO "h" to the set of addresses
2808 * we have for this peer.
2810 * @param cls closure ('struct NeighbourList*')
2811 * @param peer id of the peer, NULL for last call
2812 * @param h hello message for the peer (can be NULL)
2813 * @param err_msg NULL if successful, otherwise contains error message
2816 add_hello_for_peer (void *cls,
2817 const struct GNUNET_PeerIdentity *peer,
2818 const struct GNUNET_HELLO_Message *h,
2819 const char *err_msg)
2821 struct NeighbourList *n = cls;
2823 if (err_msg != NULL)
2825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2826 _("Error in communication with PEERINFO service\n"));
2831 GNUNET_STATISTICS_update (stats,
2832 gettext_noop ("# outstanding peerinfo iterate requests"),
2839 return; /* no HELLO available */
2841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2842 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2846 if (GNUNET_YES != n->public_key_valid)
2848 GNUNET_HELLO_get_key (h, &n->publicKey);
2849 n->public_key_valid = GNUNET_YES;
2851 GNUNET_HELLO_iterate_addresses (h,
2853 &add_to_foreign_address_list,
2859 * Create a fresh entry in our neighbour list for the given peer.
2860 * Will try to transmit our current HELLO to the new neighbour.
2861 * Do not call this function directly, use 'setup_peer_check_blacklist.
2863 * @param peer the peer for which we create the entry
2864 * @param do_hello should we schedule transmitting a HELLO
2865 * @return the new neighbour list entry
2867 static struct NeighbourList *
2868 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2871 struct NeighbourList *n;
2872 struct TransportPlugin *tp;
2873 struct ReadyList *rl;
2876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2877 "Setting up state for neighbour `%4s'\n",
2880 GNUNET_assert (our_hello != NULL);
2881 GNUNET_STATISTICS_update (stats,
2882 gettext_noop ("# active neighbours"),
2885 n = GNUNET_malloc (sizeof (struct NeighbourList));
2886 n->next = neighbours;
2890 GNUNET_TIME_relative_to_absolute
2891 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2892 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2893 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2894 MAX_BANDWIDTH_CARRY_S);
2898 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2900 rl = GNUNET_malloc (sizeof (struct ReadyList));
2902 rl->next = n->plugins;
2905 rl->addresses = NULL;
2909 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2911 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2912 &neighbour_timeout_task, n);
2915 GNUNET_STATISTICS_update (stats,
2916 gettext_noop ("# peerinfo new neighbor iterate requests"),
2919 GNUNET_STATISTICS_update (stats,
2920 gettext_noop ("# outstanding peerinfo iterate requests"),
2923 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2924 GNUNET_TIME_UNIT_FOREVER_REL,
2925 &add_hello_for_peer, n);
2927 GNUNET_STATISTICS_update (stats,
2928 gettext_noop ("# HELLO's sent to new neighbors"),
2931 transmit_to_peer (NULL, NULL, 0,
2932 HELLO_ADDRESS_EXPIRATION,
2933 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2941 * Function called after we have checked if communicating
2942 * with a given peer is acceptable.
2944 * @param cls closure
2945 * @param n NULL if communication is not acceptable
2947 typedef void (*SetupContinuation)(void *cls,
2948 struct NeighbourList *n);
2952 * Information kept for each client registered to perform
2958 * This is a linked list.
2960 struct Blacklisters *next;
2963 * This is a linked list.
2965 struct Blacklisters *prev;
2968 * Client responsible for this entry.
2970 struct GNUNET_SERVER_Client *client;
2973 * Blacklist check that we're currently performing.
2975 struct BlacklistCheck *bc;
2981 * Head of DLL of blacklisting clients.
2983 static struct Blacklisters *bl_head;
2986 * Tail of DLL of blacklisting clients.
2988 static struct Blacklisters *bl_tail;
2992 * Context we use when performing a blacklist check.
2994 struct BlacklistCheck
2998 * This is a linked list.
3000 struct BlacklistCheck *next;
3003 * This is a linked list.
3005 struct BlacklistCheck *prev;
3008 * Peer being checked.
3010 struct GNUNET_PeerIdentity peer;
3013 * Option for setup neighbour afterwards.
3018 * Continuation to call with the result.
3020 SetupContinuation cont;
3028 * Current transmission request handle for this client, or NULL if no
3029 * request is pending.
3031 struct GNUNET_CONNECTION_TransmitHandle *th;
3034 * Our current position in the blacklisters list.
3036 struct Blacklisters *bl_pos;
3039 * Current task performing the check.
3041 GNUNET_SCHEDULER_TaskIdentifier task;
3046 * Head of DLL of active blacklisting queries.
3048 static struct BlacklistCheck *bc_head;
3051 * Tail of DLL of active blacklisting queries.
3053 static struct BlacklistCheck *bc_tail;
3057 * Perform next action in the blacklist check.
3059 * @param cls the 'struct BlacklistCheck*'
3063 do_blacklist_check (void *cls,
3064 const struct GNUNET_SCHEDULER_TaskContext *tc);
3067 * Transmit blacklist query to the client.
3069 * @param cls the 'struct BlacklistCheck'
3070 * @param size number of bytes allowed
3071 * @param buf where to copy the message
3072 * @return number of bytes copied to buf
3075 transmit_blacklist_message (void *cls,
3079 struct BlacklistCheck *bc = cls;
3080 struct Blacklisters *bl;
3081 struct BlacklistMessage bm;
3086 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3087 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3092 bm.header.size = htons (sizeof (struct BlacklistMessage));
3093 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3094 bm.is_allowed = htonl (0);
3096 memcpy (buf, &bm, sizeof (bm));
3097 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3103 * Perform next action in the blacklist check.
3105 * @param cls the 'struct BlacklistCheck*'
3109 do_blacklist_check (void *cls,
3110 const struct GNUNET_SCHEDULER_TaskContext *tc)
3112 struct BlacklistCheck *bc = cls;
3113 struct Blacklisters *bl;
3115 bc->task = GNUNET_SCHEDULER_NO_TASK;
3119 bc->cont (bc->cont_cls,
3120 setup_new_neighbour (&bc->peer, bc->do_hello));
3127 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3128 sizeof (struct BlacklistMessage),
3129 GNUNET_TIME_UNIT_FOREVER_REL,
3130 &transmit_blacklist_message,
3137 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3138 * does not yet exist, check the blacklist. If the blacklist says creating
3139 * one is acceptable, create one and call the continuation; otherwise
3140 * call the continuation with NULL.
3142 * @param peer peer to setup or look up a struct NeighbourList for
3143 * @param do_hello should we also schedule sending our HELLO to the peer
3144 * if this is a new record
3145 * @param cont function to call with the 'struct NeigbhbourList*'
3146 * @param cont_cls closure for cont
3149 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3151 SetupContinuation cont,
3154 struct NeighbourList *n;
3155 struct BlacklistCheck *bc;
3157 n = find_neighbour(peer);
3164 if (bl_head == NULL)
3167 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3169 setup_new_neighbour(peer, do_hello);
3172 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3173 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3175 bc->do_hello = do_hello;
3177 bc->cont_cls = cont_cls;
3178 bc->bl_pos = bl_head;
3179 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3185 * Function called with the result of querying a new blacklister about
3186 * it being allowed (or not) to continue to talk to an existing neighbour.
3188 * @param cls the original 'struct NeighbourList'
3189 * @param n NULL if we need to disconnect
3192 confirm_or_drop_neighbour (void *cls,
3193 struct NeighbourList *n)
3195 struct NeighbourList * orig = cls;
3199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3200 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3201 "confirm_or_drop_neighboUr");
3202 disconnect_neighbour (orig, GNUNET_NO);
3208 * Handle a request to start a blacklist.
3210 * @param cls closure (always NULL)
3211 * @param client identification of the client
3212 * @param message the actual message
3215 handle_blacklist_init (void *cls,
3216 struct GNUNET_SERVER_Client *client,
3217 const struct GNUNET_MessageHeader *message)
3219 struct Blacklisters *bl;
3220 struct BlacklistCheck *bc;
3221 struct NeighbourList *n;
3226 if (bl->client == client)
3229 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3234 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3235 bl->client = client;
3236 GNUNET_SERVER_client_keep (client);
3237 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3238 /* confirm that all existing connections are OK! */
3242 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3243 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3245 bc->do_hello = GNUNET_NO;
3246 bc->cont = &confirm_or_drop_neighbour;
3249 if (n == neighbours) /* all would wait for the same client, no need to
3250 create more than just the first task right now */
3251 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3259 * Handle a request to blacklist a peer.
3261 * @param cls closure (always NULL)
3262 * @param client identification of the client
3263 * @param message the actual message
3266 handle_blacklist_reply (void *cls,
3267 struct GNUNET_SERVER_Client *client,
3268 const struct GNUNET_MessageHeader *message)
3270 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3271 struct Blacklisters *bl;
3272 struct BlacklistCheck *bc;
3275 while ( (bl != NULL) &&
3276 (bl->client != client) )
3280 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3285 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3287 bc->cont (bc->cont_cls, NULL);
3288 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3293 bc->bl_pos = bc->bl_pos->next;
3294 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3297 /* check if any other bc's are waiting for this blacklister */
3301 if ( (bc->bl_pos == bl) &&
3302 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3303 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3311 * Send periodic PING messages to a given foreign address.
3313 * @param cls our 'struct PeriodicValidationContext*'
3314 * @param tc task context
3317 send_periodic_ping (void *cls,
3318 const struct GNUNET_SCHEDULER_TaskContext *tc)
3320 struct ForeignAddressList *peer_address = cls;
3321 struct TransportPlugin *tp;
3322 struct ValidationEntry *va;
3323 struct NeighbourList *neighbour;
3324 struct TransportPingMessage ping;
3325 struct CheckAddressExistsClosure caec;
3327 uint16_t hello_size;
3331 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3332 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3334 tp = peer_address->ready_list->plugin;
3335 neighbour = peer_address->ready_list->neighbour;
3336 if (GNUNET_YES != neighbour->public_key_valid)
3338 /* no public key yet, try again later */
3339 schedule_next_ping (peer_address);
3342 caec.addr = peer_address->addr;
3343 caec.addrlen = peer_address->addrlen;
3344 caec.tname = tp->short_name;
3345 caec.session = peer_address->session;
3346 caec.exists = GNUNET_NO;
3347 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3348 &check_address_exists,
3350 if (caec.exists == GNUNET_YES)
3352 /* During validation attempts we will likely trigger the other
3353 peer trying to validate our address which in turn will cause
3354 it to send us its HELLO, so we expect to hit this case rather
3355 frequently. Only print something if we are very verbose. */
3356 #if DEBUG_TRANSPORT > 1
3357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3358 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3359 (peer_address->addr != NULL)
3360 ? a2s (tp->short_name,
3362 peer_address->addrlen)
3365 GNUNET_i2s (&neighbour->id));
3367 schedule_next_ping (peer_address);
3370 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3371 va->transport_name = GNUNET_strdup (tp->short_name);
3372 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3374 va->send_time = GNUNET_TIME_absolute_get();
3375 va->session = peer_address->session;
3376 if (peer_address->addr != NULL)
3378 va->addr = (const void*) &va[1];
3379 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3380 va->addrlen = peer_address->addrlen;
3382 memcpy(&va->publicKey,
3383 &neighbour->publicKey,
3384 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3386 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3387 &timeout_hello_validation,
3389 GNUNET_CONTAINER_multihashmap_put (validation_map,
3390 &neighbour->id.hashPubKey,
3392 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3394 if (peer_address->validated != GNUNET_YES)
3395 hello_size = GNUNET_HELLO_size(our_hello);
3399 tsize = sizeof(struct TransportPingMessage) + hello_size;
3401 if (peer_address->addr != NULL)
3403 slen = strlen (tp->short_name) + 1;
3404 tsize += slen + peer_address->addrlen;
3408 slen = 0; /* make gcc happy */
3410 message_buf = GNUNET_malloc(tsize);
3411 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3412 ping.challenge = htonl(va->challenge);
3413 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3414 if (peer_address->validated != GNUNET_YES)
3416 memcpy(message_buf, our_hello, hello_size);
3419 if (peer_address->addr != NULL)
3421 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3422 peer_address->addrlen +
3424 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3427 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3429 peer_address->addrlen);
3433 ping.header.size = htons(sizeof(struct TransportPingMessage));
3436 memcpy(&message_buf[hello_size],
3438 sizeof(struct TransportPingMessage));
3440 #if DEBUG_TRANSPORT_REVALIDATION
3441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3442 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3443 (peer_address->addr != NULL)
3444 ? a2s (peer_address->plugin->short_name,
3446 peer_address->addrlen)
3449 GNUNET_i2s (&neighbour->id),
3450 "HELLO", hello_size,
3453 if (peer_address->validated != GNUNET_YES)
3454 GNUNET_STATISTICS_update (stats,
3455 gettext_noop ("# PING with HELLO messages sent"),
3459 GNUNET_STATISTICS_update (stats,
3460 gettext_noop ("# PING without HELLO messages sent"),
3463 GNUNET_STATISTICS_update (stats,
3464 gettext_noop ("# PING messages sent for re-validation"),
3467 transmit_to_peer (NULL, peer_address,
3468 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3469 HELLO_VERIFICATION_TIMEOUT,
3471 GNUNET_YES, neighbour);
3472 GNUNET_free(message_buf);
3473 schedule_next_ping (peer_address);
3478 * Schedule the job that will cause us to send a PING to the
3479 * foreign address to evaluate its validity and latency.
3481 * @param fal address to PING
3484 schedule_next_ping (struct ForeignAddressList *fal)
3486 struct GNUNET_TIME_Relative delay;
3488 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3490 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3491 delay.rel_value /= 2; /* do before expiration */
3492 delay = GNUNET_TIME_relative_min (delay,
3493 LATENCY_EVALUATION_MAX_DELAY);
3494 if (GNUNET_YES != fal->estimated)
3496 delay = GNUNET_TIME_UNIT_ZERO;
3497 fal->estimated = GNUNET_YES;
3499 if (GNUNET_YES == fal->connected)
3501 delay = GNUNET_TIME_relative_min (delay,
3502 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3504 /* FIXME: also adjust delay based on how close the last
3505 observed latency is to the latency of the best alternative */
3506 /* bound how fast we can go */
3507 delay = GNUNET_TIME_relative_max (delay,
3508 GNUNET_TIME_UNIT_SECONDS);
3509 /* randomize a bit (to avoid doing all at the same time) */
3510 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3511 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3512 &send_periodic_ping,
3520 * Function that will be called if we receive some payload
3521 * from another peer.
3523 * @param message the payload
3524 * @param n peer who claimed to be the sender
3527 handle_payload_message (const struct GNUNET_MessageHeader *message,
3528 struct NeighbourList *n)
3530 struct InboundMessage *im;
3531 struct TransportClient *cpos;
3534 msize = ntohs (message->size);
3535 if (n->received_pong == GNUNET_NO)
3537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3538 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3539 ntohs (message->type),
3540 ntohs (message->size),
3541 GNUNET_i2s (&n->id));
3542 GNUNET_free_non_null (n->pre_connect_message_buffer);
3543 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3544 memcpy (n->pre_connect_message_buffer, message, msize);
3549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3550 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3551 ntohs (message->type),
3552 ntohs (message->size),
3553 GNUNET_i2s (&n->id));
3555 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3558 n->quota_violation_count++;
3560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3561 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3562 n->in_tracker.available_bytes_per_s__,
3563 n->quota_violation_count);
3565 /* Discount 32k per violation */
3566 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3571 if (n->quota_violation_count > 0)
3573 /* try to add 32k back */
3574 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3576 n->quota_violation_count--;
3579 GNUNET_STATISTICS_update (stats,
3580 gettext_noop ("# payload received from other peers"),
3583 /* transmit message to all clients */
3584 uint32_t ats_count = 2;
3585 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3586 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3589 im = GNUNET_malloc (size);
3590 im->header.size = htons (size);
3591 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3593 im->ats_count = htonl(ats_count);
3594 /* Setting ATS data */
3595 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3596 (&(im->ats))[0].value = htonl (n->distance);
3597 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3598 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3599 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3600 (&(im->ats))[ats_count].value = htonl (0);
3602 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3604 while (cpos != NULL)
3606 transmit_to_client (cpos, &im->header, GNUNET_YES);
3614 * Iterator over hash map entries. Checks if the given validation
3615 * entry is for the same challenge as what is given in the PONG.
3617 * @param cls the 'struct TransportPongMessage*'
3618 * @param key peer identity
3619 * @param value value in the hash map ('struct ValidationEntry')
3620 * @return GNUNET_YES if we should continue to
3621 * iterate (mismatch), GNUNET_NO if not (entry matched)
3624 check_pending_validation (void *cls,
3625 const GNUNET_HashCode * key,
3628 const struct TransportPongMessage *pong = cls;
3629 struct ValidationEntry *ve = value;
3630 struct AddValidatedAddressContext avac;
3631 unsigned int challenge = ntohl(pong->challenge);
3632 struct GNUNET_HELLO_Message *hello;
3633 struct GNUNET_PeerIdentity target;
3634 struct NeighbourList *n;
3635 struct ForeignAddressList *fal;
3636 struct OwnAddressList *oal;
3637 struct TransportPlugin *tp;
3638 struct GNUNET_MessageHeader *prem;
3644 ps = ntohs (pong->header.size);
3645 if (ps < sizeof (struct TransportPongMessage))
3647 GNUNET_break_op (0);
3650 addr = (const char*) &pong[1];
3651 slen = strlen (ve->transport_name) + 1;
3652 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3653 (ve->challenge != challenge) ||
3654 (addr[slen-1] != '\0') ||
3655 (0 != strcmp (addr, ve->transport_name)) ||
3656 (ntohl (pong->purpose.size)
3657 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3659 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3660 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3665 alen = ps - sizeof (struct TransportPongMessage) - slen;
3666 switch (ntohl (pong->purpose.purpose))
3668 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3669 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3670 (0 != memcmp (&addr[slen],
3674 return GNUNET_YES; /* different entry, keep trying! */
3676 if (0 != memcmp (&pong->pid,
3678 sizeof (struct GNUNET_PeerIdentity)))
3680 GNUNET_break_op (0);
3684 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3689 GNUNET_break_op (0);
3694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3695 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3697 a2s (ve->transport_name,
3698 (const struct sockaddr *) ve->addr,
3700 ve->transport_name);
3703 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3704 if (0 != memcmp (&pong->pid,
3706 sizeof (struct GNUNET_PeerIdentity)))
3708 GNUNET_break_op (0);
3711 if (ve->addrlen != 0)
3713 /* must have been for a different validation entry */
3716 tp = find_transport (ve->transport_name);
3722 oal = tp->addresses;
3725 if ( (oal->addrlen == alen) &&
3726 (0 == memcmp (&oal[1],
3734 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3735 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3736 a2s (ve->transport_name,
3742 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3747 GNUNET_break_op (0);
3752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3753 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3755 a2s (ve->transport_name,
3758 ve->transport_name);
3762 GNUNET_break_op (0);
3765 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3767 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3768 _("Received expired signature. Check system time.\n"));
3771 GNUNET_STATISTICS_update (stats,
3772 gettext_noop ("# address validation successes"),
3775 /* create the updated HELLO */
3776 GNUNET_CRYPTO_hash (&ve->publicKey,
3777 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3778 &target.hashPubKey);
3779 if (ve->addr != NULL)
3781 avac.done = GNUNET_NO;
3783 hello = GNUNET_HELLO_create (&ve->publicKey,
3784 &add_validated_address,
3786 GNUNET_PEERINFO_add_peer (peerinfo,
3788 GNUNET_free (hello);
3790 n = find_neighbour (&target);
3793 n->publicKey = ve->publicKey;
3794 n->public_key_valid = GNUNET_YES;
3795 fal = add_peer_address (n,
3800 GNUNET_assert (fal != NULL);
3801 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3802 fal->validated = GNUNET_YES;
3803 mark_address_connected (fal);
3804 GNUNET_STATISTICS_update (stats,
3805 gettext_noop ("# peer addresses considered valid"),
3808 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3809 schedule_next_ping (fal);
3810 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3811 n->latency = fal->latency;
3813 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3815 n->distance = fal->distance;
3816 if (GNUNET_NO == n->received_pong)
3818 n->received_pong = GNUNET_YES;
3820 notify_clients_connect (&target, n->latency, n->distance);
3821 if (NULL != (prem = n->pre_connect_message_buffer))
3823 n->pre_connect_message_buffer = NULL;
3824 handle_payload_message (prem, n);
3828 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3830 GNUNET_SCHEDULER_cancel (n->retry_task);
3831 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3832 try_transmission_to_peer (n);
3836 /* clean up validation entry */
3837 GNUNET_assert (GNUNET_YES ==
3838 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3841 abort_validation (NULL, NULL, ve);
3847 * Function that will be called if we receive a validation
3848 * of an address challenge that we transmitted to another
3849 * peer. Note that the validation should only be considered
3850 * acceptable if the challenge matches AND if the sender
3851 * address is at least a plausible address for this peer
3852 * (otherwise we may be seeing a MiM attack).
3854 * @param cls closure
3855 * @param message the pong message
3856 * @param peer who responded to our challenge
3857 * @param sender_address string describing our sender address (as observed
3858 * by the other peer in binary format)
3859 * @param sender_address_len number of bytes in 'sender_address'
3862 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3863 const struct GNUNET_PeerIdentity *peer,
3864 const char *sender_address,
3865 size_t sender_address_len)
3867 #if DEBUG_TRANSPORT > 1
3868 /* we get tons of these that just get discarded, only log
3869 if we are quite verbose */
3870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3871 "Receiving `%s' message from `%4s'.\n", "PONG",
3874 GNUNET_STATISTICS_update (stats,
3875 gettext_noop ("# PONG messages received"),
3878 if (GNUNET_SYSERR !=
3879 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3881 &check_pending_validation,
3884 /* This is *expected* to happen a lot since we send
3885 PONGs to *all* known addresses of the sender of
3886 the PING, so most likely we get multiple PONGs
3887 per PING, and all but the first PONG will end up
3888 here. So really we should not print anything here
3889 unless we want to be very, very verbose... */
3890 #if DEBUG_TRANSPORT > 2
3891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3892 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3904 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3906 * @param cls the 'struct ValidationEntry*'
3907 * @param neighbour neighbour to validate, NULL if validation failed
3910 transmit_hello_and_ping (void *cls,
3911 struct NeighbourList *neighbour)
3913 struct ValidationEntry *va = cls;
3914 struct ForeignAddressList *peer_address;
3915 struct TransportPingMessage ping;
3916 uint16_t hello_size;
3919 struct GNUNET_PeerIdentity id;
3922 GNUNET_CRYPTO_hash (&va->publicKey,
3923 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3925 if (neighbour == NULL)
3927 /* FIXME: stats... */
3928 GNUNET_break (GNUNET_OK ==
3929 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3932 abort_validation (NULL, NULL, va);
3935 neighbour->publicKey = va->publicKey;
3936 neighbour->public_key_valid = GNUNET_YES;
3937 peer_address = add_peer_address (neighbour,
3938 va->transport_name, NULL,
3939 (const void*) &va[1],
3941 if (peer_address == NULL)
3943 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3944 "Failed to add peer `%4s' for plugin `%s'\n",
3945 GNUNET_i2s (&neighbour->id),
3946 va->transport_name);
3947 GNUNET_break (GNUNET_OK ==
3948 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3951 abort_validation (NULL, NULL, va);
3954 hello_size = GNUNET_HELLO_size(our_hello);
3955 slen = strlen(va->transport_name) + 1;
3956 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3957 message_buf = GNUNET_malloc(tsize);
3958 ping.challenge = htonl(va->challenge);
3959 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3960 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3961 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3962 memcpy(message_buf, our_hello, hello_size);
3963 memcpy(&message_buf[hello_size],
3965 sizeof(struct TransportPingMessage));
3966 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3969 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3974 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3977 : a2s (va->transport_name,
3978 (const void*) &va[1], va->addrlen),
3980 GNUNET_i2s (&neighbour->id),
3981 "HELLO", hello_size,
3982 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3985 GNUNET_STATISTICS_update (stats,
3986 gettext_noop ("# PING messages sent for initial validation"),
3989 transmit_to_peer (NULL, peer_address,
3990 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3991 HELLO_VERIFICATION_TIMEOUT,
3993 GNUNET_YES, neighbour);
3994 GNUNET_free(message_buf);
3999 * Check if the given address is already being validated; if not,
4000 * append the given address to the list of entries that are being be
4001 * validated and initiate validation.
4003 * @param cls closure ('struct CheckHelloValidatedContext *')
4004 * @param tname name of the transport
4005 * @param expiration expiration time
4006 * @param addr the address
4007 * @param addrlen length of the address
4008 * @return GNUNET_OK (always)
4011 run_validation (void *cls,
4013 struct GNUNET_TIME_Absolute expiration,
4017 struct CheckHelloValidatedContext *chvc = cls;
4018 struct GNUNET_PeerIdentity id;
4019 struct TransportPlugin *tp;
4020 struct ValidationEntry *va;
4021 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4022 struct CheckAddressExistsClosure caec;
4023 struct OwnAddressList *oal;
4025 GNUNET_assert (addr != NULL);
4027 GNUNET_STATISTICS_update (stats,
4028 gettext_noop ("# peer addresses scheduled for validation"),
4031 tp = find_transport (tname);
4034 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4035 GNUNET_ERROR_TYPE_BULK,
4037 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4039 GNUNET_STATISTICS_update (stats,
4040 gettext_noop ("# peer addresses not validated (plugin not available)"),
4045 /* check if this is one of our own addresses */
4046 oal = tp->addresses;
4049 if ( (oal->addrlen == addrlen) &&
4050 (0 == memcmp (&oal[1],
4054 /* not plausible, this address is equivalent to our own address! */
4055 GNUNET_STATISTICS_update (stats,
4056 gettext_noop ("# peer addresses not validated (loopback)"),
4063 GNUNET_HELLO_get_key (chvc->hello, &pk);
4064 GNUNET_CRYPTO_hash (&pk,
4066 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4069 if (is_blacklisted(&id, tp))
4072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4073 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4081 caec.addrlen = addrlen;
4082 caec.session = NULL;
4084 caec.exists = GNUNET_NO;
4085 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4086 &check_address_exists,
4088 if (caec.exists == GNUNET_YES)
4090 /* During validation attempts we will likely trigger the other
4091 peer trying to validate our address which in turn will cause
4092 it to send us its HELLO, so we expect to hit this case rather
4093 frequently. Only print something if we are very verbose. */
4094 #if DEBUG_TRANSPORT > 1
4095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4096 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4097 a2s (tname, addr, addrlen),
4101 GNUNET_STATISTICS_update (stats,
4102 gettext_noop ("# peer addresses not validated (in progress)"),
4107 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4110 va->transport_name = GNUNET_strdup (tname);
4111 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4113 va->send_time = GNUNET_TIME_absolute_get();
4114 va->addr = (const void*) &va[1];
4115 memcpy (&va[1], addr, addrlen);
4116 va->addrlen = addrlen;
4117 GNUNET_HELLO_get_key (chvc->hello,
4119 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4120 &timeout_hello_validation,
4122 GNUNET_CONTAINER_multihashmap_put (validation_map,
4125 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4126 setup_peer_check_blacklist (&id, GNUNET_NO,
4127 &transmit_hello_and_ping,
4134 * Check if addresses in validated hello "h" overlap with
4135 * those in "chvc->hello" and validate the rest.
4137 * @param cls closure
4138 * @param peer id of the peer, NULL for last call
4139 * @param h hello message for the peer (can be NULL)
4140 * @param err_msg NULL if successful, otherwise contains error message
4143 check_hello_validated (void *cls,
4144 const struct GNUNET_PeerIdentity *peer,
4145 const struct GNUNET_HELLO_Message *h,
4146 const char *err_msg)
4148 struct CheckHelloValidatedContext *chvc = cls;
4149 struct GNUNET_HELLO_Message *plain_hello;
4150 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4151 struct GNUNET_PeerIdentity target;
4152 struct NeighbourList *n;
4154 if (err_msg != NULL)
4156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4157 _("Error in communication with PEERINFO service\n"));
4163 GNUNET_STATISTICS_update (stats,
4164 gettext_noop ("# outstanding peerinfo iterate requests"),
4168 if (GNUNET_NO == chvc->hello_known)
4170 /* notify PEERINFO about the peer now, so that we at least
4171 have the public key if some other component needs it */
4172 GNUNET_HELLO_get_key (chvc->hello, &pk);
4173 GNUNET_CRYPTO_hash (&pk,
4174 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4175 &target.hashPubKey);
4176 plain_hello = GNUNET_HELLO_create (&pk,
4179 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4180 GNUNET_free (plain_hello);
4181 #if DEBUG_TRANSPORT_HELLO
4182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4183 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4185 GNUNET_i2s (&target));
4187 GNUNET_STATISTICS_update (stats,
4188 gettext_noop ("# new HELLOs requiring full validation"),
4191 GNUNET_HELLO_iterate_addresses (chvc->hello,
4198 GNUNET_STATISTICS_update (stats,
4199 gettext_noop ("# duplicate HELLO (peer known)"),
4204 if (chvc->ve_count == 0)
4206 GNUNET_CONTAINER_DLL_remove (chvc_head,
4215 #if DEBUG_TRANSPORT_HELLO
4216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4217 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4221 chvc->hello_known = GNUNET_YES;
4222 n = find_neighbour (peer);
4225 #if DEBUG_TRANSPORT_HELLO
4226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4227 "Calling hello_iterate_addresses for %s!\n",
4230 GNUNET_HELLO_iterate_addresses (h,
4232 &add_to_foreign_address_list,
4234 try_transmission_to_peer (n);
4238 #if DEBUG_TRANSPORT_HELLO
4239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4240 "No existing neighbor record for %s!\n",
4243 GNUNET_STATISTICS_update (stats,
4244 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4248 GNUNET_STATISTICS_update (stats,
4249 gettext_noop ("# HELLO validations (update case)"),
4252 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4254 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4261 * Process HELLO-message.
4263 * @param plugin transport involved, may be NULL
4264 * @param message the actual message
4265 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4268 process_hello (struct TransportPlugin *plugin,
4269 const struct GNUNET_MessageHeader *message)
4272 struct GNUNET_PeerIdentity target;
4273 const struct GNUNET_HELLO_Message *hello;
4274 struct CheckHelloValidatedContext *chvc;
4275 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4276 #if DEBUG_TRANSPORT_HELLO > 2
4279 hsize = ntohs (message->size);
4280 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4281 (hsize < sizeof (struct GNUNET_MessageHeader)))
4284 return GNUNET_SYSERR;
4286 GNUNET_STATISTICS_update (stats,
4287 gettext_noop ("# HELLOs received for validation"),
4291 /* first, check if load is too high */
4292 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4294 GNUNET_STATISTICS_update (stats,
4295 gettext_noop ("# HELLOs ignored due to high load"),
4298 #if DEBUG_TRANSPORT_HELLO
4299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4300 "Ignoring `%s' for `%4s', load too high.\n",
4302 GNUNET_i2s (&target));
4306 hello = (const struct GNUNET_HELLO_Message *) message;
4307 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4309 #if DEBUG_TRANSPORT_HELLO
4310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4311 "Unable to get public key from `%s' for `%4s'!\n",
4313 GNUNET_i2s (&target));
4315 GNUNET_break_op (0);
4316 return GNUNET_SYSERR;
4319 GNUNET_CRYPTO_hash (&publicKey,
4320 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4321 &target.hashPubKey);
4323 #if DEBUG_TRANSPORT_HELLO
4324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4325 "Received `%s' message for `%4s'\n",
4327 GNUNET_i2s (&target));
4330 if (0 == memcmp (&my_identity,
4332 sizeof (struct GNUNET_PeerIdentity)))
4334 GNUNET_STATISTICS_update (stats,
4335 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4341 while (NULL != chvc)
4343 if (GNUNET_HELLO_equals (hello,
4345 GNUNET_TIME_absolute_get ()).abs_value > 0)
4347 #if DEBUG_TRANSPORT_HELLO > 2
4348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4349 "Received duplicate `%s' message for `%4s'; ignored\n",
4351 GNUNET_i2s (&target));
4353 return GNUNET_OK; /* validation already pending */
4355 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4356 GNUNET_break (0 != memcmp (hello, chvc->hello,
4357 GNUNET_HELLO_size(hello)));
4362 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4363 if ((NULL != temp_neighbor))
4365 fprintf(stderr, "Already know peer, ignoring hello\n");
4370 #if DEBUG_TRANSPORT_HELLO > 2
4373 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4375 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4378 GNUNET_i2s (&target),
4380 GNUNET_HELLO_size(hello));
4384 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4386 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4387 memcpy (&chvc[1], hello, hsize);
4388 GNUNET_CONTAINER_DLL_insert (chvc_head,
4391 /* finally, check if HELLO was previously validated
4392 (continuation will then schedule actual validation) */
4393 GNUNET_STATISTICS_update (stats,
4394 gettext_noop ("# peerinfo process hello iterate requests"),
4397 GNUNET_STATISTICS_update (stats,
4398 gettext_noop ("# outstanding peerinfo iterate requests"),
4401 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4403 HELLO_VERIFICATION_TIMEOUT,
4404 &check_hello_validated, chvc);
4410 * The peer specified by the given neighbour has timed-out or a plugin
4411 * has disconnected. We may either need to do nothing (other plugins
4412 * still up), or trigger a full disconnect and clean up. This
4413 * function updates our state and does the necessary notifications.
4414 * Also notifies our clients that the neighbour is now officially
4417 * @param n the neighbour list entry for the peer
4418 * @param check GNUNET_YES to check if ALL addresses for this peer
4419 * are gone, GNUNET_NO to force a disconnect of the peer
4420 * regardless of whether other addresses exist.
4423 disconnect_neighbour (struct NeighbourList *n, int check)
4425 struct ReadyList *rpos;
4426 struct NeighbourList *npos;
4427 struct NeighbourList *nprev;
4428 struct MessageQueue *mq;
4429 struct ForeignAddressList *peer_addresses;
4430 struct ForeignAddressList *peer_pos;
4432 if (GNUNET_YES == check)
4435 while (NULL != rpos)
4437 peer_addresses = rpos->addresses;
4438 while (peer_addresses != NULL)
4440 if (GNUNET_YES == peer_addresses->connected)
4442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4443 "NOT Disconnecting from `%4s', still have live addresses!\n",
4444 GNUNET_i2s (&n->id));
4445 return; /* still connected */
4447 peer_addresses = peer_addresses->next;
4453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4454 "Disconnecting from `%4s'\n",
4455 GNUNET_i2s (&n->id));
4457 /* remove n from neighbours list */
4460 while ((npos != NULL) && (npos != n))
4465 GNUNET_assert (npos != NULL);
4467 neighbours = n->next;
4469 nprev->next = n->next;
4471 /* notify all clients about disconnect */
4472 if (GNUNET_YES == n->received_pong)
4473 notify_clients_disconnect (&n->id);
4475 /* clean up all plugins, cancel connections and pending transmissions */
4476 while (NULL != (rpos = n->plugins))
4478 n->plugins = rpos->next;
4479 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4480 while (rpos->addresses != NULL)
4482 peer_pos = rpos->addresses;
4483 rpos->addresses = peer_pos->next;
4484 if (peer_pos->connected == GNUNET_YES)
4485 GNUNET_STATISTICS_update (stats,
4486 gettext_noop ("# connected addresses"),
4489 if (GNUNET_YES == peer_pos->validated)
4490 GNUNET_STATISTICS_update (stats,
4491 gettext_noop ("# peer addresses considered valid"),
4494 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4496 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4497 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4499 GNUNET_free(peer_pos);
4504 /* free all messages on the queue */
4505 while (NULL != (mq = n->messages_head))
4507 GNUNET_STATISTICS_update (stats,
4508 gettext_noop ("# bytes in message queue for other peers"),
4509 - (int64_t) mq->message_buf_size,
4511 GNUNET_STATISTICS_update (stats,
4512 gettext_noop ("# bytes discarded due to disconnect"),
4513 mq->message_buf_size,
4515 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4518 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4520 sizeof(struct GNUNET_PeerIdentity)));
4523 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4525 GNUNET_SCHEDULER_cancel (n->timeout_task);
4526 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4528 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4530 GNUNET_SCHEDULER_cancel (n->retry_task);
4531 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4533 if (n->piter != NULL)
4535 GNUNET_PEERINFO_iterate_cancel (n->piter);
4536 GNUNET_STATISTICS_update (stats,
4537 gettext_noop ("# outstanding peerinfo iterate requests"),
4542 /* finally, free n itself */
4543 GNUNET_STATISTICS_update (stats,
4544 gettext_noop ("# active neighbours"),
4547 GNUNET_free_non_null (n->pre_connect_message_buffer);
4553 * We have received a PING message from someone. Need to send a PONG message
4554 * in response to the peer by any means necessary.
4557 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4558 const struct GNUNET_PeerIdentity *peer,
4559 struct Session *session,
4560 const char *sender_address,
4561 uint16_t sender_address_len)
4563 struct TransportPlugin *plugin = cls;
4564 struct SessionHeader *session_header = (struct SessionHeader*) session;
4565 struct TransportPingMessage *ping;
4566 struct TransportPongMessage *pong;
4567 struct NeighbourList *n;
4568 struct ReadyList *rl;
4569 struct ForeignAddressList *fal;
4570 struct OwnAddressList *oal;
4575 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4577 GNUNET_break_op (0);
4578 return GNUNET_SYSERR;
4581 ping = (struct TransportPingMessage *) message;
4582 if (0 != memcmp (&ping->target,
4583 plugin->env.my_identity,
4584 sizeof (struct GNUNET_PeerIdentity)))
4586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4587 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4589 (sender_address != NULL)
4590 ? a2s (plugin->short_name,
4591 (const struct sockaddr *)sender_address,
4594 GNUNET_i2s (&ping->target));
4595 return GNUNET_SYSERR;
4598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4599 "Processing `%s' from `%s'\n",
4601 (sender_address != NULL)
4602 ? a2s (plugin->short_name,
4603 (const struct sockaddr *)sender_address,
4607 GNUNET_STATISTICS_update (stats,
4608 gettext_noop ("# PING messages received"),
4611 addr = (const char*) &ping[1];
4612 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4613 slen = strlen (plugin->short_name) + 1;
4616 /* peer wants to confirm that we have an outbound connection to him */
4617 if (session == NULL)
4619 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4620 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4622 return GNUNET_SYSERR;
4624 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4625 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4626 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4627 pong->purpose.size =
4628 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4630 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4631 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4632 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4633 pong->challenge = ping->challenge;
4634 pong->addrlen = htonl(sender_address_len + slen);
4637 sizeof(struct GNUNET_PeerIdentity));
4641 if ((sender_address!=NULL) && (sender_address_len > 0))
4642 memcpy (&((char*)&pong[1])[slen],
4644 sender_address_len);
4645 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4647 /* create / update cached sig */
4649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4650 "Creating PONG signature to indicate active connection.\n");
4652 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4653 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4654 GNUNET_assert (GNUNET_OK ==
4655 GNUNET_CRYPTO_rsa_sign (my_private_key,
4657 &session_header->pong_signature));
4661 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4663 memcpy (&pong->signature,
4664 &session_header->pong_signature,
4665 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4671 /* peer wants to confirm that this is one of our addresses */
4675 plugin->api->check_address (plugin->api->cls,
4679 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4680 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4681 a2s (plugin->short_name,
4686 oal = plugin->addresses;
4689 if ( (oal->addrlen == alen) &&
4696 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4697 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4698 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4699 pong->purpose.size =
4700 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4702 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4703 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4704 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4705 pong->challenge = ping->challenge;
4706 pong->addrlen = htonl(alen + slen);
4709 sizeof(struct GNUNET_PeerIdentity));
4710 memcpy (&pong[1], plugin->short_name, slen);
4711 memcpy (&((char*)&pong[1])[slen], addr, alen);
4712 if ( (oal != NULL) &&
4713 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4715 /* create / update cached sig */
4717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4718 "Creating PONG signature to indicate ownership.\n");
4720 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4721 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4722 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4723 GNUNET_assert (GNUNET_OK ==
4724 GNUNET_CRYPTO_rsa_sign (my_private_key,
4726 &oal->pong_signature));
4727 memcpy (&pong->signature,
4728 &oal->pong_signature,
4729 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4731 else if (oal == NULL)
4733 /* not using cache (typically DV-only) */
4734 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4735 GNUNET_assert (GNUNET_OK ==
4736 GNUNET_CRYPTO_rsa_sign (my_private_key,
4742 /* can used cached version */
4743 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4744 memcpy (&pong->signature,
4745 &oal->pong_signature,
4746 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4749 n = find_neighbour(peer);
4750 GNUNET_assert (n != NULL);
4751 /* first try reliable response transmission */
4755 fal = rl->addresses;
4758 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4761 ntohs (pong->header.size),
4762 TRANSPORT_PONG_PRIORITY,
4763 HELLO_VERIFICATION_TIMEOUT,
4771 GNUNET_STATISTICS_update (stats,
4772 gettext_noop ("# PONGs unicast via reliable transport"),
4782 /* no reliable method found, do multicast */
4783 GNUNET_STATISTICS_update (stats,
4784 gettext_noop ("# PONGs multicast to all available addresses"),
4790 fal = rl->addresses;
4793 transmit_to_peer(NULL, fal,
4794 TRANSPORT_PONG_PRIORITY,
4795 HELLO_VERIFICATION_TIMEOUT,
4797 ntohs(pong->header.size),
4810 * Function called by the plugin for each received message.
4811 * Update data volumes, possibly notify plugins about
4812 * reducing the rate at which they read from the socket
4813 * and generally forward to our receive callback.
4815 * @param cls the "struct TransportPlugin *" we gave to the plugin
4816 * @param peer (claimed) identity of the other peer
4817 * @param message the message, NULL if we only care about
4818 * learning about the delay until we should receive again
4819 * @param ats_data information for automatic transport selection
4820 * @param ats_count number of elements in ats not including 0-terminator
4821 * @param session identifier used for this session (can be NULL)
4822 * @param sender_address binary address of the sender (if observed)
4823 * @param sender_address_len number of bytes in sender_address
4824 * @return how long in ms the plugin should wait until receiving more data
4825 * (plugins that do not support this, can ignore the return value)
4827 static struct GNUNET_TIME_Relative
4828 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4829 const struct GNUNET_MessageHeader *message,
4830 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4832 struct Session *session,
4833 const char *sender_address,
4834 uint16_t sender_address_len)
4836 struct TransportPlugin *plugin = cls;
4837 struct ReadyList *service_context;
4838 struct ForeignAddressList *peer_address;
4840 struct NeighbourList *n;
4841 struct GNUNET_TIME_Relative ret;
4842 if (is_blacklisted (peer, plugin))
4843 return GNUNET_TIME_UNIT_FOREVER_REL;
4847 n = find_neighbour (peer);
4849 n = setup_new_neighbour (peer, GNUNET_YES);
4850 service_context = n->plugins;
4851 while ((service_context != NULL) && (plugin != service_context->plugin))
4852 service_context = service_context->next;
4853 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4854 peer_address = NULL;
4856 for (c=0; c<ats_count; c++)
4858 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4860 distance = ntohl(ats_data[c].value);
4863 /* notify ATS about incoming data */
4864 ats_notify_ats_data(peer, ats_data);
4866 if (message != NULL)
4868 if ( (session != NULL) ||
4869 (sender_address != NULL) )
4870 peer_address = add_peer_address (n,
4874 sender_address_len);
4875 if (peer_address != NULL)
4877 peer_address->distance = distance;
4878 if (GNUNET_YES == peer_address->validated)
4879 mark_address_connected (peer_address);
4880 peer_address->timeout
4882 GNUNET_TIME_relative_to_absolute
4883 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4884 schedule_next_ping (peer_address);
4886 /* update traffic received amount ... */
4887 msize = ntohs (message->size);
4888 GNUNET_STATISTICS_update (stats,
4889 gettext_noop ("# bytes received from other peers"),
4892 n->distance = distance;
4894 GNUNET_TIME_relative_to_absolute
4895 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4896 GNUNET_SCHEDULER_cancel (n->timeout_task);
4898 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4899 &neighbour_timeout_task, n);
4900 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4902 /* dropping message due to frequent inbound volume violations! */
4903 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4904 GNUNET_ERROR_TYPE_BULK,
4906 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4907 n->in_tracker.available_bytes_per_s__,
4908 n->quota_violation_count);
4909 GNUNET_STATISTICS_update (stats,
4910 gettext_noop ("# bandwidth quota violations by other peers"),
4913 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4918 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4919 ntohs (message->type),
4920 ntohs (message->size),
4923 switch (ntohs (message->type))
4925 case GNUNET_MESSAGE_TYPE_HELLO:
4926 GNUNET_STATISTICS_update (stats,
4927 gettext_noop ("# HELLO messages received from other peers"),
4930 process_hello (plugin, message);
4932 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4933 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4935 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4936 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4939 handle_payload_message (message, n);
4943 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4944 if (ret.rel_value > 0)
4946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4947 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4948 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4949 (unsigned int) n->in_tracker.available_bytes_per_s__,
4950 (unsigned long long) ret.rel_value);
4951 GNUNET_STATISTICS_update (stats,
4952 gettext_noop ("# ms throttling suggested"),
4953 (int64_t) ret.rel_value,
4960 * Handle START-message. This is the first message sent to us
4961 * by any client which causes us to add it to our list.
4963 * @param cls closure (always NULL)
4964 * @param client identification of the client
4965 * @param message the actual message
4968 handle_start (void *cls,
4969 struct GNUNET_SERVER_Client *client,
4970 const struct GNUNET_MessageHeader *message)
4972 const struct StartMessage *start;
4973 struct TransportClient *c;
4974 struct ConnectInfoMessage * cim;
4975 struct NeighbourList *n;
4979 start = (const struct StartMessage*) message;
4981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4982 "Received `%s' request from client\n", "START");
4987 if (c->client == client)
4989 /* client already on our list! */
4991 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4996 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4997 (0 != memcmp (&start->self,
4999 sizeof (struct GNUNET_PeerIdentity))) )
5001 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5002 _("Rejecting control connection from peer `%s', which is not me!\n"),
5003 GNUNET_i2s (&start->self));
5004 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5007 c = GNUNET_malloc (sizeof (struct TransportClient));
5011 if (our_hello != NULL)
5014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5015 "Sending our own `%s' to new client\n", "HELLO");
5017 transmit_to_client (c,
5018 (const struct GNUNET_MessageHeader *) our_hello,
5020 /* tell new client about all existing connections */
5022 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5023 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5027 cim = GNUNET_malloc (size);
5028 cim->header.size = htons (size);
5029 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5030 cim->ats_count = htonl(ats_count);
5031 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5032 (&(cim->ats))[2].value = htonl (0);
5036 if (GNUNET_YES == n->received_pong)
5038 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5039 (&(cim->ats))[0].value = htonl (n->distance);
5040 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5041 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5043 transmit_to_client (c, &cim->header, GNUNET_NO);
5049 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5054 * Handle HELLO-message.
5056 * @param cls closure (always NULL)
5057 * @param client identification of the client
5058 * @param message the actual message
5061 handle_hello (void *cls,
5062 struct GNUNET_SERVER_Client *client,
5063 const struct GNUNET_MessageHeader *message)
5067 GNUNET_STATISTICS_update (stats,
5068 gettext_noop ("# HELLOs received from clients"),
5071 ret = process_hello (NULL, message);
5072 GNUNET_SERVER_receive_done (client, ret);
5077 * Closure for 'transmit_client_message'; followed by
5078 * 'msize' bytes of the actual message.
5080 struct TransmitClientMessageContext
5083 * Client on whom's behalf we are sending.
5085 struct GNUNET_SERVER_Client *client;
5088 * Timeout for the transmission.
5090 struct GNUNET_TIME_Absolute timeout;
5098 * Size of the message in bytes.
5105 * Schedule transmission of a message we got from a client to a peer.
5107 * @param cls the 'struct TransmitClientMessageContext*'
5108 * @param n destination, or NULL on error (in that case, drop the message)
5111 transmit_client_message (void *cls,
5112 struct NeighbourList *n)
5114 struct TransmitClientMessageContext *tcmc = cls;
5115 struct TransportClient *tc;
5118 while ((tc != NULL) && (tc->client != tcmc->client))
5123 transmit_to_peer (tc, NULL, tcmc->priority,
5124 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5126 tcmc->msize, GNUNET_NO, n);
5128 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5129 GNUNET_SERVER_client_drop (tcmc->client);
5135 * Handle SEND-message.
5137 * @param cls closure (always NULL)
5138 * @param client identification of the client
5139 * @param message the actual message
5142 handle_send (void *cls,
5143 struct GNUNET_SERVER_Client *client,
5144 const struct GNUNET_MessageHeader *message)
5146 const struct OutboundMessage *obm;
5147 const struct GNUNET_MessageHeader *obmm;
5148 struct TransmitClientMessageContext *tcmc;
5152 size = ntohs (message->size);
5154 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5157 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5160 GNUNET_STATISTICS_update (stats,
5161 gettext_noop ("# payload received for other peers"),
5164 obm = (const struct OutboundMessage *) message;
5165 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5166 msize = size - sizeof (struct OutboundMessage);
5168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5169 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5170 "SEND", GNUNET_i2s (&obm->peer),
5174 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5175 tcmc->client = client;
5176 tcmc->priority = ntohl (obm->priority);
5177 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5178 tcmc->msize = msize;
5179 /* FIXME: this memcpy can be up to 7% of our total runtime */
5180 memcpy (&tcmc[1], obmm, msize);
5181 GNUNET_SERVER_client_keep (client);
5182 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5183 &transmit_client_message,
5189 * Handle request connect message
5191 * @param cls closure (always NULL)
5192 * @param client identification of the client
5193 * @param message the actual message
5196 handle_request_connect (void *cls,
5197 struct GNUNET_SERVER_Client *client,
5198 const struct GNUNET_MessageHeader *message)
5200 const struct TransportRequestConnectMessage *trcm =
5201 (const struct TransportRequestConnectMessage *) message;
5203 GNUNET_STATISTICS_update (stats,
5204 gettext_noop ("# REQUEST CONNECT messages received"),
5207 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5208 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5210 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5214 * Handle SET_QUOTA-message.
5216 * @param cls closure (always NULL)
5217 * @param client identification of the client
5218 * @param message the actual message
5221 handle_set_quota (void *cls,
5222 struct GNUNET_SERVER_Client *client,
5223 const struct GNUNET_MessageHeader *message)
5225 const struct QuotaSetMessage *qsm =
5226 (const struct QuotaSetMessage *) message;
5227 struct NeighbourList *n;
5229 GNUNET_STATISTICS_update (stats,
5230 gettext_noop ("# SET QUOTA messages received"),
5233 n = find_neighbour (&qsm->peer);
5236 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5237 GNUNET_STATISTICS_update (stats,
5238 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5245 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5247 (unsigned int) ntohl (qsm->quota.value__),
5248 (unsigned int) n->in_tracker.available_bytes_per_s__,
5249 GNUNET_i2s (&qsm->peer));
5251 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5253 if (0 == ntohl (qsm->quota.value__))
5255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5256 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5258 disconnect_neighbour (n, GNUNET_NO);
5260 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5265 * Take the given address and append it to the set of results sent back to
5268 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5269 * @param address the resolved name, NULL to indicate the last response
5272 transmit_address_to_client (void *cls, const char *address)
5274 struct GNUNET_SERVER_TransmitContext *tc = cls;
5277 if (NULL == address)
5280 slen = strlen (address) + 1;
5282 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5283 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5284 if (NULL == address)
5285 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5290 * Handle AddressLookup-message.
5292 * @param cls closure (always NULL)
5293 * @param client identification of the client
5294 * @param message the actual message
5297 handle_address_lookup (void *cls,
5298 struct GNUNET_SERVER_Client *client,
5299 const struct GNUNET_MessageHeader *message)
5301 const struct AddressLookupMessage *alum;
5302 struct TransportPlugin *lsPlugin;
5303 const char *nameTransport;
5304 const char *address;
5306 struct GNUNET_SERVER_TransmitContext *tc;
5307 struct GNUNET_TIME_Absolute timeout;
5308 struct GNUNET_TIME_Relative rtimeout;
5311 size = ntohs (message->size);
5312 if (size < sizeof (struct AddressLookupMessage))
5314 GNUNET_break_op (0);
5315 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5318 alum = (const struct AddressLookupMessage *) message;
5319 uint32_t addressLen = ntohl (alum->addrlen);
5320 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5322 GNUNET_break_op (0);
5323 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5326 address = (const char *) &alum[1];
5327 nameTransport = (const char *) &address[addressLen];
5329 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5331 GNUNET_break_op (0);
5332 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5335 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5336 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5337 numeric = ntohl (alum->numeric_only);
5338 lsPlugin = find_transport (nameTransport);
5339 if (NULL == lsPlugin)
5341 tc = GNUNET_SERVER_transmit_context_create (client);
5342 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5343 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5344 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5347 tc = GNUNET_SERVER_transmit_context_create (client);
5348 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5350 address, addressLen,
5353 &transmit_address_to_client, tc);
5358 * Setup the environment for this plugin.
5361 create_environment (struct TransportPlugin *plug)
5363 plug->env.cfg = cfg;
5364 plug->env.my_identity = &my_identity;
5365 plug->env.our_hello = &our_hello;
5366 plug->env.cls = plug;
5367 plug->env.receive = &plugin_env_receive;
5368 plug->env.notify_address = &plugin_env_notify_address;
5369 plug->env.session_end = &plugin_env_session_end;
5370 plug->env.max_connections = max_connect_per_transport;
5371 plug->env.stats = stats;
5376 * Start the specified transport (load the plugin).
5379 start_transport (struct GNUNET_SERVER_Handle *server,
5382 struct TransportPlugin *plug;
5385 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5386 _("Loading `%s' transport plugin\n"), name);
5387 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5388 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5389 create_environment (plug);
5390 plug->short_name = GNUNET_strdup (name);
5391 plug->lib_name = libname;
5392 plug->next = plugins;
5394 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5395 if (plug->api == NULL)
5397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5398 _("Failed to load transport plugin for `%s'\n"), name);
5399 GNUNET_free (plug->short_name);
5400 plugins = plug->next;
5401 GNUNET_free (libname);
5408 * Called whenever a client is disconnected. Frees our
5409 * resources associated with that client.
5411 * @param cls closure
5412 * @param client identification of the client
5415 client_disconnect_notification (void *cls,
5416 struct GNUNET_SERVER_Client *client)
5418 struct TransportClient *pos;
5419 struct TransportClient *prev;
5420 struct ClientMessageQueueEntry *mqe;
5421 struct Blacklisters *bl;
5422 struct BlacklistCheck *bc;
5427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5428 "Client disconnected, cleaning up.\n");
5430 /* clean up blacklister */
5434 if (bl->client == client)
5439 if (bc->bl_pos == bl)
5441 bc->bl_pos = bl->next;
5444 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5447 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5448 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5454 GNUNET_CONTAINER_DLL_remove (bl_head,
5457 GNUNET_SERVER_client_drop (bl->client);
5463 /* clean up 'normal' clients */
5466 while ((pos != NULL) && (pos->client != client))
5473 while (NULL != (mqe = pos->message_queue_head))
5475 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5476 pos->message_queue_tail,
5478 pos->message_count--;
5482 clients = pos->next;
5484 prev->next = pos->next;
5485 if (GNUNET_YES == pos->tcs_pending)
5490 if (pos->th != NULL)
5492 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5495 GNUNET_break (0 == pos->message_count);
5501 * Function called when the service shuts down. Unloads our plugins
5502 * and cancels pending validations.
5504 * @param cls closure, unused
5505 * @param tc task context (unused)
5508 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5510 struct TransportPlugin *plug;
5511 struct OwnAddressList *al;
5512 struct CheckHelloValidatedContext *chvc;
5513 struct ATS_plugin * rc;
5515 while (neighbours != NULL)
5517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5518 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5520 disconnect_neighbour (neighbours, GNUNET_NO);
5523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5524 "Transport service is unloading plugins...\n");
5526 while (NULL != (plug = plugins))
5528 plugins = plug->next;
5529 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5531 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5532 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5534 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5535 GNUNET_free (plug->lib_name);
5536 GNUNET_free (plug->short_name);
5537 while (NULL != (al = plug->addresses))
5539 plug->addresses = al->next;
5543 struct ATS_ressource_cost * t;
5544 while (rc->head != NULL)
5547 GNUNET_CONTAINER_DLL_remove(rc->head, rc->tail, rc->head);
5551 GNUNET_free(plug->rc);
5554 if (my_private_key != NULL)
5555 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5556 GNUNET_free_non_null (our_hello);
5558 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5561 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5562 validation_map = NULL;
5566 /* free 'chvc' data structure */
5567 while (NULL != (chvc = chvc_head))
5569 chvc_head = chvc->next;
5570 if (chvc->piter != NULL)
5572 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5573 GNUNET_STATISTICS_update (stats,
5574 gettext_noop ("# outstanding peerinfo iterate requests"),
5580 GNUNET_assert (chvc->ve_count == 0);
5587 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5590 if (peerinfo != NULL)
5592 GNUNET_PEERINFO_disconnect (peerinfo);
5595 /* Can we assume those are gone by now, or do we need to clean up
5597 GNUNET_break (bl_head == NULL);
5598 GNUNET_break (bc_head == NULL);
5601 struct ATS_mechanism
5603 struct ATS_mechanism * prev;
5604 struct ATS_mechanism * next;
5605 struct ForeignAddressList * addr;
5606 struct TransportPlugin * plugin;
5607 struct ATS_peer * peer;
5610 struct ATS_ressource_cost * rc;
5616 struct GNUNET_PeerIdentity peer;
5617 struct NeighbourList * n;
5618 struct ATS_mechanism * m_head;
5619 struct ATS_mechanism * m_tail;
5621 /* preference value f */
5633 struct ATS_ressource
5635 /* index in ressources array */
5637 /* depending ATSi parameter to calculcate limits */
5639 /* cfg option to load limits */
5646 /* cofficients for the specific plugins */
5656 static struct ATS_ressource ressources[] =
5658 /* FIXME: the coefficients for the specific plugins */
5659 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
5660 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
5661 {3, 4, "WLAN_ENERGY_LIMIT", VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
5663 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
5664 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
5665 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
5666 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
5669 static int available_ressources = 3;
5677 * Time of last execution
5679 struct GNUNET_TIME_Absolute last;
5681 * Minimum intervall between two executions
5683 struct GNUNET_TIME_Relative min_delta;
5685 * Regular intervall when execution is triggered
5687 struct GNUNET_TIME_Relative exec_intervall;
5689 * Maximum execution time per calculation
5691 struct GNUNET_TIME_Relative max_exec_duration;
5693 * Maximum number of LP iterations per calculation
5697 GNUNET_SCHEDULER_TaskIdentifier ats_task;
5699 struct ATS_plugin * head;
5700 struct ATS_plugin * tail;
5703 #define DEBUG_ATS GNUNET_YES
5704 #define VERBOSE_ATS GNUNET_NO
5707 /** solve the bandwidth distribution problem
5708 * @param max_it maximum iterations
5709 * @param max_dur maximum duration in ms
5710 * @param D weight for diversity
5711 * @param U weight for utility
5712 * @param R weight for relativity
5713 * @param v_b_min minimal bandwidth per peer
5714 * @param v_n_min minimum number of connections
5715 * @param res result struct
5716 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5718 static int ats_solve_problem (int max_it, int max_dur , double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
5721 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5722 return GNUNET_SYSERR;
5724 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5734 int c_c_ressources = 0;
5735 int c_q_metrics = available_quality_metrics;
5737 //double M = 10000000000; // ~10 GB
5738 //double M = VERY_BIG_DOUBLE_VALUE;
5740 double Q[c_q_metrics+1];
5741 for (c=1; c<=c_q_metrics; c++)
5746 struct NeighbourList *next = neighbours;
5749 struct ReadyList *r_next = next->plugins;
5750 while (r_next != NULL)
5752 struct ForeignAddressList * a_next = r_next->addresses;
5753 while (a_next != NULL)
5756 a_next = a_next->next;
5758 r_next = r_next->next;
5766 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5770 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5771 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5773 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
5779 peers[c_peers].peer = next->id;
5780 peers[c_peers].m_head = NULL;
5781 peers[c_peers].m_tail = NULL;
5783 peers[c_peers].f = 1.0 / c_mechs;
5785 struct ReadyList *r_next = next->plugins;
5786 while (r_next != NULL)
5788 struct ForeignAddressList * a_next = r_next->addresses;
5789 while (a_next != NULL)
5791 //struct ATS_ressource_cost *rc;
5793 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' plugin `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id), r_next->plugin->short_name, a_next);
5794 mechanisms[c_mechs].addr = a_next;
5795 mechanisms[c_mechs].col_index = c_mechs;
5796 mechanisms[c_mechs].peer = &peers[c_peers];
5797 mechanisms[c_mechs].next = NULL;
5798 mechanisms[c_mechs].plugin = r_next->plugin;
5799 mechanisms[c_mechs].rc = GNUNET_malloc (available_ressources * sizeof (struct ATS_ressource_cost));
5801 //rc = a_next->ressources;
5802 /* get address specific ressource costs */
5806 memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost));
5807 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Set address specific rc %s = %f \n", ressources[rc->index].cfg_param, mechanisms[c_mechs].rc[rc->index].c_1);
5811 // get plugin specific ressourc costs
5814 rc = mechanisms[c_mechs].plugin->rc->head;
5817 if ((mechanisms[c_mechs].rc[rc->index].c_1 == 0) && (rc->c_1 != 0))
5819 memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost));
5822 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Set plugin specific rc %s = %f \n", ressources[rc->index].cfg_param, mechanisms[c_mechs].rc[rc->index].c_1);
5826 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5828 a_next = a_next->next;
5830 r_next = r_next->next;
5838 if (v_n_min > c_peers)
5841 /* number of variables == coloumns */
5842 //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
5843 /* number of constraints == rows */
5844 //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
5846 if (VERBOSE_ATS) 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);
5848 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources ;
5849 //int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers + (c_q_metrics*c_mechs)+c_q_metrics + c_c_ressources ;
5852 int * ia = GNUNET_malloc (size * sizeof (int));
5853 int * ja = GNUNET_malloc (size * sizeof (int));
5854 double * ar = GNUNET_malloc(size* sizeof (double));
5856 prob = glp_create_prob();
5857 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5858 glp_set_obj_dir(prob, GLP_MAX);
5860 /* adding columns */
5862 glp_add_cols(prob, 2 * c_mechs);
5863 /* adding b_t cols */
5864 for (c=1; c <= c_mechs; c++)
5866 GNUNET_asprintf(&name, "b%i",c);
5867 glp_set_col_name(prob, c, name);
5869 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5870 glp_set_obj_coef(prob, c, 1);
5873 /* adding n_t cols */
5874 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5876 GNUNET_asprintf(&name, "n%i",(c-c_mechs));
5877 glp_set_col_name(prob, c, name);
5879 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5880 glp_set_col_kind(prob, c, GLP_IV);
5881 glp_set_obj_coef(prob, c, 0);
5884 /* feasibility constraints */
5885 /* Constraint 1: one address per peer*/
5886 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
5888 glp_add_rows(prob, c_peers);
5889 for (c=1; c<=c_peers; c++)
5891 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
5893 struct ATS_mechanism *m = peers[c].m_head;
5896 ia[array_index] = row_index;
5897 ja[array_index] = (c_mechs + m->col_index);
5898 ar[array_index] = 1;
5899 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5906 /* Constraint 2: only active mechanism gets bandwidth assigned */
5907 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
5908 glp_add_rows(prob, c_mechs);
5909 for (c=1; c<=c_mechs; c++)
5911 /* b_t - n_t * M <= 0 */
5912 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5913 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5915 ia[array_index] = row_index;
5916 ja[array_index] = mechanisms[c].col_index;
5917 ar[array_index] = 1;
5918 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5920 ia[array_index] = row_index;
5921 ja[array_index] = c_mechs + mechanisms[c].col_index;
5922 ar[array_index] = -M;
5923 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5928 /* Constraint 3: minimum bandwidth*/
5929 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5930 glp_add_rows(prob, c_mechs);
5931 for (c=1; c<=c_mechs; c++)
5933 /* b_t - n_t * b_min <= 0 */
5934 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5935 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5937 ia[array_index] = row_index;
5938 ja[array_index] = mechanisms[c].col_index;
5939 ar[array_index] = 1;
5940 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5942 ia[array_index] = row_index;
5943 ja[array_index] = c_mechs + mechanisms[c].col_index;
5944 ar[array_index] = -v_b_min;
5945 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5950 /* Constraint 4: max ressource capacity */
5951 /* V cr: bt * ct_r <= cr_max
5954 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 4\n");
5955 glp_add_rows(prob, available_ressources);
5956 //double ct_max = 0.0;
5957 //double ct_1 = 0.0;
5959 for (c=0; c<available_ressources; c++)
5961 ct_max = ressources[c].c_max;
5962 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f\n",row_index, ct_max);
5963 glp_set_row_bnds(prob, row_index, GLP_DB, 0.0, ct_max);
5965 for (c2=1; c2<=c_mechs; c2++)
5967 if (mechanisms[c2].rc[c].c_1 != 0)
5969 ia[array_index] = row_index;
5970 ja[array_index] = mechanisms[c2].col_index;
5971 ar[array_index] = mechanisms[c2].rc[c].c_1;
5972 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5979 /* Constraint 5: min number of connections*/
5980 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
5981 glp_add_rows(prob, 1);
5982 for (c=1; c<=c_mechs; c++)
5984 // b_t - n_t * b_min >= 0
5985 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5986 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
5988 ia[array_index] = row_index;
5989 ja[array_index] = c_mechs + mechanisms[c].col_index;
5990 ar[array_index] = 1;
5991 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5996 /* optimisation constraints*/
5998 /* adding columns */
5999 glp_add_cols(prob, 3 + c_q_metrics);
6001 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
6002 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
6003 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6004 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
6005 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
6006 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6007 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
6008 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
6009 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6011 for (c=1; c<= c_q_metrics; c++)
6013 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6014 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
6015 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6017 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6020 // Constraint 6: optimize for diversity
6021 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 6\n");
6022 glp_add_rows(prob, 1);
6023 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6024 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6025 //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6026 for (c=1; c<=c_mechs; c++)
6028 // b_t - n_t * b_min >= 0
6029 ia[array_index] = row_index;
6030 ja[array_index] = c_mechs + mechanisms[c].col_index;
6031 ar[array_index] = 1;
6032 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6035 ia[array_index] = row_index;
6036 ja[array_index] = (2*c_mechs) + 1;
6037 ar[array_index] = -1;
6038 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6043 // Constraint 7: optimize for quality
6045 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 7\n");
6046 glp_add_rows(prob, available_quality_metrics);
6047 for (c=1; c <= c_q_metrics; c++)
6049 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6050 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6052 for (c2=1; c2<=c_mechs; c2++)
6055 ia[array_index] = row_index;
6056 ja[array_index] = c2;
6057 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6059 if (mechanisms[c2].addr->latency.rel_value == -1)
6061 if (mechanisms[c2].addr->latency.rel_value == 0)
6064 value = 100 / (double) mechanisms[c2].addr->latency.rel_value;
6066 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DELAY VALUE %f %llu\n",value, mechanisms[c2].addr->latency.rel_value);
6068 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6070 if (mechanisms[c2].addr->distance == -1)
6072 else if (mechanisms[c2].addr->distance == 0)
6074 else value = (double) 10 / mechanisms[c2].addr->distance;
6075 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DISTANCE VALUE %f %lli\n",value, mechanisms[c2].addr->distance);
6077 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6078 //if (VERBOSE_ATS) 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]);
6082 ia[array_index] = row_index;
6083 ja[array_index] = (2*c_mechs) + 3 +c;
6084 ar[array_index] = -1;
6085 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6090 // Constraint 8: optimize bandwidth utility
6091 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 8\n");
6092 glp_add_rows(prob, 1);
6093 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6094 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6095 for (c=1; c<=c_mechs; c++)
6097 ia[array_index] = row_index;
6098 ja[array_index] = c;
6099 ar[array_index] = mechanisms[c].peer->f;
6100 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6103 ia[array_index] = row_index;
6104 ja[array_index] = (2*c_mechs) + 2;
6105 ar[array_index] = -1;
6107 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6113 // Constraint 9: optimize relativity
6114 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 9\n");
6115 glp_add_rows(prob, c_peers);
6116 for (c=1; c<=c_peers; c++)
6118 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6120 struct ATS_mechanism *m = peers[c].m_head;
6123 ia[array_index] = row_index;
6124 ja[array_index] = m->col_index;
6125 ar[array_index] = 1;
6126 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6130 ia[array_index] = row_index;
6131 ja[array_index] = (2*c_mechs) + 3;
6132 ar[array_index] = -1;
6133 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6138 glp_load_matrix(prob, array_index-1, ia, ja, ar);
6141 glp_init_smcp(&opt_lp);
6143 opt_lp.msg_lev = GLP_MSG_ALL;
6145 opt_lp.msg_lev = GLP_MSG_OFF;
6146 result = glp_simplex(prob, &opt_lp);
6149 glp_init_iocp(&opt_mlp);
6150 /* maximum duration */
6151 opt_mlp.tm_lim = max_dur;
6154 opt_mlp.msg_lev = GLP_MSG_ALL;
6156 opt_mlp.msg_lev = GLP_MSG_OFF;
6158 result = glp_intopt (prob, &opt_mlp);
6159 solution = glp_mip_status (prob);
6166 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",c_peers, c_mechs);
6167 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6168 glp_write_lp (prob, NULL, filename);
6169 GNUNET_free (filename);
6177 case GLP_ESTOP : /* search terminated by application */
6178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Search terminated by application ");
6180 case GLP_EITLIM : /* iteration limit exceeded */
6181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Iteration limit exceeded ");
6184 case GLP_ETMLIM : /* time limit exceeded */
6185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Time limit exceeded ");
6187 case GLP_ENOPFS : /* no primal feasible solution */
6188 case GLP_ENODFS : /* no dual feasible solution */
6189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No feasible solution");
6192 case GLP_EBADB : /* invalid basis */
6193 case GLP_ESING : /* singular matrix */
6194 case GLP_ECOND : /* ill-conditioned matrix */
6195 case GLP_EBOUND : /* invalid bounds */
6196 case GLP_EFAIL : /* solver failed */
6197 case GLP_EOBJLL : /* objective lower limit reached */
6198 case GLP_EOBJUL : /* objective upper limit reached */
6199 case GLP_EROOT : /* root LP optimum not provided */
6200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid Input data: %i\n", result);
6205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem has been solved\n");
6211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is undefined\n");
6214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer optimal\n");
6217 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n");
6220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MI problem has no integer feasible solution\n");
6228 int error = GNUNET_NO;
6230 struct ATS_mechanism *t = NULL;
6231 for (c=1; c<= (c_peers); c++ )
6234 t = peers[c].m_head;
6237 bw = glp_get_col_prim(prob, t->col_index);
6240 if (VERBOSE_ATS) 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);
6241 if (check ==GNUNET_YES)
6243 if (check ==GNUNET_NO)
6246 GNUNET_assert (error != GNUNET_YES);
6251 for (c=1; c<= c_q_metrics; c++ )
6253 if (VERBOSE_ATS) 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));
6255 if (VERBOSE_ATS) 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));
6256 if (VERBOSE_ATS) 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));
6257 if (VERBOSE_ATS) 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));
6259 res->c_mechs = c_mechs;
6260 res->c_peers = c_peers;
6261 res->solution = solution;
6266 glp_delete_prob(prob);
6272 for (c=0; c<c_mechs; c++)
6274 GNUNET_free_non_null (mechanisms[c].rc);
6277 GNUNET_free(mechanisms);
6284 void ats_calculate_bandwidth_distribution ()
6286 static int glpk = GNUNET_YES;
6287 struct GNUNET_TIME_Absolute start;
6288 struct GNUNET_TIME_Relative duration;
6289 struct ATS_result result;
6292 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6293 if (delta.rel_value < ats->min_delta.rel_value)
6296 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6302 if (INT_MAX < ats->max_exec_duration.rel_value)
6305 dur = (int) ats->max_exec_duration.rel_value;
6307 start = GNUNET_TIME_absolute_get();
6309 if (glpk==GNUNET_YES)
6311 start = GNUNET_TIME_absolute_get();
6312 c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result);
6313 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6316 if (DEBUG_ATS) {GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);}
6317 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6318 GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6319 GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6320 GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6321 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6323 else if (c_mechs == 0)
6325 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6327 else glpk = GNUNET_NO;
6329 ats->last = GNUNET_TIME_absolute_get();
6335 ats_schedule_calculation (void *cls,
6336 const struct GNUNET_SCHEDULER_TaskContext *tc)
6338 struct ATS_info *ats = (struct ATS_info *) cls;
6342 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6343 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6349 ats_calculate_bandwidth_distribution (ats);
6351 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6352 &ats_schedule_calculation, ats);
6357 ats = GNUNET_malloc(sizeof (struct ATS_info));
6359 ats->min_delta = ATS_MIN_INTERVAL;
6360 ats->exec_intervall = ATS_EXEC_INTERVAL;
6361 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6362 ats->max_iterations = ATS_MAX_ITERATIONS;
6363 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6366 unsigned long long value;
6368 /* loading cost ressources */
6369 for (c=0; c<available_ressources; c++)
6371 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6372 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6374 GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6375 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6376 ressources[c].c_max = value;
6378 GNUNET_free (section);
6379 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6380 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6382 GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6383 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6384 ressources[c].c_min = value;
6386 GNUNET_free (section);
6389 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6393 void ats_shutdown ()
6396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6398 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6399 GNUNET_SCHEDULER_cancel(ats->ats_task);
6400 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6402 struct ATS_plugin * p;
6403 struct ATS_ressource_cost * rc;
6407 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6411 GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6415 GNUNET_free(p->short_name);
6424 void ats_notify_peer_connect (
6425 const struct GNUNET_PeerIdentity *peer,
6426 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6430 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6433 while (ntohl(ats_data[c].type)!=0)
6436 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6440 ats_calculate_bandwidth_distribution(ats);
6443 void ats_notify_peer_disconnect (
6444 const struct GNUNET_PeerIdentity *peer)
6447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6449 ats_calculate_bandwidth_distribution (ats);
6453 void ats_notify_ats_data (
6454 const struct GNUNET_PeerIdentity *peer,
6455 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6458 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6460 ats_calculate_bandwidth_distribution(ats);
6463 struct ForeignAddressList * ats_get_preferred_address (
6464 struct NeighbourList *n)
6467 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6469 struct ReadyList *next = n->plugins;
6470 while (next != NULL)
6473 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6477 return find_ready_address(n);
6481 * Initiate transport service.
6483 * @param cls closure
6484 * @param server the initialized server
6485 * @param c configuration to use
6489 struct GNUNET_SERVER_Handle *server,
6490 const struct GNUNET_CONFIGURATION_Handle *c)
6492 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6493 {&handle_start, NULL,
6494 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6495 {&handle_hello, NULL,
6496 GNUNET_MESSAGE_TYPE_HELLO, 0},
6497 {&handle_send, NULL,
6498 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6499 {&handle_request_connect, NULL,
6500 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6501 {&handle_set_quota, NULL,
6502 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6503 {&handle_address_lookup, NULL,
6504 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6506 {&handle_blacklist_init, NULL,
6507 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6508 {&handle_blacklist_reply, NULL,
6509 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6515 unsigned long long tneigh;
6519 stats = GNUNET_STATISTICS_create ("transport", cfg);
6520 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6521 /* parse configuration */
6523 GNUNET_CONFIGURATION_get_value_number (c,
6528 GNUNET_CONFIGURATION_get_value_filename (c,
6530 "HOSTKEY", &keyfile)))
6532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6534 ("Transport service is lacking key configuration settings. Exiting.\n"));
6535 GNUNET_SCHEDULER_shutdown ();
6538 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6541 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6542 validation_map = NULL;
6546 max_connect_per_transport = (uint32_t) tneigh;
6547 peerinfo = GNUNET_PEERINFO_connect (cfg);
6548 if (peerinfo == NULL)
6550 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6551 _("Could not access PEERINFO service. Exiting.\n"));
6552 GNUNET_SCHEDULER_shutdown ();
6555 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6558 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6559 validation_map = NULL;
6560 GNUNET_free (keyfile);
6563 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6564 GNUNET_free (keyfile);
6565 if (my_private_key == NULL)
6567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6569 ("Transport service could not access hostkey. Exiting.\n"));
6570 GNUNET_SCHEDULER_shutdown ();
6573 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6576 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6577 validation_map = NULL;
6580 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6581 GNUNET_CRYPTO_hash (&my_public_key,
6582 sizeof (my_public_key), &my_identity.hashPubKey);
6583 /* setup notification */
6584 GNUNET_SERVER_disconnect_notify (server,
6585 &client_disconnect_notification, NULL);
6586 /* load plugins... */
6589 GNUNET_CONFIGURATION_get_value_string (c,
6590 "TRANSPORT", "PLUGINS", &plugs))
6592 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6593 _("Starting transport plugins `%s'\n"), plugs);
6594 pos = strtok (plugs, " ");
6597 start_transport (server, pos);
6599 pos = strtok (NULL, " ");
6601 GNUNET_free (plugs);
6603 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6604 &shutdown_task, NULL);
6611 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6613 /* If we have a blacklist file, read from it */
6614 read_blacklist_file(cfg);
6615 /* process client requests */
6616 GNUNET_SERVER_add_handlers (server, handlers);
6621 * The main function for the transport service.
6623 * @param argc number of arguments from the command line
6624 * @param argv command line arguments
6625 * @return 0 ok, 1 on error
6628 main (int argc, char *const *argv)
6630 a2s (NULL, NULL, 0); /* make compiler happy */
6631 return (GNUNET_OK ==
6632 GNUNET_SERVICE_run (argc,
6635 GNUNET_SERVICE_OPTION_NONE,
6636 &run, NULL)) ? 0 : 1;
6639 /* end of gnunet-service-transport.c */