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;
943 static struct ATS_quality_metric qm[] =
945 {1, 1028, "QUALITY_NET_DISTANCE"},
946 {2, 1034, "QUALITY_NET_DELAY"},
948 static int available_quality_metrics = 2;
951 * The peer specified by the given neighbour has timed-out or a plugin
952 * has disconnected. We may either need to do nothing (other plugins
953 * still up), or trigger a full disconnect and clean up. This
954 * function updates our state and do the necessary notifications.
955 * Also notifies our clients that the neighbour is now officially
958 * @param n the neighbour list entry for the peer
959 * @param check should we just check if all plugins
960 * disconnected or must we ask all plugins to
963 static void disconnect_neighbour (struct NeighbourList *n, int check);
966 * Check the ready list for the given neighbour and if a plugin is
967 * ready for transmission (and if we have a message), do so!
969 * @param nexi target peer for which to transmit
971 static void try_transmission_to_peer (struct NeighbourList *n);
974 struct ATS_info * ats_init ();
976 void ats_shutdown ( );
978 void ats_notify_peer_connect (
979 const struct GNUNET_PeerIdentity *peer,
980 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
982 void ats_notify_peer_disconnect (
983 const struct GNUNET_PeerIdentity *peer);
985 void ats_notify_ats_data (
986 const struct GNUNET_PeerIdentity *peer,
987 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
989 struct ForeignAddressList * ats_get_preferred_address (
990 struct NeighbourList *n);
993 * Find an entry in the neighbour list for a particular peer.
995 * @return NULL if not found.
997 static struct NeighbourList *
998 find_neighbour (const struct GNUNET_PeerIdentity *key)
1000 struct NeighbourList *head = neighbours;
1002 while ((head != NULL) &&
1003 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1010 * Find an entry in the transport list for a particular transport.
1012 * @return NULL if not found.
1014 static struct TransportPlugin *
1015 find_transport (const char *short_name)
1017 struct TransportPlugin *head = plugins;
1018 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1024 * Is a particular peer blacklisted for a particular transport?
1026 * @param peer the peer to check for
1027 * @param plugin the plugin used to connect to the peer
1029 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1032 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1035 if (plugin->blacklist != NULL)
1037 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1041 "Peer `%s:%s' is blacklisted!\n",
1042 plugin->short_name, GNUNET_i2s (peer));
1045 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1055 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1057 struct TransportPlugin *plugin;
1059 plugin = find_transport(transport_name);
1060 if (plugin == NULL) /* Nothing to do */
1062 if (plugin->blacklist == NULL)
1063 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1064 GNUNET_assert(plugin->blacklist != NULL);
1065 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1067 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1072 * Read the blacklist file, containing transport:peer entries.
1073 * Provided the transport is loaded, set up hashmap with these
1074 * entries to blacklist peers by transport.
1078 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1085 struct GNUNET_PeerIdentity pid;
1087 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1088 unsigned int entries_found;
1089 char *transport_name;
1092 GNUNET_CONFIGURATION_get_value_filename (cfg,
1098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099 "Option `%s' in section `%s' not specified!\n",
1105 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1106 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1107 | GNUNET_DISK_PERM_USER_WRITE);
1108 if (0 != STAT (fn, &frstat))
1110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1111 _("Could not read blacklist file `%s'\n"), fn);
1115 if (frstat.st_size == 0)
1118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1119 _("Blacklist file `%s' is empty.\n"),
1125 /* FIXME: use mmap */
1126 data = GNUNET_malloc_large (frstat.st_size);
1127 GNUNET_assert(data != NULL);
1128 if (frstat.st_size !=
1129 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1132 _("Failed to read blacklist from `%s'\n"), fn);
1139 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1141 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1142 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1145 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1148 if (colon_pos >= frstat.st_size)
1150 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1151 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1152 (unsigned long long) colon_pos);
1158 if (isspace( (unsigned char) data[colon_pos]))
1160 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1161 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1162 (unsigned long long) colon_pos);
1164 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1168 tsize = colon_pos - pos;
1169 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1171 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1172 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1173 (unsigned long long) colon_pos);
1182 transport_name = GNUNET_malloc(tsize + 1);
1183 memcpy(transport_name, &data[pos], tsize);
1184 pos = colon_pos + 1;
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Read transport name %s in blacklist file.\n",
1190 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1191 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1193 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1194 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1195 (unsigned long long) pos);
1197 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1199 GNUNET_free_non_null(transport_name);
1202 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1203 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1206 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1207 (unsigned long long) pos,
1212 if (0 != memcmp (&pid,
1214 sizeof (struct GNUNET_PeerIdentity)))
1217 add_peer_to_blacklist (&pid,
1222 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1223 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1227 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1228 GNUNET_free_non_null(transport_name);
1229 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1232 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1239 * Function called to notify a client about the socket being ready to
1240 * queue more data. "buf" will be NULL and "size" zero if the socket
1241 * was closed for writing in the meantime.
1243 * @param cls closure
1244 * @param size number of bytes available in buf
1245 * @param buf where the callee should write the message
1246 * @return number of bytes written to buf
1249 transmit_to_client_callback (void *cls, size_t size, void *buf)
1251 struct TransportClient *client = cls;
1252 struct ClientMessageQueueEntry *q;
1255 const struct GNUNET_MessageHeader *msg;
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "Transmission to client failed, closing connection.\n");
1265 /* fatal error with client, free message queue! */
1266 while (NULL != (q = client->message_queue_head))
1268 GNUNET_STATISTICS_update (stats,
1269 gettext_noop ("# bytes discarded (could not transmit to client)"),
1270 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1272 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1273 client->message_queue_tail,
1277 client->message_count = 0;
1282 while (NULL != (q = client->message_queue_head))
1284 msg = (const struct GNUNET_MessageHeader *) &q[1];
1285 msize = ntohs (msg->size);
1286 if (msize + tsize > size)
1289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1290 "Transmitting message of type %u to client.\n",
1293 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1294 client->message_queue_tail,
1296 memcpy (&cbuf[tsize], msg, msize);
1299 client->message_count--;
1303 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1304 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1306 GNUNET_TIME_UNIT_FOREVER_REL,
1307 &transmit_to_client_callback,
1309 GNUNET_assert (client->th != NULL);
1316 * Convert an address to a string.
1318 * @param plugin name of the plugin responsible for the address
1319 * @param addr binary address
1320 * @param addr_len number of bytes in addr
1321 * @return NULL on error, otherwise address string
1324 a2s (const char *plugin,
1328 struct TransportPlugin *p;
1332 p = find_transport (plugin);
1335 return p->api->address_to_string (p->api->cls,
1342 * Mark the given FAL entry as 'connected' (and hence preferred for
1343 * sending); also mark all others for the same peer as 'not connected'
1344 * (since only one can be preferred).
1346 * @param fal address to set to 'connected'
1349 mark_address_connected (struct ForeignAddressList *fal)
1351 struct ForeignAddressList *pos;
1354 GNUNET_assert (GNUNET_YES == fal->validated);
1355 if (fal->connected == GNUNET_YES)
1356 return; /* nothing to do */
1358 pos = fal->ready_list->addresses;
1361 if (GNUNET_YES == pos->connected)
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1366 a2s (pos->ready_list->plugin->short_name,
1370 GNUNET_break (cnt == GNUNET_YES);
1372 pos->connected = GNUNET_NO;
1373 GNUNET_STATISTICS_update (stats,
1374 gettext_noop ("# connected addresses"),
1380 fal->connected = GNUNET_YES;
1381 if (GNUNET_YES == cnt)
1383 GNUNET_STATISTICS_update (stats,
1384 gettext_noop ("# connected addresses"),
1392 * Send the specified message to the specified client. Since multiple
1393 * messages may be pending for the same client at a time, this code
1394 * makes sure that no message is lost.
1396 * @param client client to transmit the message to
1397 * @param msg the message to send
1398 * @param may_drop can this message be dropped if the
1399 * message queue for this client is getting far too large?
1402 transmit_to_client (struct TransportClient *client,
1403 const struct GNUNET_MessageHeader *msg, int may_drop)
1405 struct ClientMessageQueueEntry *q;
1408 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1412 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1415 client->message_count,
1417 GNUNET_STATISTICS_update (stats,
1418 gettext_noop ("# messages dropped due to slow client"),
1423 msize = ntohs (msg->size);
1424 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1425 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1426 memcpy (&q[1], msg, msize);
1427 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1428 client->message_queue_tail,
1429 client->message_queue_tail,
1431 client->message_count++;
1432 if (client->th == NULL)
1434 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1436 GNUNET_TIME_UNIT_FOREVER_REL,
1437 &transmit_to_client_callback,
1439 GNUNET_assert (client->th != NULL);
1445 * Transmit a 'SEND_OK' notification to the given client for the
1448 * @param client who to notify
1449 * @param n neighbour to notify about, can be NULL (on failure)
1450 * @param target target of the transmission
1451 * @param result status code for the transmission request
1454 transmit_send_ok (struct TransportClient *client,
1455 struct NeighbourList *n,
1456 const struct GNUNET_PeerIdentity *target,
1459 struct SendOkMessage send_ok_msg;
1461 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1462 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1463 send_ok_msg.success = htonl (result);
1465 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1467 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1468 send_ok_msg.peer = *target;
1469 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1474 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1475 * upon "completion" of a send request. This tells the API
1476 * that it is now legal to send another message to the given
1479 * @param cls closure, identifies the entry on the
1480 * message queue that was transmitted and the
1481 * client responsible for queuing the message
1482 * @param target the peer receiving the message
1483 * @param result GNUNET_OK on success, if the transmission
1484 * failed, we should not tell the client to transmit
1488 transmit_send_continuation (void *cls,
1489 const struct GNUNET_PeerIdentity *target,
1492 struct MessageQueue *mq = cls;
1493 struct NeighbourList *n;
1495 GNUNET_STATISTICS_update (stats,
1496 gettext_noop ("# bytes pending with plugins"),
1497 - (int64_t) mq->message_buf_size,
1499 if (result == GNUNET_OK)
1501 GNUNET_STATISTICS_update (stats,
1502 gettext_noop ("# bytes successfully transmitted by plugins"),
1503 mq->message_buf_size,
1508 GNUNET_STATISTICS_update (stats,
1509 gettext_noop ("# bytes with transmission failure by plugins"),
1510 mq->message_buf_size,
1513 if (mq->specific_address != NULL)
1515 if (result == GNUNET_OK)
1517 mq->specific_address->timeout =
1518 GNUNET_TIME_relative_to_absolute
1519 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1520 if (mq->specific_address->validated == GNUNET_YES)
1521 mark_address_connected (mq->specific_address);
1525 if (mq->specific_address->connected != GNUNET_NO)
1528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1529 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1530 a2s (mq->specific_address->ready_list->plugin->short_name,
1531 mq->specific_address->addr,
1532 mq->specific_address->addrlen));
1534 GNUNET_STATISTICS_update (stats,
1535 gettext_noop ("# connected addresses"),
1538 mq->specific_address->connected = GNUNET_NO;
1541 if (! mq->internal_msg)
1542 mq->specific_address->in_transmit = GNUNET_NO;
1544 n = find_neighbour(&mq->neighbour_id);
1545 if (mq->client != NULL)
1546 transmit_send_ok (mq->client, n, target, result);
1549 try_transmission_to_peer (n);
1554 * Find an address in any of the available transports for
1555 * the given neighbour that would be good for message
1556 * transmission. This is essentially the transport selection
1559 * @param neighbour for whom to select an address
1560 * @return selected address, NULL if we have none
1562 struct ForeignAddressList *
1563 find_ready_address(struct NeighbourList *neighbour)
1565 struct ReadyList *head = neighbour->plugins;
1566 struct ForeignAddressList *addresses;
1567 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1568 struct ForeignAddressList *best_address;
1570 /* Hack to prefer unix domain sockets */
1571 struct ForeignAddressList *unix_address = NULL;
1573 best_address = NULL;
1574 while (head != NULL)
1576 addresses = head->addresses;
1577 while (addresses != NULL)
1579 if ( (addresses->timeout.abs_value < now.abs_value) &&
1580 (addresses->connected == GNUNET_YES) )
1583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1584 "Marking long-time inactive connection to `%4s' as down.\n",
1585 GNUNET_i2s (&neighbour->id));
1587 GNUNET_STATISTICS_update (stats,
1588 gettext_noop ("# connected addresses"),
1591 addresses->connected = GNUNET_NO;
1593 addresses = addresses->next;
1596 addresses = head->addresses;
1597 while (addresses != NULL)
1599 #if DEBUG_TRANSPORT > 1
1600 if (addresses->addr != NULL)
1601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1602 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1603 a2s (head->plugin->short_name,
1605 addresses->addrlen),
1606 GNUNET_i2s (&neighbour->id),
1607 addresses->connected,
1608 addresses->in_transmit,
1609 addresses->validated,
1610 addresses->connect_attempts,
1611 (unsigned long long) addresses->timeout.abs_value,
1612 (unsigned int) addresses->distance);
1614 if (0==strcmp(head->plugin->short_name,"unix"))
1616 if ((unix_address == NULL) || ((unix_address != NULL) &&
1617 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1618 unix_address = addresses;
1620 if ( ( (best_address == NULL) ||
1621 (addresses->connected == GNUNET_YES) ||
1622 (best_address->connected == GNUNET_NO) ) &&
1623 (addresses->in_transmit == GNUNET_NO) &&
1624 ( (best_address == NULL) ||
1625 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1626 best_address = addresses;
1627 /* FIXME: also give lower-latency addresses that are not
1628 connected a chance some times... */
1629 addresses = addresses->next;
1631 if (unix_address != NULL)
1635 if (unix_address != NULL)
1637 best_address = unix_address;
1639 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1642 if (best_address != NULL)
1646 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1647 "Best address found (`%s') has latency of %llu ms.\n",
1648 (best_address->addrlen > 0)
1649 ? a2s (best_address->ready_list->plugin->short_name,
1651 best_address->addrlen)
1653 best_address->latency.rel_value);
1658 GNUNET_STATISTICS_update (stats,
1659 gettext_noop ("# transmission attempts failed (no address)"),
1664 return best_address;
1670 * We should re-try transmitting to the given peer,
1671 * hopefully we've learned something in the meantime.
1674 retry_transmission_task (void *cls,
1675 const struct GNUNET_SCHEDULER_TaskContext *tc)
1677 struct NeighbourList *n = cls;
1679 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1680 try_transmission_to_peer (n);
1685 * Check the ready list for the given neighbour and if a plugin is
1686 * ready for transmission (and if we have a message), do so!
1688 * @param neighbour target peer for which to transmit
1691 try_transmission_to_peer (struct NeighbourList *n)
1693 struct ReadyList *rl;
1694 struct MessageQueue *mq;
1695 struct GNUNET_TIME_Relative timeout;
1699 if (n->messages_head == NULL)
1702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1703 "Transmission queue for `%4s' is empty\n",
1704 GNUNET_i2s (&neighbour->id));
1706 return; /* nothing to do */
1709 mq = n->messages_head;
1710 force_address = GNUNET_YES;
1711 if (mq->specific_address == NULL)
1714 mq->specific_address = ats_get_preferred_address(n);
1715 GNUNET_STATISTICS_update (stats,
1716 gettext_noop ("# transport selected peer address freely"),
1719 force_address = GNUNET_NO;
1721 if (mq->specific_address == NULL)
1723 GNUNET_STATISTICS_update (stats,
1724 gettext_noop ("# transport failed to selected peer address"),
1727 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1728 if (timeout.rel_value == 0)
1731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732 "No destination address available to transmit message of size %u to peer `%4s'\n",
1733 mq->message_buf_size,
1734 GNUNET_i2s (&mq->neighbour_id));
1736 GNUNET_STATISTICS_update (stats,
1737 gettext_noop ("# bytes in message queue for other peers"),
1738 - (int64_t) mq->message_buf_size,
1740 GNUNET_STATISTICS_update (stats,
1741 gettext_noop ("# bytes discarded (no destination address available)"),
1742 mq->message_buf_size,
1744 if (mq->client != NULL)
1745 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1746 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1750 return; /* nobody ready */
1752 GNUNET_STATISTICS_update (stats,
1753 gettext_noop ("# message delivery deferred (no address)"),
1756 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1757 GNUNET_SCHEDULER_cancel (n->retry_task);
1758 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1759 &retry_transmission_task,
1762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1763 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1764 mq->message_buf_size,
1765 GNUNET_i2s (&mq->neighbour_id),
1768 /* FIXME: might want to trigger peerinfo lookup here
1769 (unless that's already pending...) */
1772 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1775 if (mq->specific_address->connected == GNUNET_NO)
1776 mq->specific_address->connect_attempts++;
1777 rl = mq->specific_address->ready_list;
1778 mq->plugin = rl->plugin;
1779 if (!mq->internal_msg)
1780 mq->specific_address->in_transmit = GNUNET_YES;
1782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1784 mq->message_buf_size,
1785 GNUNET_i2s (&neighbour->id),
1786 (mq->specific_address->addr != NULL)
1787 ? a2s (mq->plugin->short_name,
1788 mq->specific_address->addr,
1789 mq->specific_address->addrlen)
1791 rl->plugin->short_name);
1793 GNUNET_STATISTICS_update (stats,
1794 gettext_noop ("# bytes in message queue for other peers"),
1795 - (int64_t) mq->message_buf_size,
1797 GNUNET_STATISTICS_update (stats,
1798 gettext_noop ("# bytes pending with plugins"),
1799 mq->message_buf_size,
1801 ret = rl->plugin->api->send (rl->plugin->api->cls,
1804 mq->message_buf_size,
1806 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1807 mq->specific_address->session,
1808 mq->specific_address->addr,
1809 mq->specific_address->addrlen,
1811 &transmit_send_continuation, mq);
1814 /* failure, but 'send' would not call continuation in this case,
1815 so we need to do it here! */
1816 transmit_send_continuation (mq,
1824 * Send the specified message to the specified peer.
1826 * @param client source of the transmission request (can be NULL)
1827 * @param peer_address ForeignAddressList where we should send this message
1828 * @param priority how important is the message
1829 * @param timeout how long do we have to transmit?
1830 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1831 * @param message_buf_size total size of all messages in message_buf
1832 * @param is_internal is this an internal message; these are pre-pended and
1833 * also do not count for plugins being "ready" to transmit
1834 * @param neighbour handle to the neighbour for transmission
1837 transmit_to_peer (struct TransportClient *client,
1838 struct ForeignAddressList *peer_address,
1839 unsigned int priority,
1840 struct GNUNET_TIME_Relative timeout,
1841 const char *message_buf,
1842 size_t message_buf_size,
1843 int is_internal, struct NeighbourList *neighbour)
1845 struct MessageQueue *mq;
1850 /* check for duplicate submission */
1851 mq = neighbour->messages_head;
1854 if (mq->client == client)
1856 /* client transmitted to same peer twice
1857 before getting SEND_OK! */
1865 GNUNET_STATISTICS_update (stats,
1866 gettext_noop ("# bytes in message queue for other peers"),
1869 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1870 mq->specific_address = peer_address;
1871 mq->client = client;
1872 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1873 memcpy (&mq[1], message_buf, message_buf_size);
1874 mq->message_buf = (const char*) &mq[1];
1875 mq->message_buf_size = message_buf_size;
1876 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1877 mq->internal_msg = is_internal;
1878 mq->priority = priority;
1879 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1881 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1882 neighbour->messages_tail,
1885 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1886 neighbour->messages_tail,
1887 neighbour->messages_tail,
1889 try_transmission_to_peer (neighbour);
1896 struct GeneratorContext
1898 struct TransportPlugin *plug_pos;
1899 struct OwnAddressList *addr_pos;
1900 struct GNUNET_TIME_Absolute expiration;
1908 address_generator (void *cls, size_t max, void *buf)
1910 struct GeneratorContext *gc = cls;
1913 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1915 gc->plug_pos = gc->plug_pos->next;
1916 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1918 if (NULL == gc->plug_pos)
1923 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1926 gc->addr_pos->addrlen, buf, max);
1927 gc->addr_pos = gc->addr_pos->next;
1933 * Construct our HELLO message from all of the addresses of
1934 * all of the transports.
1939 struct GNUNET_HELLO_Message *hello;
1940 struct TransportClient *cpos;
1941 struct NeighbourList *npos;
1942 struct GeneratorContext gc;
1944 gc.plug_pos = plugins;
1945 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1946 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1947 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1950 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1952 GNUNET_STATISTICS_update (stats,
1953 gettext_noop ("# refreshed my HELLO"),
1957 while (cpos != NULL)
1959 transmit_to_client (cpos,
1960 (const struct GNUNET_MessageHeader *) hello,
1965 GNUNET_free_non_null (our_hello);
1967 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1969 while (npos != NULL)
1972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1973 "Transmitting updated `%s' to neighbour `%4s'\n",
1974 "HELLO", GNUNET_i2s (&npos->id));
1976 GNUNET_STATISTICS_update (stats,
1977 gettext_noop ("# transmitted my HELLO to other peers"),
1980 transmit_to_peer (NULL, NULL, 0,
1981 HELLO_ADDRESS_EXPIRATION,
1982 (const char *) our_hello,
1983 GNUNET_HELLO_size(our_hello),
1991 * Task used to clean up expired addresses for a plugin.
1993 * @param cls closure
1997 expire_address_task (void *cls,
1998 const struct GNUNET_SCHEDULER_TaskContext *tc);
2002 * Update the list of addresses for this plugin,
2003 * expiring those that are past their expiration date.
2005 * @param plugin addresses of which plugin should be recomputed?
2006 * @param fresh set to GNUNET_YES if a new address was added
2007 * and we need to regenerate the HELLO even if nobody
2011 update_addresses (struct TransportPlugin *plugin,
2014 static struct GNUNET_TIME_Absolute last_update;
2015 struct GNUNET_TIME_Relative min_remaining;
2016 struct GNUNET_TIME_Relative remaining;
2017 struct GNUNET_TIME_Absolute now;
2018 struct OwnAddressList *pos;
2019 struct OwnAddressList *prev;
2020 struct OwnAddressList *next;
2023 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2024 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2025 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2026 now = GNUNET_TIME_absolute_get ();
2027 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2028 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2030 pos = plugin->addresses;
2034 if (pos->expires.abs_value < now.abs_value)
2036 expired = GNUNET_YES;
2038 plugin->addresses = pos->next;
2040 prev->next = pos->next;
2045 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2046 if (remaining.rel_value < min_remaining.rel_value)
2047 min_remaining = remaining;
2053 if (expired || fresh)
2058 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2059 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2061 plugin->address_update_task
2062 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2063 &expire_address_task, plugin);
2068 * Task used to clean up expired addresses for a plugin.
2070 * @param cls closure
2074 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2076 struct TransportPlugin *plugin = cls;
2078 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2079 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2080 update_addresses (plugin, GNUNET_NO);
2085 * Iterator over hash map entries that NULLs the session of validation
2086 * entries that match the given session.
2088 * @param cls closure (the 'struct Session*' to match against)
2089 * @param key current key code (peer ID, not used)
2090 * @param value value in the hash map ('struct ValidationEntry*')
2091 * @return GNUNET_YES (we should continue to iterate)
2094 remove_session_validations (void *cls,
2095 const GNUNET_HashCode * key,
2098 struct Session *session = cls;
2099 struct ValidationEntry *ve = value;
2101 if (session == ve->session)
2108 * We've been disconnected from the other peer (for some
2109 * connection-oriented transport). Either quickly
2110 * re-establish the connection or signal the disconnect
2113 * Only signal CORE level disconnect if ALL addresses
2114 * for the peer are exhausted.
2116 * @param p overall plugin context
2117 * @param nl neighbour that was disconnected
2120 try_fast_reconnect (struct TransportPlugin *p,
2121 struct NeighbourList *nl)
2123 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2124 /* Note: the idea here is to hide problems with transports (or
2125 switching between plugins) from the core to eliminate the need to
2126 re-negotiate session keys and the like; OTOH, we should tell core
2127 quickly (much faster than timeout) `if a connection was lost and
2128 could not be re-established (i.e. other peer went down or is
2129 unable / refuses to communicate);
2131 So we should consider:
2132 1) ideally: our own willingness / need to connect
2133 2) prior failures to connect to this peer (by plugin)
2134 3) ideally: reasons why other peer terminated (as far as knowable)
2136 Most importantly, it must be POSSIBLE for another peer to terminate
2137 a connection for a while (without us instantly re-establishing it).
2138 Similarly, if another peer is gone we should quickly notify CORE.
2139 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2140 on the other end), we should reconnect in such a way that BOTH CORE
2141 services never even notice.
2142 Furthermore, the same mechanism (or small variation) could be used
2143 to switch to a better-performing plugin (ATS).
2145 Finally, this needs to be tested throughly... */
2148 * GNUNET_NO in the call below makes transport disconnect the peer,
2149 * even if only a single address (out of say, six) went away. This
2150 * function must be careful to ONLY disconnect if the peer is gone,
2151 * not just a specifi address.
2153 * More specifically, half the places it was used had it WRONG.
2156 /* No reconnect, signal disconnect instead! */
2157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2158 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2159 "try_fast_reconnect");
2160 disconnect_neighbour (nl, GNUNET_YES);
2165 * Function that will be called whenever the plugin internally
2166 * cleans up a session pointer and hence the service needs to
2167 * discard all of those sessions as well. Plugins that do not
2168 * use sessions can simply omit calling this function and always
2169 * use NULL wherever a session pointer is needed.
2171 * @param cls closure
2172 * @param peer which peer was the session for
2173 * @param session which session is being destoyed
2176 plugin_env_session_end (void *cls,
2177 const struct GNUNET_PeerIdentity *peer,
2178 struct Session *session)
2180 struct TransportPlugin *p = cls;
2181 struct NeighbourList *nl;
2182 struct ReadyList *rl;
2183 struct ForeignAddressList *pos;
2184 struct ForeignAddressList *prev;
2186 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2187 &remove_session_validations,
2189 nl = find_neighbour (peer);
2191 return; /* was never marked as connected */
2195 if (rl->plugin == p)
2200 return; /* was never marked as connected */
2202 pos = rl->addresses;
2203 while ( (pos != NULL) &&
2204 (pos->session != session) )
2210 return; /* was never marked as connected */
2211 pos->session = NULL;
2212 if (pos->addrlen != 0)
2214 if (nl->received_pong != GNUNET_NO)
2215 try_fast_reconnect (p, nl);
2218 /* was inbound connection, free 'pos' */
2220 rl->addresses = pos->next;
2222 prev->next = pos->next;
2223 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2225 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2226 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2229 if (nl->received_pong == GNUNET_NO)
2230 return; /* nothing to do, never connected... */
2231 /* check if we have any validated addresses left */
2232 pos = rl->addresses;
2237 try_fast_reconnect (p, nl);
2242 /* no valid addresses left, signal disconnect! */
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2246 "plugin_env_session_end");
2247 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2248 * it means there aren't any left for this PLUGIN/PEER combination! So
2249 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2250 * when it isn't necessary. Using GNUNET_YES at least checks to see
2251 * if there are any addresses that work first, so as not to overdo it.
2254 disconnect_neighbour (nl, GNUNET_YES);
2259 * Function that must be called by each plugin to notify the
2260 * transport service about the addresses under which the transport
2261 * provided by the plugin can be reached.
2263 * @param cls closure
2264 * @param name name of the transport that generated the address
2265 * @param addr one of the addresses of the host, NULL for the last address
2266 * the specific address format depends on the transport
2267 * @param addrlen length of the address
2268 * @param expires when should this address automatically expire?
2271 plugin_env_notify_address (void *cls,
2275 struct GNUNET_TIME_Relative expires)
2277 struct TransportPlugin *p = cls;
2278 struct OwnAddressList *al;
2279 struct GNUNET_TIME_Absolute abex;
2281 GNUNET_assert (addr != NULL);
2282 abex = GNUNET_TIME_relative_to_absolute (expires);
2283 GNUNET_assert (p == find_transport (name));
2287 if ( (addrlen == al->addrlen) &&
2288 (0 == memcmp (addr, &al[1], addrlen)) )
2291 update_addresses (p, GNUNET_NO);
2296 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2297 al->next = p->addresses;
2300 al->addrlen = addrlen;
2301 memcpy (&al[1], addr, addrlen);
2302 update_addresses (p, GNUNET_YES);
2307 * Notify all of our clients about a peer connecting.
2310 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2311 struct GNUNET_TIME_Relative latency,
2314 struct ConnectInfoMessage * cim;
2315 struct TransportClient *cpos;
2320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2321 "Notifying clients about connection from `%s'\n",
2324 GNUNET_STATISTICS_update (stats,
2325 gettext_noop ("# peers connected"),
2330 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2331 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2335 cim = GNUNET_malloc (size);
2337 cim->header.size = htons (size);
2338 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2339 cim->ats_count = htonl(2);
2340 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2341 (&(cim->ats))[0].value = htonl (distance);
2342 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2343 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2344 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2345 (&(cim->ats))[2].value = htonl (0);
2346 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2348 /* notify ats about connecting peer */
2349 ats_notify_peer_connect (peer, &(cim->ats));
2352 while (cpos != NULL)
2354 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2363 * Notify all of our clients about a peer disconnecting.
2366 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2368 struct DisconnectInfoMessage dim;
2369 struct TransportClient *cpos;
2372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373 "Notifying clients about lost connection to `%s'\n",
2376 GNUNET_STATISTICS_update (stats,
2377 gettext_noop ("# peers connected"),
2380 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2381 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2382 dim.reserved = htonl (0);
2383 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2385 /* notify ats about connecting peer */
2386 ats_notify_peer_disconnect (peer);
2389 while (cpos != NULL)
2391 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2398 * Find a ForeignAddressList entry for the given neighbour
2399 * that matches the given address and transport.
2401 * @param neighbour which peer we care about
2402 * @param tname name of the transport plugin
2403 * @param session session to look for, NULL for 'any'; otherwise
2404 * can be used for the service to "learn" this session ID
2406 * @param addr binary address
2407 * @param addrlen length of addr
2408 * @return NULL if no such entry exists
2410 static struct ForeignAddressList *
2411 find_peer_address(struct NeighbourList *neighbour,
2413 struct Session *session,
2417 struct ReadyList *head;
2418 struct ForeignAddressList *pos;
2420 head = neighbour->plugins;
2421 while (head != NULL)
2423 if (0 == strcmp (tname, head->plugin->short_name))
2429 pos = head->addresses;
2430 while ( (pos != NULL) &&
2431 ( (pos->addrlen != addrlen) ||
2432 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2434 if ( (session != NULL) &&
2435 (pos->session == session) )
2439 if ( (session != NULL) && (pos != NULL) )
2440 pos->session = session; /* learn it! */
2446 * Get the peer address struct for the given neighbour and
2447 * address. If it doesn't yet exist, create it.
2449 * @param neighbour which peer we care about
2450 * @param tname name of the transport plugin
2451 * @param session session of the plugin, or NULL for none
2452 * @param addr binary address
2453 * @param addrlen length of addr
2454 * @return NULL if we do not have a transport plugin for 'tname'
2456 static struct ForeignAddressList *
2457 add_peer_address (struct NeighbourList *neighbour,
2459 struct Session *session,
2463 struct ReadyList *head;
2464 struct ForeignAddressList *ret;
2466 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2469 head = neighbour->plugins;
2471 while (head != NULL)
2473 if (0 == strcmp (tname, head->plugin->short_name))
2479 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2480 ret->session = session;
2483 ret->addr = (const char*) &ret[1];
2484 memcpy (&ret[1], addr, addrlen);
2490 ret->ressources = NULL;
2491 ret->addrlen = addrlen;
2492 ret->expires = GNUNET_TIME_relative_to_absolute
2493 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2494 ret->latency = GNUNET_TIME_relative_get_forever();
2496 ret->timeout = GNUNET_TIME_relative_to_absolute
2497 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2498 ret->ready_list = head;
2499 ret->next = head->addresses;
2500 head->addresses = ret;
2506 * Closure for 'add_validated_address'.
2508 struct AddValidatedAddressContext
2511 * Entry that has been validated.
2513 const struct ValidationEntry *ve;
2516 * Flag set after we have added the address so
2517 * that we terminate the iteration next time.
2524 * Callback function used to fill a buffer of max bytes with a list of
2525 * addresses in the format used by HELLOs. Should use
2526 * "GNUNET_HELLO_add_address" as a helper function.
2528 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2529 * @param max maximum number of bytes that can be written to buf
2530 * @param buf where to write the address information
2531 * @return number of bytes written, 0 to signal the
2532 * end of the iteration.
2535 add_validated_address (void *cls,
2536 size_t max, void *buf)
2538 struct AddValidatedAddressContext *avac = cls;
2539 const struct ValidationEntry *ve = avac->ve;
2541 if (GNUNET_YES == avac->done)
2543 avac->done = GNUNET_YES;
2544 return GNUNET_HELLO_add_address (ve->transport_name,
2545 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2555 * Closure for 'check_address_exists'.
2557 struct CheckAddressExistsClosure
2560 * Address to check for.
2565 * Name of the transport.
2572 struct Session *session;
2575 * Set to GNUNET_YES if the address exists.
2588 * Iterator over hash map entries. Checks if the given
2589 * validation entry is for the same address as what is given
2592 * @param cls the 'struct CheckAddressExistsClosure*'
2593 * @param key current key code (ignored)
2594 * @param value value in the hash map ('struct ValidationEntry')
2595 * @return GNUNET_YES if we should continue to
2596 * iterate (mismatch), GNUNET_NO if not (entry matched)
2599 check_address_exists (void *cls,
2600 const GNUNET_HashCode * key,
2603 struct CheckAddressExistsClosure *caec = cls;
2604 struct ValidationEntry *ve = value;
2606 if ( (0 == strcmp (caec->tname,
2607 ve->transport_name)) &&
2608 (caec->addrlen == ve->addrlen) &&
2609 (0 == memcmp (caec->addr,
2613 caec->exists = GNUNET_YES;
2616 if ( (ve->session != NULL) &&
2617 (caec->session == ve->session) )
2619 caec->exists = GNUNET_YES;
2628 * Iterator to free entries in the validation_map.
2630 * @param cls closure (unused)
2631 * @param key current key code
2632 * @param value value in the hash map (validation to abort)
2633 * @return GNUNET_YES (always)
2636 abort_validation (void *cls,
2637 const GNUNET_HashCode * key,
2640 struct ValidationEntry *va = value;
2642 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2643 GNUNET_SCHEDULER_cancel (va->timeout_task);
2644 GNUNET_free (va->transport_name);
2645 if (va->chvc != NULL)
2647 va->chvc->ve_count--;
2648 if (va->chvc->ve_count == 0)
2650 GNUNET_CONTAINER_DLL_remove (chvc_head,
2653 GNUNET_free (va->chvc);
2663 * HELLO validation cleanup task (validation failed).
2665 * @param cls the 'struct ValidationEntry' that failed
2666 * @param tc scheduler context (unused)
2669 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2671 struct ValidationEntry *va = cls;
2672 struct GNUNET_PeerIdentity pid;
2674 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2675 GNUNET_STATISTICS_update (stats,
2676 gettext_noop ("# address validation timeouts"),
2679 GNUNET_CRYPTO_hash (&va->publicKey,
2681 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2683 GNUNET_break (GNUNET_OK ==
2684 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2687 abort_validation (NULL, NULL, va);
2692 neighbour_timeout_task (void *cls,
2693 const struct GNUNET_SCHEDULER_TaskContext *tc)
2695 struct NeighbourList *n = cls;
2698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2699 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2701 GNUNET_STATISTICS_update (stats,
2702 gettext_noop ("# disconnects due to timeout"),
2705 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2706 disconnect_neighbour (n, GNUNET_NO);
2711 * Schedule the job that will cause us to send a PING to the
2712 * foreign address to evaluate its validity and latency.
2714 * @param fal address to PING
2717 schedule_next_ping (struct ForeignAddressList *fal);
2721 * Add the given address to the list of foreign addresses
2722 * available for the given peer (check for duplicates).
2724 * @param cls the respective 'struct NeighbourList' to update
2725 * @param tname name of the transport
2726 * @param expiration expiration time
2727 * @param addr the address
2728 * @param addrlen length of the address
2729 * @return GNUNET_OK (always)
2732 add_to_foreign_address_list (void *cls,
2734 struct GNUNET_TIME_Absolute expiration,
2738 struct NeighbourList *n = cls;
2739 struct ForeignAddressList *fal;
2742 GNUNET_STATISTICS_update (stats,
2743 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2747 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2750 #if DEBUG_TRANSPORT_HELLO
2751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2753 a2s (tname, addr, addrlen),
2755 GNUNET_i2s (&n->id),
2756 expiration.abs_value);
2758 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2761 GNUNET_STATISTICS_update (stats,
2762 gettext_noop ("# previously validated addresses lacking transport"),
2768 fal->expires = GNUNET_TIME_absolute_max (expiration,
2770 schedule_next_ping (fal);
2776 fal->expires = GNUNET_TIME_absolute_max (expiration,
2781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2782 "Failed to add new address for `%4s'\n",
2783 GNUNET_i2s (&n->id));
2786 if (fal->validated == GNUNET_NO)
2788 fal->validated = GNUNET_YES;
2789 GNUNET_STATISTICS_update (stats,
2790 gettext_noop ("# peer addresses considered valid"),
2794 if (try == GNUNET_YES)
2796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2797 "Have new addresses, will try to trigger transmissions.\n");
2798 try_transmission_to_peer (n);
2805 * Add addresses in validated HELLO "h" to the set of addresses
2806 * we have for this peer.
2808 * @param cls closure ('struct NeighbourList*')
2809 * @param peer id of the peer, NULL for last call
2810 * @param h hello message for the peer (can be NULL)
2811 * @param err_msg NULL if successful, otherwise contains error message
2814 add_hello_for_peer (void *cls,
2815 const struct GNUNET_PeerIdentity *peer,
2816 const struct GNUNET_HELLO_Message *h,
2817 const char *err_msg)
2819 struct NeighbourList *n = cls;
2821 if (err_msg != NULL)
2823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2824 _("Error in communication with PEERINFO service\n"));
2829 GNUNET_STATISTICS_update (stats,
2830 gettext_noop ("# outstanding peerinfo iterate requests"),
2837 return; /* no HELLO available */
2839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2840 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2844 if (GNUNET_YES != n->public_key_valid)
2846 GNUNET_HELLO_get_key (h, &n->publicKey);
2847 n->public_key_valid = GNUNET_YES;
2849 GNUNET_HELLO_iterate_addresses (h,
2851 &add_to_foreign_address_list,
2857 * Create a fresh entry in our neighbour list for the given peer.
2858 * Will try to transmit our current HELLO to the new neighbour.
2859 * Do not call this function directly, use 'setup_peer_check_blacklist.
2861 * @param peer the peer for which we create the entry
2862 * @param do_hello should we schedule transmitting a HELLO
2863 * @return the new neighbour list entry
2865 static struct NeighbourList *
2866 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2869 struct NeighbourList *n;
2870 struct TransportPlugin *tp;
2871 struct ReadyList *rl;
2874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2875 "Setting up state for neighbour `%4s'\n",
2878 GNUNET_assert (our_hello != NULL);
2879 GNUNET_STATISTICS_update (stats,
2880 gettext_noop ("# active neighbours"),
2883 n = GNUNET_malloc (sizeof (struct NeighbourList));
2884 n->next = neighbours;
2888 GNUNET_TIME_relative_to_absolute
2889 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2890 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2891 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2892 MAX_BANDWIDTH_CARRY_S);
2896 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2898 rl = GNUNET_malloc (sizeof (struct ReadyList));
2900 rl->next = n->plugins;
2903 rl->addresses = NULL;
2907 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2909 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2910 &neighbour_timeout_task, n);
2913 GNUNET_STATISTICS_update (stats,
2914 gettext_noop ("# peerinfo new neighbor iterate requests"),
2917 GNUNET_STATISTICS_update (stats,
2918 gettext_noop ("# outstanding peerinfo iterate requests"),
2921 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2922 GNUNET_TIME_UNIT_FOREVER_REL,
2923 &add_hello_for_peer, n);
2925 GNUNET_STATISTICS_update (stats,
2926 gettext_noop ("# HELLO's sent to new neighbors"),
2929 transmit_to_peer (NULL, NULL, 0,
2930 HELLO_ADDRESS_EXPIRATION,
2931 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2939 * Function called after we have checked if communicating
2940 * with a given peer is acceptable.
2942 * @param cls closure
2943 * @param n NULL if communication is not acceptable
2945 typedef void (*SetupContinuation)(void *cls,
2946 struct NeighbourList *n);
2950 * Information kept for each client registered to perform
2956 * This is a linked list.
2958 struct Blacklisters *next;
2961 * This is a linked list.
2963 struct Blacklisters *prev;
2966 * Client responsible for this entry.
2968 struct GNUNET_SERVER_Client *client;
2971 * Blacklist check that we're currently performing.
2973 struct BlacklistCheck *bc;
2979 * Head of DLL of blacklisting clients.
2981 static struct Blacklisters *bl_head;
2984 * Tail of DLL of blacklisting clients.
2986 static struct Blacklisters *bl_tail;
2990 * Context we use when performing a blacklist check.
2992 struct BlacklistCheck
2996 * This is a linked list.
2998 struct BlacklistCheck *next;
3001 * This is a linked list.
3003 struct BlacklistCheck *prev;
3006 * Peer being checked.
3008 struct GNUNET_PeerIdentity peer;
3011 * Option for setup neighbour afterwards.
3016 * Continuation to call with the result.
3018 SetupContinuation cont;
3026 * Current transmission request handle for this client, or NULL if no
3027 * request is pending.
3029 struct GNUNET_CONNECTION_TransmitHandle *th;
3032 * Our current position in the blacklisters list.
3034 struct Blacklisters *bl_pos;
3037 * Current task performing the check.
3039 GNUNET_SCHEDULER_TaskIdentifier task;
3044 * Head of DLL of active blacklisting queries.
3046 static struct BlacklistCheck *bc_head;
3049 * Tail of DLL of active blacklisting queries.
3051 static struct BlacklistCheck *bc_tail;
3055 * Perform next action in the blacklist check.
3057 * @param cls the 'struct BlacklistCheck*'
3061 do_blacklist_check (void *cls,
3062 const struct GNUNET_SCHEDULER_TaskContext *tc);
3065 * Transmit blacklist query to the client.
3067 * @param cls the 'struct BlacklistCheck'
3068 * @param size number of bytes allowed
3069 * @param buf where to copy the message
3070 * @return number of bytes copied to buf
3073 transmit_blacklist_message (void *cls,
3077 struct BlacklistCheck *bc = cls;
3078 struct Blacklisters *bl;
3079 struct BlacklistMessage bm;
3084 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3085 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3090 bm.header.size = htons (sizeof (struct BlacklistMessage));
3091 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3092 bm.is_allowed = htonl (0);
3094 memcpy (buf, &bm, sizeof (bm));
3095 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3101 * Perform next action in the blacklist check.
3103 * @param cls the 'struct BlacklistCheck*'
3107 do_blacklist_check (void *cls,
3108 const struct GNUNET_SCHEDULER_TaskContext *tc)
3110 struct BlacklistCheck *bc = cls;
3111 struct Blacklisters *bl;
3113 bc->task = GNUNET_SCHEDULER_NO_TASK;
3117 bc->cont (bc->cont_cls,
3118 setup_new_neighbour (&bc->peer, bc->do_hello));
3125 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3126 sizeof (struct BlacklistMessage),
3127 GNUNET_TIME_UNIT_FOREVER_REL,
3128 &transmit_blacklist_message,
3135 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3136 * does not yet exist, check the blacklist. If the blacklist says creating
3137 * one is acceptable, create one and call the continuation; otherwise
3138 * call the continuation with NULL.
3140 * @param peer peer to setup or look up a struct NeighbourList for
3141 * @param do_hello should we also schedule sending our HELLO to the peer
3142 * if this is a new record
3143 * @param cont function to call with the 'struct NeigbhbourList*'
3144 * @param cont_cls closure for cont
3147 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3149 SetupContinuation cont,
3152 struct NeighbourList *n;
3153 struct BlacklistCheck *bc;
3155 n = find_neighbour(peer);
3162 if (bl_head == NULL)
3165 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3167 setup_new_neighbour(peer, do_hello);
3170 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3171 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3173 bc->do_hello = do_hello;
3175 bc->cont_cls = cont_cls;
3176 bc->bl_pos = bl_head;
3177 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3183 * Function called with the result of querying a new blacklister about
3184 * it being allowed (or not) to continue to talk to an existing neighbour.
3186 * @param cls the original 'struct NeighbourList'
3187 * @param n NULL if we need to disconnect
3190 confirm_or_drop_neighbour (void *cls,
3191 struct NeighbourList *n)
3193 struct NeighbourList * orig = cls;
3197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3198 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3199 "confirm_or_drop_neighboUr");
3200 disconnect_neighbour (orig, GNUNET_NO);
3206 * Handle a request to start a blacklist.
3208 * @param cls closure (always NULL)
3209 * @param client identification of the client
3210 * @param message the actual message
3213 handle_blacklist_init (void *cls,
3214 struct GNUNET_SERVER_Client *client,
3215 const struct GNUNET_MessageHeader *message)
3217 struct Blacklisters *bl;
3218 struct BlacklistCheck *bc;
3219 struct NeighbourList *n;
3224 if (bl->client == client)
3227 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3232 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3233 bl->client = client;
3234 GNUNET_SERVER_client_keep (client);
3235 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3236 /* confirm that all existing connections are OK! */
3240 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3241 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3243 bc->do_hello = GNUNET_NO;
3244 bc->cont = &confirm_or_drop_neighbour;
3247 if (n == neighbours) /* all would wait for the same client, no need to
3248 create more than just the first task right now */
3249 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3257 * Handle a request to blacklist a peer.
3259 * @param cls closure (always NULL)
3260 * @param client identification of the client
3261 * @param message the actual message
3264 handle_blacklist_reply (void *cls,
3265 struct GNUNET_SERVER_Client *client,
3266 const struct GNUNET_MessageHeader *message)
3268 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3269 struct Blacklisters *bl;
3270 struct BlacklistCheck *bc;
3273 while ( (bl != NULL) &&
3274 (bl->client != client) )
3278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3283 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3285 bc->cont (bc->cont_cls, NULL);
3286 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3291 bc->bl_pos = bc->bl_pos->next;
3292 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3295 /* check if any other bc's are waiting for this blacklister */
3299 if ( (bc->bl_pos == bl) &&
3300 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3301 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3309 * Send periodic PING messages to a given foreign address.
3311 * @param cls our 'struct PeriodicValidationContext*'
3312 * @param tc task context
3315 send_periodic_ping (void *cls,
3316 const struct GNUNET_SCHEDULER_TaskContext *tc)
3318 struct ForeignAddressList *peer_address = cls;
3319 struct TransportPlugin *tp;
3320 struct ValidationEntry *va;
3321 struct NeighbourList *neighbour;
3322 struct TransportPingMessage ping;
3323 struct CheckAddressExistsClosure caec;
3325 uint16_t hello_size;
3329 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3330 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3332 tp = peer_address->ready_list->plugin;
3333 neighbour = peer_address->ready_list->neighbour;
3334 if (GNUNET_YES != neighbour->public_key_valid)
3336 /* no public key yet, try again later */
3337 schedule_next_ping (peer_address);
3340 caec.addr = peer_address->addr;
3341 caec.addrlen = peer_address->addrlen;
3342 caec.tname = tp->short_name;
3343 caec.session = peer_address->session;
3344 caec.exists = GNUNET_NO;
3345 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3346 &check_address_exists,
3348 if (caec.exists == GNUNET_YES)
3350 /* During validation attempts we will likely trigger the other
3351 peer trying to validate our address which in turn will cause
3352 it to send us its HELLO, so we expect to hit this case rather
3353 frequently. Only print something if we are very verbose. */
3354 #if DEBUG_TRANSPORT > 1
3355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3356 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3357 (peer_address->addr != NULL)
3358 ? a2s (tp->short_name,
3360 peer_address->addrlen)
3363 GNUNET_i2s (&neighbour->id));
3365 schedule_next_ping (peer_address);
3368 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3369 va->transport_name = GNUNET_strdup (tp->short_name);
3370 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3372 va->send_time = GNUNET_TIME_absolute_get();
3373 va->session = peer_address->session;
3374 if (peer_address->addr != NULL)
3376 va->addr = (const void*) &va[1];
3377 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3378 va->addrlen = peer_address->addrlen;
3380 memcpy(&va->publicKey,
3381 &neighbour->publicKey,
3382 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3384 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3385 &timeout_hello_validation,
3387 GNUNET_CONTAINER_multihashmap_put (validation_map,
3388 &neighbour->id.hashPubKey,
3390 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3392 if (peer_address->validated != GNUNET_YES)
3393 hello_size = GNUNET_HELLO_size(our_hello);
3397 tsize = sizeof(struct TransportPingMessage) + hello_size;
3399 if (peer_address->addr != NULL)
3401 slen = strlen (tp->short_name) + 1;
3402 tsize += slen + peer_address->addrlen;
3406 slen = 0; /* make gcc happy */
3408 message_buf = GNUNET_malloc(tsize);
3409 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3410 ping.challenge = htonl(va->challenge);
3411 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3412 if (peer_address->validated != GNUNET_YES)
3414 memcpy(message_buf, our_hello, hello_size);
3417 if (peer_address->addr != NULL)
3419 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3420 peer_address->addrlen +
3422 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3425 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3427 peer_address->addrlen);
3431 ping.header.size = htons(sizeof(struct TransportPingMessage));
3434 memcpy(&message_buf[hello_size],
3436 sizeof(struct TransportPingMessage));
3438 #if DEBUG_TRANSPORT_REVALIDATION
3439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3440 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3441 (peer_address->addr != NULL)
3442 ? a2s (peer_address->plugin->short_name,
3444 peer_address->addrlen)
3447 GNUNET_i2s (&neighbour->id),
3448 "HELLO", hello_size,
3451 if (peer_address->validated != GNUNET_YES)
3452 GNUNET_STATISTICS_update (stats,
3453 gettext_noop ("# PING with HELLO messages sent"),
3457 GNUNET_STATISTICS_update (stats,
3458 gettext_noop ("# PING without HELLO messages sent"),
3461 GNUNET_STATISTICS_update (stats,
3462 gettext_noop ("# PING messages sent for re-validation"),
3465 transmit_to_peer (NULL, peer_address,
3466 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3467 HELLO_VERIFICATION_TIMEOUT,
3469 GNUNET_YES, neighbour);
3470 GNUNET_free(message_buf);
3471 schedule_next_ping (peer_address);
3476 * Schedule the job that will cause us to send a PING to the
3477 * foreign address to evaluate its validity and latency.
3479 * @param fal address to PING
3482 schedule_next_ping (struct ForeignAddressList *fal)
3484 struct GNUNET_TIME_Relative delay;
3486 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3488 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3489 delay.rel_value /= 2; /* do before expiration */
3490 delay = GNUNET_TIME_relative_min (delay,
3491 LATENCY_EVALUATION_MAX_DELAY);
3492 if (GNUNET_YES != fal->estimated)
3494 delay = GNUNET_TIME_UNIT_ZERO;
3495 fal->estimated = GNUNET_YES;
3497 if (GNUNET_YES == fal->connected)
3499 delay = GNUNET_TIME_relative_min (delay,
3500 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3502 /* FIXME: also adjust delay based on how close the last
3503 observed latency is to the latency of the best alternative */
3504 /* bound how fast we can go */
3505 delay = GNUNET_TIME_relative_max (delay,
3506 GNUNET_TIME_UNIT_SECONDS);
3507 /* randomize a bit (to avoid doing all at the same time) */
3508 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3509 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3510 &send_periodic_ping,
3518 * Function that will be called if we receive some payload
3519 * from another peer.
3521 * @param message the payload
3522 * @param n peer who claimed to be the sender
3525 handle_payload_message (const struct GNUNET_MessageHeader *message,
3526 struct NeighbourList *n)
3528 struct InboundMessage *im;
3529 struct TransportClient *cpos;
3532 msize = ntohs (message->size);
3533 if (n->received_pong == GNUNET_NO)
3535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3536 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3537 ntohs (message->type),
3538 ntohs (message->size),
3539 GNUNET_i2s (&n->id));
3540 GNUNET_free_non_null (n->pre_connect_message_buffer);
3541 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3542 memcpy (n->pre_connect_message_buffer, message, msize);
3547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3548 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3549 ntohs (message->type),
3550 ntohs (message->size),
3551 GNUNET_i2s (&n->id));
3553 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3556 n->quota_violation_count++;
3558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3559 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3560 n->in_tracker.available_bytes_per_s__,
3561 n->quota_violation_count);
3563 /* Discount 32k per violation */
3564 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3569 if (n->quota_violation_count > 0)
3571 /* try to add 32k back */
3572 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3574 n->quota_violation_count--;
3577 GNUNET_STATISTICS_update (stats,
3578 gettext_noop ("# payload received from other peers"),
3581 /* transmit message to all clients */
3582 uint32_t ats_count = 2;
3583 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3584 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3587 im = GNUNET_malloc (size);
3588 im->header.size = htons (size);
3589 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3591 im->ats_count = htonl(ats_count);
3592 /* Setting ATS data */
3593 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3594 (&(im->ats))[0].value = htonl (n->distance);
3595 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3596 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3597 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3598 (&(im->ats))[ats_count].value = htonl (0);
3600 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3602 while (cpos != NULL)
3604 transmit_to_client (cpos, &im->header, GNUNET_YES);
3612 * Iterator over hash map entries. Checks if the given validation
3613 * entry is for the same challenge as what is given in the PONG.
3615 * @param cls the 'struct TransportPongMessage*'
3616 * @param key peer identity
3617 * @param value value in the hash map ('struct ValidationEntry')
3618 * @return GNUNET_YES if we should continue to
3619 * iterate (mismatch), GNUNET_NO if not (entry matched)
3622 check_pending_validation (void *cls,
3623 const GNUNET_HashCode * key,
3626 const struct TransportPongMessage *pong = cls;
3627 struct ValidationEntry *ve = value;
3628 struct AddValidatedAddressContext avac;
3629 unsigned int challenge = ntohl(pong->challenge);
3630 struct GNUNET_HELLO_Message *hello;
3631 struct GNUNET_PeerIdentity target;
3632 struct NeighbourList *n;
3633 struct ForeignAddressList *fal;
3634 struct OwnAddressList *oal;
3635 struct TransportPlugin *tp;
3636 struct GNUNET_MessageHeader *prem;
3642 ps = ntohs (pong->header.size);
3643 if (ps < sizeof (struct TransportPongMessage))
3645 GNUNET_break_op (0);
3648 addr = (const char*) &pong[1];
3649 slen = strlen (ve->transport_name) + 1;
3650 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3651 (ve->challenge != challenge) ||
3652 (addr[slen-1] != '\0') ||
3653 (0 != strcmp (addr, ve->transport_name)) ||
3654 (ntohl (pong->purpose.size)
3655 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3657 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3658 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3663 alen = ps - sizeof (struct TransportPongMessage) - slen;
3664 switch (ntohl (pong->purpose.purpose))
3666 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3667 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3668 (0 != memcmp (&addr[slen],
3672 return GNUNET_YES; /* different entry, keep trying! */
3674 if (0 != memcmp (&pong->pid,
3676 sizeof (struct GNUNET_PeerIdentity)))
3678 GNUNET_break_op (0);
3682 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3687 GNUNET_break_op (0);
3692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3693 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3695 a2s (ve->transport_name,
3696 (const struct sockaddr *) ve->addr,
3698 ve->transport_name);
3701 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3702 if (0 != memcmp (&pong->pid,
3704 sizeof (struct GNUNET_PeerIdentity)))
3706 GNUNET_break_op (0);
3709 if (ve->addrlen != 0)
3711 /* must have been for a different validation entry */
3714 tp = find_transport (ve->transport_name);
3720 oal = tp->addresses;
3723 if ( (oal->addrlen == alen) &&
3724 (0 == memcmp (&oal[1],
3732 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3733 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3734 a2s (ve->transport_name,
3740 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3745 GNUNET_break_op (0);
3750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3751 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3753 a2s (ve->transport_name,
3756 ve->transport_name);
3760 GNUNET_break_op (0);
3763 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3765 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3766 _("Received expired signature. Check system time.\n"));
3769 GNUNET_STATISTICS_update (stats,
3770 gettext_noop ("# address validation successes"),
3773 /* create the updated HELLO */
3774 GNUNET_CRYPTO_hash (&ve->publicKey,
3775 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3776 &target.hashPubKey);
3777 if (ve->addr != NULL)
3779 avac.done = GNUNET_NO;
3781 hello = GNUNET_HELLO_create (&ve->publicKey,
3782 &add_validated_address,
3784 GNUNET_PEERINFO_add_peer (peerinfo,
3786 GNUNET_free (hello);
3788 n = find_neighbour (&target);
3791 n->publicKey = ve->publicKey;
3792 n->public_key_valid = GNUNET_YES;
3793 fal = add_peer_address (n,
3798 GNUNET_assert (fal != NULL);
3799 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3800 fal->validated = GNUNET_YES;
3801 mark_address_connected (fal);
3802 GNUNET_STATISTICS_update (stats,
3803 gettext_noop ("# peer addresses considered valid"),
3806 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3807 schedule_next_ping (fal);
3808 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3809 n->latency = fal->latency;
3811 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3813 n->distance = fal->distance;
3814 if (GNUNET_NO == n->received_pong)
3816 n->received_pong = GNUNET_YES;
3818 notify_clients_connect (&target, n->latency, n->distance);
3819 if (NULL != (prem = n->pre_connect_message_buffer))
3821 n->pre_connect_message_buffer = NULL;
3822 handle_payload_message (prem, n);
3826 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3828 GNUNET_SCHEDULER_cancel (n->retry_task);
3829 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3830 try_transmission_to_peer (n);
3834 /* clean up validation entry */
3835 GNUNET_assert (GNUNET_YES ==
3836 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3839 abort_validation (NULL, NULL, ve);
3845 * Function that will be called if we receive a validation
3846 * of an address challenge that we transmitted to another
3847 * peer. Note that the validation should only be considered
3848 * acceptable if the challenge matches AND if the sender
3849 * address is at least a plausible address for this peer
3850 * (otherwise we may be seeing a MiM attack).
3852 * @param cls closure
3853 * @param message the pong message
3854 * @param peer who responded to our challenge
3855 * @param sender_address string describing our sender address (as observed
3856 * by the other peer in binary format)
3857 * @param sender_address_len number of bytes in 'sender_address'
3860 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3861 const struct GNUNET_PeerIdentity *peer,
3862 const char *sender_address,
3863 size_t sender_address_len)
3865 #if DEBUG_TRANSPORT > 1
3866 /* we get tons of these that just get discarded, only log
3867 if we are quite verbose */
3868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3869 "Receiving `%s' message from `%4s'.\n", "PONG",
3872 GNUNET_STATISTICS_update (stats,
3873 gettext_noop ("# PONG messages received"),
3876 if (GNUNET_SYSERR !=
3877 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3879 &check_pending_validation,
3882 /* This is *expected* to happen a lot since we send
3883 PONGs to *all* known addresses of the sender of
3884 the PING, so most likely we get multiple PONGs
3885 per PING, and all but the first PONG will end up
3886 here. So really we should not print anything here
3887 unless we want to be very, very verbose... */
3888 #if DEBUG_TRANSPORT > 2
3889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3890 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3902 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3904 * @param cls the 'struct ValidationEntry*'
3905 * @param neighbour neighbour to validate, NULL if validation failed
3908 transmit_hello_and_ping (void *cls,
3909 struct NeighbourList *neighbour)
3911 struct ValidationEntry *va = cls;
3912 struct ForeignAddressList *peer_address;
3913 struct TransportPingMessage ping;
3914 uint16_t hello_size;
3917 struct GNUNET_PeerIdentity id;
3920 GNUNET_CRYPTO_hash (&va->publicKey,
3921 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3923 if (neighbour == NULL)
3925 /* FIXME: stats... */
3926 GNUNET_break (GNUNET_OK ==
3927 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3930 abort_validation (NULL, NULL, va);
3933 neighbour->publicKey = va->publicKey;
3934 neighbour->public_key_valid = GNUNET_YES;
3935 peer_address = add_peer_address (neighbour,
3936 va->transport_name, NULL,
3937 (const void*) &va[1],
3939 if (peer_address == NULL)
3941 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3942 "Failed to add peer `%4s' for plugin `%s'\n",
3943 GNUNET_i2s (&neighbour->id),
3944 va->transport_name);
3945 GNUNET_break (GNUNET_OK ==
3946 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3949 abort_validation (NULL, NULL, va);
3952 hello_size = GNUNET_HELLO_size(our_hello);
3953 slen = strlen(va->transport_name) + 1;
3954 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3955 message_buf = GNUNET_malloc(tsize);
3956 ping.challenge = htonl(va->challenge);
3957 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3958 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3959 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3960 memcpy(message_buf, our_hello, hello_size);
3961 memcpy(&message_buf[hello_size],
3963 sizeof(struct TransportPingMessage));
3964 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3967 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3972 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3975 : a2s (va->transport_name,
3976 (const void*) &va[1], va->addrlen),
3978 GNUNET_i2s (&neighbour->id),
3979 "HELLO", hello_size,
3980 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3983 GNUNET_STATISTICS_update (stats,
3984 gettext_noop ("# PING messages sent for initial validation"),
3987 transmit_to_peer (NULL, peer_address,
3988 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3989 HELLO_VERIFICATION_TIMEOUT,
3991 GNUNET_YES, neighbour);
3992 GNUNET_free(message_buf);
3997 * Check if the given address is already being validated; if not,
3998 * append the given address to the list of entries that are being be
3999 * validated and initiate validation.
4001 * @param cls closure ('struct CheckHelloValidatedContext *')
4002 * @param tname name of the transport
4003 * @param expiration expiration time
4004 * @param addr the address
4005 * @param addrlen length of the address
4006 * @return GNUNET_OK (always)
4009 run_validation (void *cls,
4011 struct GNUNET_TIME_Absolute expiration,
4015 struct CheckHelloValidatedContext *chvc = cls;
4016 struct GNUNET_PeerIdentity id;
4017 struct TransportPlugin *tp;
4018 struct ValidationEntry *va;
4019 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4020 struct CheckAddressExistsClosure caec;
4021 struct OwnAddressList *oal;
4023 GNUNET_assert (addr != NULL);
4025 GNUNET_STATISTICS_update (stats,
4026 gettext_noop ("# peer addresses scheduled for validation"),
4029 tp = find_transport (tname);
4032 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4033 GNUNET_ERROR_TYPE_BULK,
4035 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4037 GNUNET_STATISTICS_update (stats,
4038 gettext_noop ("# peer addresses not validated (plugin not available)"),
4043 /* check if this is one of our own addresses */
4044 oal = tp->addresses;
4047 if ( (oal->addrlen == addrlen) &&
4048 (0 == memcmp (&oal[1],
4052 /* not plausible, this address is equivalent to our own address! */
4053 GNUNET_STATISTICS_update (stats,
4054 gettext_noop ("# peer addresses not validated (loopback)"),
4061 GNUNET_HELLO_get_key (chvc->hello, &pk);
4062 GNUNET_CRYPTO_hash (&pk,
4064 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4067 if (is_blacklisted(&id, tp))
4070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4071 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4079 caec.addrlen = addrlen;
4080 caec.session = NULL;
4082 caec.exists = GNUNET_NO;
4083 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4084 &check_address_exists,
4086 if (caec.exists == GNUNET_YES)
4088 /* During validation attempts we will likely trigger the other
4089 peer trying to validate our address which in turn will cause
4090 it to send us its HELLO, so we expect to hit this case rather
4091 frequently. Only print something if we are very verbose. */
4092 #if DEBUG_TRANSPORT > 1
4093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4094 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4095 a2s (tname, addr, addrlen),
4099 GNUNET_STATISTICS_update (stats,
4100 gettext_noop ("# peer addresses not validated (in progress)"),
4105 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4108 va->transport_name = GNUNET_strdup (tname);
4109 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4111 va->send_time = GNUNET_TIME_absolute_get();
4112 va->addr = (const void*) &va[1];
4113 memcpy (&va[1], addr, addrlen);
4114 va->addrlen = addrlen;
4115 GNUNET_HELLO_get_key (chvc->hello,
4117 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4118 &timeout_hello_validation,
4120 GNUNET_CONTAINER_multihashmap_put (validation_map,
4123 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4124 setup_peer_check_blacklist (&id, GNUNET_NO,
4125 &transmit_hello_and_ping,
4132 * Check if addresses in validated hello "h" overlap with
4133 * those in "chvc->hello" and validate the rest.
4135 * @param cls closure
4136 * @param peer id of the peer, NULL for last call
4137 * @param h hello message for the peer (can be NULL)
4138 * @param err_msg NULL if successful, otherwise contains error message
4141 check_hello_validated (void *cls,
4142 const struct GNUNET_PeerIdentity *peer,
4143 const struct GNUNET_HELLO_Message *h,
4144 const char *err_msg)
4146 struct CheckHelloValidatedContext *chvc = cls;
4147 struct GNUNET_HELLO_Message *plain_hello;
4148 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4149 struct GNUNET_PeerIdentity target;
4150 struct NeighbourList *n;
4152 if (err_msg != NULL)
4154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4155 _("Error in communication with PEERINFO service\n"));
4161 GNUNET_STATISTICS_update (stats,
4162 gettext_noop ("# outstanding peerinfo iterate requests"),
4166 if (GNUNET_NO == chvc->hello_known)
4168 /* notify PEERINFO about the peer now, so that we at least
4169 have the public key if some other component needs it */
4170 GNUNET_HELLO_get_key (chvc->hello, &pk);
4171 GNUNET_CRYPTO_hash (&pk,
4172 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4173 &target.hashPubKey);
4174 plain_hello = GNUNET_HELLO_create (&pk,
4177 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4178 GNUNET_free (plain_hello);
4179 #if DEBUG_TRANSPORT_HELLO
4180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4181 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4183 GNUNET_i2s (&target));
4185 GNUNET_STATISTICS_update (stats,
4186 gettext_noop ("# new HELLOs requiring full validation"),
4189 GNUNET_HELLO_iterate_addresses (chvc->hello,
4196 GNUNET_STATISTICS_update (stats,
4197 gettext_noop ("# duplicate HELLO (peer known)"),
4202 if (chvc->ve_count == 0)
4204 GNUNET_CONTAINER_DLL_remove (chvc_head,
4213 #if DEBUG_TRANSPORT_HELLO
4214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4215 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4219 chvc->hello_known = GNUNET_YES;
4220 n = find_neighbour (peer);
4223 #if DEBUG_TRANSPORT_HELLO
4224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4225 "Calling hello_iterate_addresses for %s!\n",
4228 GNUNET_HELLO_iterate_addresses (h,
4230 &add_to_foreign_address_list,
4232 try_transmission_to_peer (n);
4236 #if DEBUG_TRANSPORT_HELLO
4237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4238 "No existing neighbor record for %s!\n",
4241 GNUNET_STATISTICS_update (stats,
4242 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4246 GNUNET_STATISTICS_update (stats,
4247 gettext_noop ("# HELLO validations (update case)"),
4250 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4252 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4259 * Process HELLO-message.
4261 * @param plugin transport involved, may be NULL
4262 * @param message the actual message
4263 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4266 process_hello (struct TransportPlugin *plugin,
4267 const struct GNUNET_MessageHeader *message)
4270 struct GNUNET_PeerIdentity target;
4271 const struct GNUNET_HELLO_Message *hello;
4272 struct CheckHelloValidatedContext *chvc;
4273 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4274 #if DEBUG_TRANSPORT_HELLO > 2
4277 hsize = ntohs (message->size);
4278 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4279 (hsize < sizeof (struct GNUNET_MessageHeader)))
4282 return GNUNET_SYSERR;
4284 GNUNET_STATISTICS_update (stats,
4285 gettext_noop ("# HELLOs received for validation"),
4289 /* first, check if load is too high */
4290 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4292 GNUNET_STATISTICS_update (stats,
4293 gettext_noop ("# HELLOs ignored due to high load"),
4296 #if DEBUG_TRANSPORT_HELLO
4297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4298 "Ignoring `%s' for `%4s', load too high.\n",
4300 GNUNET_i2s (&target));
4304 hello = (const struct GNUNET_HELLO_Message *) message;
4305 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4307 #if DEBUG_TRANSPORT_HELLO
4308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4309 "Unable to get public key from `%s' for `%4s'!\n",
4311 GNUNET_i2s (&target));
4313 GNUNET_break_op (0);
4314 return GNUNET_SYSERR;
4317 GNUNET_CRYPTO_hash (&publicKey,
4318 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4319 &target.hashPubKey);
4321 #if DEBUG_TRANSPORT_HELLO
4322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4323 "Received `%s' message for `%4s'\n",
4325 GNUNET_i2s (&target));
4328 if (0 == memcmp (&my_identity,
4330 sizeof (struct GNUNET_PeerIdentity)))
4332 GNUNET_STATISTICS_update (stats,
4333 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4339 while (NULL != chvc)
4341 if (GNUNET_HELLO_equals (hello,
4343 GNUNET_TIME_absolute_get ()).abs_value > 0)
4345 #if DEBUG_TRANSPORT_HELLO > 2
4346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4347 "Received duplicate `%s' message for `%4s'; ignored\n",
4349 GNUNET_i2s (&target));
4351 return GNUNET_OK; /* validation already pending */
4353 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4354 GNUNET_break (0 != memcmp (hello, chvc->hello,
4355 GNUNET_HELLO_size(hello)));
4360 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4361 if ((NULL != temp_neighbor))
4363 fprintf(stderr, "Already know peer, ignoring hello\n");
4368 #if DEBUG_TRANSPORT_HELLO > 2
4371 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4373 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4376 GNUNET_i2s (&target),
4378 GNUNET_HELLO_size(hello));
4382 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4384 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4385 memcpy (&chvc[1], hello, hsize);
4386 GNUNET_CONTAINER_DLL_insert (chvc_head,
4389 /* finally, check if HELLO was previously validated
4390 (continuation will then schedule actual validation) */
4391 GNUNET_STATISTICS_update (stats,
4392 gettext_noop ("# peerinfo process hello iterate requests"),
4395 GNUNET_STATISTICS_update (stats,
4396 gettext_noop ("# outstanding peerinfo iterate requests"),
4399 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4401 HELLO_VERIFICATION_TIMEOUT,
4402 &check_hello_validated, chvc);
4408 * The peer specified by the given neighbour has timed-out or a plugin
4409 * has disconnected. We may either need to do nothing (other plugins
4410 * still up), or trigger a full disconnect and clean up. This
4411 * function updates our state and does the necessary notifications.
4412 * Also notifies our clients that the neighbour is now officially
4415 * @param n the neighbour list entry for the peer
4416 * @param check GNUNET_YES to check if ALL addresses for this peer
4417 * are gone, GNUNET_NO to force a disconnect of the peer
4418 * regardless of whether other addresses exist.
4421 disconnect_neighbour (struct NeighbourList *n, int check)
4423 struct ReadyList *rpos;
4424 struct NeighbourList *npos;
4425 struct NeighbourList *nprev;
4426 struct MessageQueue *mq;
4427 struct ForeignAddressList *peer_addresses;
4428 struct ForeignAddressList *peer_pos;
4430 if (GNUNET_YES == check)
4433 while (NULL != rpos)
4435 peer_addresses = rpos->addresses;
4436 while (peer_addresses != NULL)
4438 if (GNUNET_YES == peer_addresses->connected)
4440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4441 "NOT Disconnecting from `%4s', still have live addresses!\n",
4442 GNUNET_i2s (&n->id));
4443 return; /* still connected */
4445 peer_addresses = peer_addresses->next;
4451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4452 "Disconnecting from `%4s'\n",
4453 GNUNET_i2s (&n->id));
4455 /* remove n from neighbours list */
4458 while ((npos != NULL) && (npos != n))
4463 GNUNET_assert (npos != NULL);
4465 neighbours = n->next;
4467 nprev->next = n->next;
4469 /* notify all clients about disconnect */
4470 if (GNUNET_YES == n->received_pong)
4471 notify_clients_disconnect (&n->id);
4473 /* clean up all plugins, cancel connections and pending transmissions */
4474 while (NULL != (rpos = n->plugins))
4476 n->plugins = rpos->next;
4477 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4478 while (rpos->addresses != NULL)
4480 peer_pos = rpos->addresses;
4481 rpos->addresses = peer_pos->next;
4482 if (peer_pos->connected == GNUNET_YES)
4483 GNUNET_STATISTICS_update (stats,
4484 gettext_noop ("# connected addresses"),
4487 if (GNUNET_YES == peer_pos->validated)
4488 GNUNET_STATISTICS_update (stats,
4489 gettext_noop ("# peer addresses considered valid"),
4492 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4494 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4495 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4497 GNUNET_free(peer_pos);
4502 /* free all messages on the queue */
4503 while (NULL != (mq = n->messages_head))
4505 GNUNET_STATISTICS_update (stats,
4506 gettext_noop ("# bytes in message queue for other peers"),
4507 - (int64_t) mq->message_buf_size,
4509 GNUNET_STATISTICS_update (stats,
4510 gettext_noop ("# bytes discarded due to disconnect"),
4511 mq->message_buf_size,
4513 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4516 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4518 sizeof(struct GNUNET_PeerIdentity)));
4521 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4523 GNUNET_SCHEDULER_cancel (n->timeout_task);
4524 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4526 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4528 GNUNET_SCHEDULER_cancel (n->retry_task);
4529 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4531 if (n->piter != NULL)
4533 GNUNET_PEERINFO_iterate_cancel (n->piter);
4534 GNUNET_STATISTICS_update (stats,
4535 gettext_noop ("# outstanding peerinfo iterate requests"),
4540 /* finally, free n itself */
4541 GNUNET_STATISTICS_update (stats,
4542 gettext_noop ("# active neighbours"),
4545 GNUNET_free_non_null (n->pre_connect_message_buffer);
4551 * We have received a PING message from someone. Need to send a PONG message
4552 * in response to the peer by any means necessary.
4555 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4556 const struct GNUNET_PeerIdentity *peer,
4557 struct Session *session,
4558 const char *sender_address,
4559 uint16_t sender_address_len)
4561 struct TransportPlugin *plugin = cls;
4562 struct SessionHeader *session_header = (struct SessionHeader*) session;
4563 struct TransportPingMessage *ping;
4564 struct TransportPongMessage *pong;
4565 struct NeighbourList *n;
4566 struct ReadyList *rl;
4567 struct ForeignAddressList *fal;
4568 struct OwnAddressList *oal;
4573 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4575 GNUNET_break_op (0);
4576 return GNUNET_SYSERR;
4579 ping = (struct TransportPingMessage *) message;
4580 if (0 != memcmp (&ping->target,
4581 plugin->env.my_identity,
4582 sizeof (struct GNUNET_PeerIdentity)))
4584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4585 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4587 (sender_address != NULL)
4588 ? a2s (plugin->short_name,
4589 (const struct sockaddr *)sender_address,
4592 GNUNET_i2s (&ping->target));
4593 return GNUNET_SYSERR;
4596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4597 "Processing `%s' from `%s'\n",
4599 (sender_address != NULL)
4600 ? a2s (plugin->short_name,
4601 (const struct sockaddr *)sender_address,
4605 GNUNET_STATISTICS_update (stats,
4606 gettext_noop ("# PING messages received"),
4609 addr = (const char*) &ping[1];
4610 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4611 slen = strlen (plugin->short_name) + 1;
4614 /* peer wants to confirm that we have an outbound connection to him */
4615 if (session == NULL)
4617 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4618 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4620 return GNUNET_SYSERR;
4622 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4623 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4624 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4625 pong->purpose.size =
4626 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4628 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4629 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4630 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4631 pong->challenge = ping->challenge;
4632 pong->addrlen = htonl(sender_address_len + slen);
4635 sizeof(struct GNUNET_PeerIdentity));
4639 if ((sender_address!=NULL) && (sender_address_len > 0))
4640 memcpy (&((char*)&pong[1])[slen],
4642 sender_address_len);
4643 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4645 /* create / update cached sig */
4647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4648 "Creating PONG signature to indicate active connection.\n");
4650 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4651 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4652 GNUNET_assert (GNUNET_OK ==
4653 GNUNET_CRYPTO_rsa_sign (my_private_key,
4655 &session_header->pong_signature));
4659 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4661 memcpy (&pong->signature,
4662 &session_header->pong_signature,
4663 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4669 /* peer wants to confirm that this is one of our addresses */
4673 plugin->api->check_address (plugin->api->cls,
4677 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4678 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4679 a2s (plugin->short_name,
4684 oal = plugin->addresses;
4687 if ( (oal->addrlen == alen) &&
4694 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4695 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4696 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4697 pong->purpose.size =
4698 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4700 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4701 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4702 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4703 pong->challenge = ping->challenge;
4704 pong->addrlen = htonl(alen + slen);
4707 sizeof(struct GNUNET_PeerIdentity));
4708 memcpy (&pong[1], plugin->short_name, slen);
4709 memcpy (&((char*)&pong[1])[slen], addr, alen);
4710 if ( (oal != NULL) &&
4711 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4713 /* create / update cached sig */
4715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4716 "Creating PONG signature to indicate ownership.\n");
4718 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4719 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4720 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4721 GNUNET_assert (GNUNET_OK ==
4722 GNUNET_CRYPTO_rsa_sign (my_private_key,
4724 &oal->pong_signature));
4725 memcpy (&pong->signature,
4726 &oal->pong_signature,
4727 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4729 else if (oal == NULL)
4731 /* not using cache (typically DV-only) */
4732 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4733 GNUNET_assert (GNUNET_OK ==
4734 GNUNET_CRYPTO_rsa_sign (my_private_key,
4740 /* can used cached version */
4741 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4742 memcpy (&pong->signature,
4743 &oal->pong_signature,
4744 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4747 n = find_neighbour(peer);
4748 GNUNET_assert (n != NULL);
4749 /* first try reliable response transmission */
4753 fal = rl->addresses;
4756 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4759 ntohs (pong->header.size),
4760 TRANSPORT_PONG_PRIORITY,
4761 HELLO_VERIFICATION_TIMEOUT,
4769 GNUNET_STATISTICS_update (stats,
4770 gettext_noop ("# PONGs unicast via reliable transport"),
4780 /* no reliable method found, do multicast */
4781 GNUNET_STATISTICS_update (stats,
4782 gettext_noop ("# PONGs multicast to all available addresses"),
4788 fal = rl->addresses;
4791 transmit_to_peer(NULL, fal,
4792 TRANSPORT_PONG_PRIORITY,
4793 HELLO_VERIFICATION_TIMEOUT,
4795 ntohs(pong->header.size),
4808 * Function called by the plugin for each received message.
4809 * Update data volumes, possibly notify plugins about
4810 * reducing the rate at which they read from the socket
4811 * and generally forward to our receive callback.
4813 * @param cls the "struct TransportPlugin *" we gave to the plugin
4814 * @param peer (claimed) identity of the other peer
4815 * @param message the message, NULL if we only care about
4816 * learning about the delay until we should receive again
4817 * @param ats_data information for automatic transport selection
4818 * @param ats_count number of elements in ats not including 0-terminator
4819 * @param session identifier used for this session (can be NULL)
4820 * @param sender_address binary address of the sender (if observed)
4821 * @param sender_address_len number of bytes in sender_address
4822 * @return how long in ms the plugin should wait until receiving more data
4823 * (plugins that do not support this, can ignore the return value)
4825 static struct GNUNET_TIME_Relative
4826 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4827 const struct GNUNET_MessageHeader *message,
4828 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4830 struct Session *session,
4831 const char *sender_address,
4832 uint16_t sender_address_len)
4834 struct TransportPlugin *plugin = cls;
4835 struct ReadyList *service_context;
4836 struct ForeignAddressList *peer_address;
4838 struct NeighbourList *n;
4839 struct GNUNET_TIME_Relative ret;
4840 if (is_blacklisted (peer, plugin))
4841 return GNUNET_TIME_UNIT_FOREVER_REL;
4845 n = find_neighbour (peer);
4847 n = setup_new_neighbour (peer, GNUNET_YES);
4848 service_context = n->plugins;
4849 while ((service_context != NULL) && (plugin != service_context->plugin))
4850 service_context = service_context->next;
4851 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4852 peer_address = NULL;
4854 for (c=0; c<ats_count; c++)
4856 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4858 distance = ntohl(ats_data[c].value);
4861 /* notify ATS about incoming data */
4862 ats_notify_ats_data(peer, ats_data);
4864 if (message != NULL)
4866 if ( (session != NULL) ||
4867 (sender_address != NULL) )
4868 peer_address = add_peer_address (n,
4872 sender_address_len);
4873 if (peer_address != NULL)
4875 peer_address->distance = distance;
4876 if (GNUNET_YES == peer_address->validated)
4877 mark_address_connected (peer_address);
4878 peer_address->timeout
4880 GNUNET_TIME_relative_to_absolute
4881 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4882 schedule_next_ping (peer_address);
4884 /* update traffic received amount ... */
4885 msize = ntohs (message->size);
4886 GNUNET_STATISTICS_update (stats,
4887 gettext_noop ("# bytes received from other peers"),
4890 n->distance = distance;
4892 GNUNET_TIME_relative_to_absolute
4893 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4894 GNUNET_SCHEDULER_cancel (n->timeout_task);
4896 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4897 &neighbour_timeout_task, n);
4898 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4900 /* dropping message due to frequent inbound volume violations! */
4901 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4902 GNUNET_ERROR_TYPE_BULK,
4904 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4905 n->in_tracker.available_bytes_per_s__,
4906 n->quota_violation_count);
4907 GNUNET_STATISTICS_update (stats,
4908 gettext_noop ("# bandwidth quota violations by other peers"),
4911 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4916 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4917 ntohs (message->type),
4918 ntohs (message->size),
4921 switch (ntohs (message->type))
4923 case GNUNET_MESSAGE_TYPE_HELLO:
4924 GNUNET_STATISTICS_update (stats,
4925 gettext_noop ("# HELLO messages received from other peers"),
4928 process_hello (plugin, message);
4930 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4931 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4933 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4934 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4937 handle_payload_message (message, n);
4941 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4942 if (ret.rel_value > 0)
4944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4945 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4946 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4947 (unsigned int) n->in_tracker.available_bytes_per_s__,
4948 (unsigned long long) ret.rel_value);
4949 GNUNET_STATISTICS_update (stats,
4950 gettext_noop ("# ms throttling suggested"),
4951 (int64_t) ret.rel_value,
4958 * Handle START-message. This is the first message sent to us
4959 * by any client which causes us to add it to our list.
4961 * @param cls closure (always NULL)
4962 * @param client identification of the client
4963 * @param message the actual message
4966 handle_start (void *cls,
4967 struct GNUNET_SERVER_Client *client,
4968 const struct GNUNET_MessageHeader *message)
4970 const struct StartMessage *start;
4971 struct TransportClient *c;
4972 struct ConnectInfoMessage * cim;
4973 struct NeighbourList *n;
4977 start = (const struct StartMessage*) message;
4979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4980 "Received `%s' request from client\n", "START");
4985 if (c->client == client)
4987 /* client already on our list! */
4989 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4994 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4995 (0 != memcmp (&start->self,
4997 sizeof (struct GNUNET_PeerIdentity))) )
4999 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5000 _("Rejecting control connection from peer `%s', which is not me!\n"),
5001 GNUNET_i2s (&start->self));
5002 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5005 c = GNUNET_malloc (sizeof (struct TransportClient));
5009 if (our_hello != NULL)
5012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5013 "Sending our own `%s' to new client\n", "HELLO");
5015 transmit_to_client (c,
5016 (const struct GNUNET_MessageHeader *) our_hello,
5018 /* tell new client about all existing connections */
5020 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5021 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5025 cim = GNUNET_malloc (size);
5026 cim->header.size = htons (size);
5027 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5028 cim->ats_count = htonl(ats_count);
5029 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5030 (&(cim->ats))[2].value = htonl (0);
5034 if (GNUNET_YES == n->received_pong)
5036 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5037 (&(cim->ats))[0].value = htonl (n->distance);
5038 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5039 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5041 transmit_to_client (c, &cim->header, GNUNET_NO);
5047 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5052 * Handle HELLO-message.
5054 * @param cls closure (always NULL)
5055 * @param client identification of the client
5056 * @param message the actual message
5059 handle_hello (void *cls,
5060 struct GNUNET_SERVER_Client *client,
5061 const struct GNUNET_MessageHeader *message)
5065 GNUNET_STATISTICS_update (stats,
5066 gettext_noop ("# HELLOs received from clients"),
5069 ret = process_hello (NULL, message);
5070 GNUNET_SERVER_receive_done (client, ret);
5075 * Closure for 'transmit_client_message'; followed by
5076 * 'msize' bytes of the actual message.
5078 struct TransmitClientMessageContext
5081 * Client on whom's behalf we are sending.
5083 struct GNUNET_SERVER_Client *client;
5086 * Timeout for the transmission.
5088 struct GNUNET_TIME_Absolute timeout;
5096 * Size of the message in bytes.
5103 * Schedule transmission of a message we got from a client to a peer.
5105 * @param cls the 'struct TransmitClientMessageContext*'
5106 * @param n destination, or NULL on error (in that case, drop the message)
5109 transmit_client_message (void *cls,
5110 struct NeighbourList *n)
5112 struct TransmitClientMessageContext *tcmc = cls;
5113 struct TransportClient *tc;
5116 while ((tc != NULL) && (tc->client != tcmc->client))
5121 transmit_to_peer (tc, NULL, tcmc->priority,
5122 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5124 tcmc->msize, GNUNET_NO, n);
5126 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5127 GNUNET_SERVER_client_drop (tcmc->client);
5133 * Handle SEND-message.
5135 * @param cls closure (always NULL)
5136 * @param client identification of the client
5137 * @param message the actual message
5140 handle_send (void *cls,
5141 struct GNUNET_SERVER_Client *client,
5142 const struct GNUNET_MessageHeader *message)
5144 const struct OutboundMessage *obm;
5145 const struct GNUNET_MessageHeader *obmm;
5146 struct TransmitClientMessageContext *tcmc;
5150 size = ntohs (message->size);
5152 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5155 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5158 GNUNET_STATISTICS_update (stats,
5159 gettext_noop ("# payload received for other peers"),
5162 obm = (const struct OutboundMessage *) message;
5163 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5164 msize = size - sizeof (struct OutboundMessage);
5166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5167 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5168 "SEND", GNUNET_i2s (&obm->peer),
5172 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5173 tcmc->client = client;
5174 tcmc->priority = ntohl (obm->priority);
5175 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5176 tcmc->msize = msize;
5177 /* FIXME: this memcpy can be up to 7% of our total runtime */
5178 memcpy (&tcmc[1], obmm, msize);
5179 GNUNET_SERVER_client_keep (client);
5180 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5181 &transmit_client_message,
5187 * Handle request connect message
5189 * @param cls closure (always NULL)
5190 * @param client identification of the client
5191 * @param message the actual message
5194 handle_request_connect (void *cls,
5195 struct GNUNET_SERVER_Client *client,
5196 const struct GNUNET_MessageHeader *message)
5198 const struct TransportRequestConnectMessage *trcm =
5199 (const struct TransportRequestConnectMessage *) message;
5201 GNUNET_STATISTICS_update (stats,
5202 gettext_noop ("# REQUEST CONNECT messages received"),
5205 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5206 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5208 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5212 * Handle SET_QUOTA-message.
5214 * @param cls closure (always NULL)
5215 * @param client identification of the client
5216 * @param message the actual message
5219 handle_set_quota (void *cls,
5220 struct GNUNET_SERVER_Client *client,
5221 const struct GNUNET_MessageHeader *message)
5223 const struct QuotaSetMessage *qsm =
5224 (const struct QuotaSetMessage *) message;
5225 struct NeighbourList *n;
5227 GNUNET_STATISTICS_update (stats,
5228 gettext_noop ("# SET QUOTA messages received"),
5231 n = find_neighbour (&qsm->peer);
5234 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5235 GNUNET_STATISTICS_update (stats,
5236 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5243 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5245 (unsigned int) ntohl (qsm->quota.value__),
5246 (unsigned int) n->in_tracker.available_bytes_per_s__,
5247 GNUNET_i2s (&qsm->peer));
5249 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5251 if (0 == ntohl (qsm->quota.value__))
5253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5254 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5256 disconnect_neighbour (n, GNUNET_NO);
5258 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5263 * Take the given address and append it to the set of results sent back to
5266 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5267 * @param address the resolved name, NULL to indicate the last response
5270 transmit_address_to_client (void *cls, const char *address)
5272 struct GNUNET_SERVER_TransmitContext *tc = cls;
5275 if (NULL == address)
5278 slen = strlen (address) + 1;
5280 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5281 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5282 if (NULL == address)
5283 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5288 * Handle AddressLookup-message.
5290 * @param cls closure (always NULL)
5291 * @param client identification of the client
5292 * @param message the actual message
5295 handle_address_lookup (void *cls,
5296 struct GNUNET_SERVER_Client *client,
5297 const struct GNUNET_MessageHeader *message)
5299 const struct AddressLookupMessage *alum;
5300 struct TransportPlugin *lsPlugin;
5301 const char *nameTransport;
5302 const char *address;
5304 struct GNUNET_SERVER_TransmitContext *tc;
5305 struct GNUNET_TIME_Absolute timeout;
5306 struct GNUNET_TIME_Relative rtimeout;
5309 size = ntohs (message->size);
5310 if (size < sizeof (struct AddressLookupMessage))
5312 GNUNET_break_op (0);
5313 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5316 alum = (const struct AddressLookupMessage *) message;
5317 uint32_t addressLen = ntohl (alum->addrlen);
5318 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5320 GNUNET_break_op (0);
5321 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5324 address = (const char *) &alum[1];
5325 nameTransport = (const char *) &address[addressLen];
5327 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5329 GNUNET_break_op (0);
5330 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5333 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5334 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5335 numeric = ntohl (alum->numeric_only);
5336 lsPlugin = find_transport (nameTransport);
5337 if (NULL == lsPlugin)
5339 tc = GNUNET_SERVER_transmit_context_create (client);
5340 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5341 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5342 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5345 tc = GNUNET_SERVER_transmit_context_create (client);
5346 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5348 address, addressLen,
5351 &transmit_address_to_client, tc);
5356 * Setup the environment for this plugin.
5359 create_environment (struct TransportPlugin *plug)
5361 plug->env.cfg = cfg;
5362 plug->env.my_identity = &my_identity;
5363 plug->env.our_hello = &our_hello;
5364 plug->env.cls = plug;
5365 plug->env.receive = &plugin_env_receive;
5366 plug->env.notify_address = &plugin_env_notify_address;
5367 plug->env.session_end = &plugin_env_session_end;
5368 plug->env.max_connections = max_connect_per_transport;
5369 plug->env.stats = stats;
5374 * Start the specified transport (load the plugin).
5377 start_transport (struct GNUNET_SERVER_Handle *server,
5380 struct TransportPlugin *plug;
5383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5384 _("Loading `%s' transport plugin\n"), name);
5385 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5386 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5387 create_environment (plug);
5388 plug->short_name = GNUNET_strdup (name);
5389 plug->lib_name = libname;
5390 plug->next = plugins;
5392 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5393 if (plug->api == NULL)
5395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5396 _("Failed to load transport plugin for `%s'\n"), name);
5397 GNUNET_free (plug->short_name);
5398 plugins = plug->next;
5399 GNUNET_free (libname);
5406 * Called whenever a client is disconnected. Frees our
5407 * resources associated with that client.
5409 * @param cls closure
5410 * @param client identification of the client
5413 client_disconnect_notification (void *cls,
5414 struct GNUNET_SERVER_Client *client)
5416 struct TransportClient *pos;
5417 struct TransportClient *prev;
5418 struct ClientMessageQueueEntry *mqe;
5419 struct Blacklisters *bl;
5420 struct BlacklistCheck *bc;
5425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5426 "Client disconnected, cleaning up.\n");
5428 /* clean up blacklister */
5432 if (bl->client == client)
5437 if (bc->bl_pos == bl)
5439 bc->bl_pos = bl->next;
5442 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5445 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5446 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5452 GNUNET_CONTAINER_DLL_remove (bl_head,
5455 GNUNET_SERVER_client_drop (bl->client);
5461 /* clean up 'normal' clients */
5464 while ((pos != NULL) && (pos->client != client))
5471 while (NULL != (mqe = pos->message_queue_head))
5473 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5474 pos->message_queue_tail,
5476 pos->message_count--;
5480 clients = pos->next;
5482 prev->next = pos->next;
5483 if (GNUNET_YES == pos->tcs_pending)
5488 if (pos->th != NULL)
5490 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5493 GNUNET_break (0 == pos->message_count);
5499 * Function called when the service shuts down. Unloads our plugins
5500 * and cancels pending validations.
5502 * @param cls closure, unused
5503 * @param tc task context (unused)
5506 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5508 struct TransportPlugin *plug;
5509 struct OwnAddressList *al;
5510 struct CheckHelloValidatedContext *chvc;
5511 struct ATS_plugin * rc;
5513 while (neighbours != NULL)
5515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5516 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5518 disconnect_neighbour (neighbours, GNUNET_NO);
5521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5522 "Transport service is unloading plugins...\n");
5524 while (NULL != (plug = plugins))
5526 plugins = plug->next;
5527 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5529 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5530 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5532 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5533 GNUNET_free (plug->lib_name);
5534 GNUNET_free (plug->short_name);
5535 while (NULL != (al = plug->addresses))
5537 plug->addresses = al->next;
5541 struct ATS_ressource_cost * t;
5542 while (rc->head != NULL)
5545 GNUNET_CONTAINER_DLL_remove(rc->head, rc->tail, rc->head);
5549 GNUNET_free(plug->rc);
5552 if (my_private_key != NULL)
5553 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5554 GNUNET_free_non_null (our_hello);
5556 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5559 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5560 validation_map = NULL;
5564 /* free 'chvc' data structure */
5565 while (NULL != (chvc = chvc_head))
5567 chvc_head = chvc->next;
5568 if (chvc->piter != NULL)
5570 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5571 GNUNET_STATISTICS_update (stats,
5572 gettext_noop ("# outstanding peerinfo iterate requests"),
5578 GNUNET_assert (chvc->ve_count == 0);
5585 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5588 if (peerinfo != NULL)
5590 GNUNET_PEERINFO_disconnect (peerinfo);
5593 /* Can we assume those are gone by now, or do we need to clean up
5595 GNUNET_break (bl_head == NULL);
5596 GNUNET_break (bc_head == NULL);
5599 struct ATS_mechanism
5601 struct ATS_mechanism * prev;
5602 struct ATS_mechanism * next;
5603 struct ForeignAddressList * addr;
5604 struct TransportPlugin * plugin;
5605 struct ATS_peer * peer;
5608 struct ATS_ressource_cost * rc;
5614 struct GNUNET_PeerIdentity peer;
5615 struct NeighbourList * n;
5616 struct ATS_mechanism * m_head;
5617 struct ATS_mechanism * m_tail;
5619 /* preference value f */
5633 struct ATS_ressource
5641 static struct ATS_ressource ressources[] =
5643 {1, 1, "COST_FINANCIAL_PER_VOLUME",VERY_BIG_DOUBLE_VALUE},
5644 {2, 2, "COST_FINANCIAL_PER_TIME", VERY_BIG_DOUBLE_VALUE},
5645 {3, 3, "COST_COMPUTATIONAL", VERY_BIG_DOUBLE_VALUE},
5646 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
5647 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
5648 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
5649 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},
5652 static int available_ressources = 7;
5658 struct GNUNET_CONTAINER_MultiHashMap * peers;
5660 * Time of last execution
5662 struct GNUNET_TIME_Absolute last;
5664 * Minimum intervall between two executions
5666 struct GNUNET_TIME_Relative min_delta;
5668 * Regular intervall when execution is triggered
5670 struct GNUNET_TIME_Relative exec_intervall;
5672 * Maximum execution time per calculation
5674 struct GNUNET_TIME_Relative max_exec_duration;
5676 * Maximum number of LP iterations per calculation
5680 GNUNET_SCHEDULER_TaskIdentifier ats_task;
5682 struct ATS_plugin * head;
5683 struct ATS_plugin * tail;
5686 #define DEBUG_ATS GNUNET_NO
5687 #define VERBOSE_ATS GNUNET_NO
5690 /** solve the bandwidth distribution problem
5691 * @param max_it maximum iterations
5692 * @param max_dur maximum duration in ms
5693 * @param D weight for diversity
5694 * @param U weight for utility
5695 * @param R weight for relativity
5696 * @param v_b_min minimal bandwidth per peer
5697 * @param v_n_min minimum number of connections
5698 * @param res result struct
5699 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5701 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)
5704 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5705 return GNUNET_SYSERR;
5707 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5717 int c_c_ressources = 0;
5718 int c_q_metrics = available_quality_metrics;
5720 //double M = 10000000000; // ~10 GB
5721 double M = VERY_BIG_DOUBLE_VALUE;
5723 double Q[c_q_metrics+1];
5724 for (c=1; c<=c_q_metrics; c++)
5729 struct NeighbourList *next = neighbours;
5732 struct ReadyList *r_next = next->plugins;
5733 while (r_next != NULL)
5735 struct ForeignAddressList * a_next = r_next->addresses;
5736 while (a_next != NULL)
5739 a_next = a_next->next;
5741 r_next = r_next->next;
5749 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5753 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5754 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5756 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
5762 peers[c_peers].peer = next->id;
5763 peers[c_peers].m_head = NULL;
5764 peers[c_peers].m_tail = NULL;
5766 peers[c_peers].f = 1.0 / c_mechs;
5768 struct ReadyList *r_next = next->plugins;
5769 while (r_next != NULL)
5771 struct ForeignAddressList * a_next = r_next->addresses;
5772 while (a_next != NULL)
5774 struct ATS_ressource_cost *rc;
5776 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);
5777 mechanisms[c_mechs].addr = a_next;
5778 mechanisms[c_mechs].col_index = c_mechs;
5779 mechanisms[c_mechs].peer = &peers[c_peers];
5780 mechanisms[c_mechs].next = NULL;
5781 mechanisms[c_mechs].plugin = r_next->plugin;
5782 mechanisms[c_mechs].rc = GNUNET_malloc (available_ressources * sizeof (struct ATS_ressource_cost));
5784 rc = a_next->ressources;
5785 /* get address specific ressource costs */
5788 memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost));
5789 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);
5793 /* get plugin specific ressourc costs */
5796 rc = mechanisms[c_mechs].plugin->rc->head;
5799 if ((mechanisms[c_mechs].rc[rc->index].c_1 == 0) && (rc->c_1 != 0))
5801 memcpy(&mechanisms[c_mechs].rc[rc->index], rc, sizeof (struct ATS_ressource_cost));
5804 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);
5808 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5810 a_next = a_next->next;
5812 r_next = r_next->next;
5820 if (v_n_min > c_peers)
5823 /* number of variables == coloumns */
5824 //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
5825 /* number of constraints == rows */
5826 //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
5828 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);
5830 int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers + (c_q_metrics*c_mechs)+c_q_metrics + 100;// + c_c_ressources ;
5833 int * ia = GNUNET_malloc (size * sizeof (int));
5834 int * ja = GNUNET_malloc (size * sizeof (int));
5835 double * ar = GNUNET_malloc(size* sizeof (double));
5837 prob = glp_create_prob();
5838 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5839 glp_set_obj_dir(prob, GLP_MAX);
5841 /* adding columns */
5843 glp_add_cols(prob, 2 * c_mechs);
5844 /* adding b_t cols */
5845 for (c=1; c <= c_mechs; c++)
5847 GNUNET_asprintf(&name, "b%i",c);
5848 glp_set_col_name(prob, c, name);
5850 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5851 glp_set_obj_coef(prob, c, 1);
5854 /* adding n_t cols */
5855 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5857 GNUNET_asprintf(&name, "n%i",(c-c_mechs));
5858 glp_set_col_name(prob, c, name);
5860 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5861 glp_set_col_kind(prob, c, GLP_IV);
5862 glp_set_obj_coef(prob, c, 0);
5865 /* feasibility constraints */
5866 /* Constraint 1: one address per peer*/
5867 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
5869 glp_add_rows(prob, c_peers);
5870 for (c=1; c<=c_peers; c++)
5872 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
5874 struct ATS_mechanism *m = peers[c].m_head;
5877 ia[array_index] = row_index;
5878 ja[array_index] = (c_mechs + m->col_index);
5879 ar[array_index] = 1;
5880 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]);
5887 /* Constraint 2: only active mechanism gets bandwidth assigned */
5888 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
5889 glp_add_rows(prob, c_mechs);
5890 for (c=1; c<=c_mechs; c++)
5892 /* b_t - n_t * M <= 0 */
5893 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5894 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5896 ia[array_index] = row_index;
5897 ja[array_index] = mechanisms[c].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]);
5901 ia[array_index] = row_index;
5902 ja[array_index] = c_mechs + mechanisms[c].col_index;
5903 ar[array_index] = -M;
5904 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]);
5909 /* Constraint 3: minimum bandwidth*/
5910 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5911 glp_add_rows(prob, c_mechs);
5912 for (c=1; c<=c_mechs; c++)
5914 /* b_t - n_t * b_min <= 0 */
5915 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5916 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5918 ia[array_index] = row_index;
5919 ja[array_index] = mechanisms[c].col_index;
5920 ar[array_index] = 1;
5921 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]);
5923 ia[array_index] = row_index;
5924 ja[array_index] = c_mechs + mechanisms[c].col_index;
5925 ar[array_index] = -v_b_min;
5926 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]);
5931 /* Constraint 4: max ressource capacity */
5932 /* V cr: bt * ct_r <= cr_max
5935 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 4\n");
5936 glp_add_rows(prob, available_ressources);
5937 double ct_max = 0.0;
5938 //double ct_1 = 0.0;
5940 for (c=0; c<available_ressources; c++)
5942 ct_max = ressources[c].c_max;
5943 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f\n",row_index, ct_max);
5944 glp_set_row_bnds(prob, row_index, GLP_DB, 0.0, ct_max);
5946 for (c2=1; c2<=c_mechs; c2++)
5948 if (mechanisms[c2].rc[c].c_1 != 0)
5950 ia[array_index] = row_index;
5951 ja[array_index] = mechanisms[c2].col_index;
5952 ar[array_index] = mechanisms[c2].rc[c].c_1;
5953 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]);
5960 /* Constraint 5: min number of connections*/
5961 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
5962 glp_add_rows(prob, 1);
5963 for (c=1; c<=c_mechs; c++)
5965 // b_t - n_t * b_min >= 0
5966 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5967 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
5969 ia[array_index] = row_index;
5970 ja[array_index] = c_mechs + mechanisms[c].col_index;
5971 ar[array_index] = 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]);
5977 /* optimisation constraints*/
5979 /* adding columns */
5980 glp_add_cols(prob, 3 + c_q_metrics);
5982 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
5983 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
5984 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
5986 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
5987 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
5988 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
5989 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
5990 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
5991 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
5993 for (c=1; c<= c_q_metrics; c++)
5995 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
5996 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
5997 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
5999 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6002 // Constraint 6: optimize for diversity
6003 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 6\n");
6004 glp_add_rows(prob, 1);
6005 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6006 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6007 //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6008 for (c=1; c<=c_mechs; c++)
6010 // b_t - n_t * b_min >= 0
6011 ia[array_index] = row_index;
6012 ja[array_index] = c_mechs + mechanisms[c].col_index;
6013 ar[array_index] = 1;
6014 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]);
6017 ia[array_index] = row_index;
6018 ja[array_index] = (2*c_mechs) + 1;
6019 ar[array_index] = -1;
6020 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]);
6025 // Constraint 7: optimize for quality
6027 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 7\n");
6028 glp_add_rows(prob, available_quality_metrics);
6029 for (c=1; c <= c_q_metrics; c++)
6031 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6032 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6034 for (c2=1; c2<=c_mechs; c2++)
6037 ia[array_index] = row_index;
6038 ja[array_index] = c2;
6039 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6041 //value = mechanisms[c2].addr->latency.rel_value;
6044 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6046 //value = mechanisms[c2].addr->distance;
6049 ar[array_index] = 1 * mechanisms[c2].peer->f * value ;
6050 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]);
6054 ia[array_index] = row_index;
6055 ja[array_index] = (2*c_mechs) + 3 +c;
6056 ar[array_index] = -1;
6057 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]);
6062 // Constraint 8: optimize bandwidth utility
6063 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 8\n");
6064 glp_add_rows(prob, 1);
6065 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6066 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6067 for (c=1; c<=c_mechs; c++)
6069 ia[array_index] = row_index;
6070 ja[array_index] = c;
6071 ar[array_index] = mechanisms[c].peer->f;
6072 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]);
6075 ia[array_index] = row_index;
6076 ja[array_index] = (2*c_mechs) + 2;
6077 ar[array_index] = -1;
6079 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6085 // Constraint 9: optimize relativity
6086 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 9\n");
6087 glp_add_rows(prob, c_peers);
6088 for (c=1; c<=c_peers; c++)
6090 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6092 struct ATS_mechanism *m = peers[c].m_head;
6095 ia[array_index] = row_index;
6096 ja[array_index] = m->col_index;
6097 ar[array_index] = 1;
6098 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]);
6102 ia[array_index] = row_index;
6103 ja[array_index] = (2*c_mechs) + 3;
6104 ar[array_index] = -1;
6105 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]);
6110 glp_load_matrix(prob, array_index-1, ia, ja, ar);
6114 glp_init_smcp(&opt_lp);
6116 opt_lp.msg_lev = GLP_MSG_ALL;
6118 opt_lp.msg_lev = GLP_MSG_OFF;
6119 result = glp_simplex(prob, &opt_lp);
6122 glp_init_iocp(&opt_mlp);
6123 /* maximum duration */
6124 opt_mlp.tm_lim = max_dur;
6127 opt_mlp.msg_lev = GLP_MSG_ALL;
6129 opt_mlp.msg_lev = GLP_MSG_OFF;
6131 result = glp_intopt (prob, &opt_mlp);
6132 solution = glp_mip_status (prob);
6135 if (VERBOSE_ATS) glp_write_lp(prob, NULL, "ats_mlp.lp");
6138 case GLP_ESTOP : /* search terminated by application */
6139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Search terminated by application ");
6141 case GLP_EITLIM : /* iteration limit exceeded */
6142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Iteration limit exceeded ");
6145 case GLP_ETMLIM : /* time limit exceeded */
6146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Time limit exceeded ");
6148 case GLP_ENOPFS : /* no primal feasible solution */
6149 case GLP_ENODFS : /* no dual feasible solution */
6150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No feasible solution");
6153 case GLP_EBADB : /* invalid basis */
6154 case GLP_ESING : /* singular matrix */
6155 case GLP_ECOND : /* ill-conditioned matrix */
6156 case GLP_EBOUND : /* invalid bounds */
6157 case GLP_EFAIL : /* solver failed */
6158 case GLP_EOBJLL : /* objective lower limit reached */
6159 case GLP_EOBJUL : /* objective upper limit reached */
6160 case GLP_EROOT : /* root LP optimum not provided */
6161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid Input data: %i\n", result);
6166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem has been solved\n");
6172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is undefined\n");
6175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer optimal\n");
6178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n");
6181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MI problem has no integer feasible solution\n");
6190 struct ATS_mechanism *t = NULL;
6191 for (c=1; c<= (c_peers); c++ )
6194 t = peers[c].m_head;
6197 bw = glp_get_col_prim(prob, t->col_index);
6201 GNUNET_assert (check != GNUNET_YES);
6203 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);
6209 for (c=1; c<= c_q_metrics; c++ )
6211 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));
6214 res->c_mechs = c_mechs;
6215 res->c_peers = c_peers;
6216 res->solution = solution;
6221 glp_delete_prob(prob);
6227 for (c=0; c<c_mechs; c++)
6229 GNUNET_free_non_null (mechanisms[c].rc);
6232 GNUNET_free(mechanisms);
6239 void ats_calculate_bandwidth_distribution ()
6241 static int glpk = GNUNET_YES;
6242 struct GNUNET_TIME_Absolute start;
6243 struct GNUNET_TIME_Relative duration;
6244 struct ATS_result result;
6247 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6248 if (delta.rel_value < ats->min_delta.rel_value)
6251 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6257 if (INT_MAX < ats->max_exec_duration.rel_value)
6260 dur = (int) ats->max_exec_duration.rel_value;
6262 start = GNUNET_TIME_absolute_get();
6264 if (glpk==GNUNET_YES)
6266 start = GNUNET_TIME_absolute_get();
6267 c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result);
6268 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6271 if (DEBUG_ATS) {GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);}
6272 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6273 GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6274 GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6275 GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6276 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6278 else if (c_mechs == 0)
6280 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6282 else glpk = GNUNET_NO;
6284 ats->last = GNUNET_TIME_absolute_get();
6290 ats_schedule_calculation (void *cls,
6291 const struct GNUNET_SCHEDULER_TaskContext *tc)
6293 struct ATS_info *ats = (struct ATS_info *) cls;
6297 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6298 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6302 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6304 ats_calculate_bandwidth_distribution (ats);
6306 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6307 &ats_schedule_calculation, ats);
6311 int ats_map_remove_peer (void *cls,
6312 const GNUNET_HashCode * key,
6316 struct ATS_peer * p = (struct ATS_peer *) value;
6318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
6328 struct ATS_info * ats_init ()
6330 struct ATS_info * ats;
6332 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
6334 ats = GNUNET_malloc(sizeof (struct ATS_info));
6335 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
6336 GNUNET_assert(ats->peers!=NULL);
6338 ats->min_delta = ATS_MIN_INTERVAL;
6339 ats->exec_intervall = ATS_EXEC_INTERVAL;
6340 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6341 ats->max_iterations = ATS_MAX_ITERATIONS;
6342 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6344 /* loading cost ressources */
6346 struct TransportPlugin * cur = plugins;
6347 struct ATS_ressource_cost * rc;
6348 struct ATS_plugin * p;
6349 unsigned long long value;
6354 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Loading resource cost for plugin `%s'\n", cur->short_name);
6355 p = GNUNET_malloc(sizeof (struct ATS_plugin));
6356 GNUNET_CONTAINER_DLL_insert_tail(ats->head,ats->tail, p);
6358 GNUNET_asprintf(§ion,"transport-%s",cur->short_name);
6359 p->short_name = strdup(cur->short_name);
6361 while (c < available_ressources)
6363 if (GNUNET_CONFIGURATION_have_value(cfg,section, ressources[c].cfg_param))
6365 GNUNET_CONFIGURATION_get_value_number(cfg,section, ressources[c].cfg_param, &value);
6366 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", ressources[c].cfg_param, value);
6369 rc = GNUNET_malloc(sizeof (struct ATS_ressource_cost));
6371 rc->atsi_index = ressources[c].atis_index;
6373 GNUNET_CONTAINER_DLL_insert_tail(p->head,p->tail, rc);
6377 //if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT Found ressource cost: [%s] = %llu \n", ressources[c].cfg_param, value);
6384 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6390 void ats_shutdown ()
6393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6395 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6396 GNUNET_SCHEDULER_cancel(ats->ats_task);
6397 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6399 struct ATS_plugin * p;
6400 struct ATS_ressource_cost * rc;
6404 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6408 GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6412 GNUNET_free(p->short_name);
6417 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
6418 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
6423 void ats_notify_peer_connect (
6424 const struct GNUNET_PeerIdentity *peer,
6425 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6429 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6432 while (ntohl(ats_data[c].type)!=0)
6435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6439 /* check if peer is already known */
6440 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
6442 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
6443 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
6444 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
6447 ats_calculate_bandwidth_distribution(ats);
6450 void ats_notify_peer_disconnect (
6451 const struct GNUNET_PeerIdentity *peer)
6454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6457 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
6459 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
6460 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
6463 ats_calculate_bandwidth_distribution (ats);
6467 void ats_notify_ats_data (
6468 const struct GNUNET_PeerIdentity *peer,
6469 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6472 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6474 ats_calculate_bandwidth_distribution(ats);
6477 struct ForeignAddressList * ats_get_preferred_address (
6478 struct NeighbourList *n)
6481 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6483 struct ReadyList *next = n->plugins;
6484 while (next != NULL)
6487 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6491 return find_ready_address(n);
6495 * Initiate transport service.
6497 * @param cls closure
6498 * @param server the initialized server
6499 * @param c configuration to use
6503 struct GNUNET_SERVER_Handle *server,
6504 const struct GNUNET_CONFIGURATION_Handle *c)
6506 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6507 {&handle_start, NULL,
6508 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6509 {&handle_hello, NULL,
6510 GNUNET_MESSAGE_TYPE_HELLO, 0},
6511 {&handle_send, NULL,
6512 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6513 {&handle_request_connect, NULL,
6514 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6515 {&handle_set_quota, NULL,
6516 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6517 {&handle_address_lookup, NULL,
6518 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6520 {&handle_blacklist_init, NULL,
6521 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6522 {&handle_blacklist_reply, NULL,
6523 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6529 unsigned long long tneigh;
6533 stats = GNUNET_STATISTICS_create ("transport", cfg);
6534 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6535 /* parse configuration */
6537 GNUNET_CONFIGURATION_get_value_number (c,
6542 GNUNET_CONFIGURATION_get_value_filename (c,
6544 "HOSTKEY", &keyfile)))
6546 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6548 ("Transport service is lacking key configuration settings. Exiting.\n"));
6549 GNUNET_SCHEDULER_shutdown ();
6552 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6555 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6556 validation_map = NULL;
6560 max_connect_per_transport = (uint32_t) tneigh;
6561 peerinfo = GNUNET_PEERINFO_connect (cfg);
6562 if (peerinfo == NULL)
6564 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6565 _("Could not access PEERINFO service. Exiting.\n"));
6566 GNUNET_SCHEDULER_shutdown ();
6569 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6572 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6573 validation_map = NULL;
6574 GNUNET_free (keyfile);
6577 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6578 GNUNET_free (keyfile);
6579 if (my_private_key == NULL)
6581 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6583 ("Transport service could not access hostkey. Exiting.\n"));
6584 GNUNET_SCHEDULER_shutdown ();
6587 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6590 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6591 validation_map = NULL;
6594 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6595 GNUNET_CRYPTO_hash (&my_public_key,
6596 sizeof (my_public_key), &my_identity.hashPubKey);
6597 /* setup notification */
6598 GNUNET_SERVER_disconnect_notify (server,
6599 &client_disconnect_notification, NULL);
6600 /* load plugins... */
6603 GNUNET_CONFIGURATION_get_value_string (c,
6604 "TRANSPORT", "PLUGINS", &plugs))
6606 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6607 _("Starting transport plugins `%s'\n"), plugs);
6608 pos = strtok (plugs, " ");
6611 start_transport (server, pos);
6613 pos = strtok (NULL, " ");
6615 GNUNET_free (plugs);
6617 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6618 &shutdown_task, NULL);
6625 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6627 /* If we have a blacklist file, read from it */
6628 read_blacklist_file(cfg);
6629 /* process client requests */
6630 GNUNET_SERVER_add_handlers (server, handlers);
6635 * The main function for the transport service.
6637 * @param argc number of arguments from the command line
6638 * @param argv command line arguments
6639 * @return 0 ok, 1 on error
6642 main (int argc, char *const *argv)
6644 a2s (NULL, NULL, 0); /* make compiler happy */
6645 return (GNUNET_OK ==
6646 GNUNET_SERVICE_run (argc,
6649 GNUNET_SERVICE_OPTION_NONE,
6650 &run, NULL)) ? 0 : 1;
6653 /* end of gnunet-service-transport.c */