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)
153 * List of addresses of other peers
155 struct ForeignAddressList
158 * This is a linked list.
160 struct ForeignAddressList *next;
163 * Which ready list does this entry belong to.
165 struct ReadyList *ready_list;
168 * How long until we auto-expire this address (unless it is
169 * re-confirmed by the transport)?
171 struct GNUNET_TIME_Absolute expires;
174 * Task used to re-validate addresses, updates latencies and
177 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
185 * Session (or NULL if no valid session currently exists or if the
186 * plugin does not use sessions).
188 struct Session *session;
191 * What was the last latency observed for this address, plugin and peer?
193 struct GNUNET_TIME_Relative latency;
196 * If we did not successfully transmit a message to the given peer
197 * via this connection during the specified time, we should consider
198 * the connection to be dead. This is used in the case that a TCP
199 * transport simply stalls writing to the stream but does not
200 * formerly get a signal that the other peer died.
202 struct GNUNET_TIME_Absolute timeout;
205 * How often have we tried to connect using this plugin? Used to
206 * discriminate against addresses that do not work well.
207 * FIXME: not yet used, but should be!
209 unsigned int connect_attempts;
212 * DV distance to this peer (1 if no DV is used).
213 * FIXME: need to set this from transport plugins!
223 * Have we ever estimated the latency of this address? Used to
224 * ensure that the first time we add an address, we immediately
230 * Are we currently connected via this address? The first time we
231 * successfully transmit or receive data to a peer via a particular
232 * address, we set this to GNUNET_YES. If we later get an error
233 * (disconnect notification, transmission failure, timeout), we set
234 * it back to GNUNET_NO.
239 * Is this plugin currently busy transmitting to the specific target?
240 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
241 * messages do not count as 'in transmit'.
246 * Has this address been validated yet?
254 * Entry in linked list of network addresses for ourselves. Also
255 * includes a cached signature for 'struct TransportPongMessage's.
257 struct OwnAddressList
260 * This is a linked list.
262 struct OwnAddressList *next;
265 * How long until we actually auto-expire this address (unless it is
266 * re-confirmed by the transport)?
268 struct GNUNET_TIME_Absolute expires;
271 * How long until the current signature expires? (ZERO if the
272 * signature was never created).
274 struct GNUNET_TIME_Absolute pong_sig_expires;
277 * Signature for a 'struct TransportPongMessage' for this address.
279 struct GNUNET_CRYPTO_RsaSignature pong_signature;
290 * Entry in linked list of all of our plugins.
292 struct TransportPlugin
296 * This is a linked list.
298 struct TransportPlugin *next;
301 * API of the transport as returned by the plugin's
302 * initialization function.
304 struct GNUNET_TRANSPORT_PluginFunctions *api;
307 * Short name for the plugin (i.e. "tcp").
312 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
317 * List of our known addresses for this transport.
319 struct OwnAddressList *addresses;
322 * Environment this transport service is using
325 struct GNUNET_TRANSPORT_PluginEnvironment env;
328 * ID of task that is used to clean up expired addresses.
330 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
333 * Set to GNUNET_YES if we need to scrap the existing list of
334 * "addresses" and start fresh when we receive the next address
335 * update from a transport. Set to GNUNET_NO if we should just add
336 * the new address to the list and wait for the commit call.
341 * Hashmap of blacklisted peers for this particular transport.
343 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
346 struct NeighbourList;
349 * For each neighbour we keep a list of messages
350 * that we still want to transmit to the neighbour.
356 * This is a doubly linked list.
358 struct MessageQueue *next;
361 * This is a doubly linked list.
363 struct MessageQueue *prev;
366 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
367 * stuck together in memory. Allocated at the end of this struct.
369 const char *message_buf;
372 * Size of the message buf
374 size_t message_buf_size;
377 * Client responsible for queueing the message;
378 * used to check that a client has no two messages
379 * pending for the same target. Can be NULL.
381 struct TransportClient *client;
384 * Using which specific address should we send this message?
386 struct ForeignAddressList *specific_address;
389 * Peer ID of the Neighbour this entry belongs to.
391 struct GNUNET_PeerIdentity neighbour_id;
394 * Plugin that we used for the transmission.
395 * NULL until we scheduled a transmission.
397 struct TransportPlugin *plugin;
400 * At what time should we fail?
402 struct GNUNET_TIME_Absolute timeout;
405 * Internal message of the transport system that should not be
406 * included in the usual SEND-SEND_OK transmission confirmation
407 * traffic management scheme. Typically, "internal_msg" will
408 * be set whenever "client" is NULL (but it is not strictly
414 * How important is the message?
416 unsigned int priority;
422 * For a given Neighbour, which plugins are available
423 * to talk to this peer and what are their costs?
428 * This is a linked list.
430 struct ReadyList *next;
433 * Which of our transport plugins does this entry
436 struct TransportPlugin *plugin;
439 * Transport addresses, latency, and readiness for
440 * this particular plugin.
442 struct ForeignAddressList *addresses;
445 * To which neighbour does this ready list belong to?
447 struct NeighbourList *neighbour;
453 * Entry in linked list of all of our current neighbours.
459 * This is a linked list.
461 struct NeighbourList *next;
464 * Which of our transports is connected to this peer
465 * and what is their status?
467 struct ReadyList *plugins;
470 * Head of list of messages we would like to send to this peer;
471 * must contain at most one message per client.
473 struct MessageQueue *messages_head;
476 * Tail of list of messages we would like to send to this peer; must
477 * contain at most one message per client.
479 struct MessageQueue *messages_tail;
482 * Buffer for at most one payload message used when we receive
483 * payload data before our PING-PONG has succeeded. We then
484 * store such messages in this intermediary buffer until the
485 * connection is fully up.
487 struct GNUNET_MessageHeader *pre_connect_message_buffer;
490 * Context for peerinfo iteration.
491 * NULL after we are done processing peerinfo's information.
493 struct GNUNET_PEERINFO_IteratorContext *piter;
496 * Public key for this peer. Valid only if the respective flag is set below.
498 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
501 * Identity of this neighbour.
503 struct GNUNET_PeerIdentity id;
506 * ID of task scheduled to run when this peer is about to
507 * time out (will free resources associated with the peer).
509 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
512 * ID of task scheduled to run when we should retry transmitting
513 * the head of the message queue. Actually triggered when the
514 * transmission is timing out (we trigger instantly when we have
515 * a chance of success).
517 GNUNET_SCHEDULER_TaskIdentifier retry_task;
520 * How long until we should consider this peer dead
521 * (if we don't receive another message in the
524 struct GNUNET_TIME_Absolute peer_timeout;
527 * Tracker for inbound bandwidth.
529 struct GNUNET_BANDWIDTH_Tracker in_tracker;
532 * The latency we have seen for this particular address for
533 * this particular peer. This latency may have been calculated
534 * over multiple transports. This value reflects how long it took
535 * us to receive a response when SENDING via this particular
536 * transport/neighbour/address combination!
538 * FIXME: we need to periodically send PINGs to update this
539 * latency (at least more often than the current "huge" (11h?)
542 struct GNUNET_TIME_Relative latency;
545 * How often has the other peer (recently) violated the
546 * inbound traffic limit? Incremented by 10 per violation,
547 * decremented by 1 per non-violation (for each
550 unsigned int quota_violation_count;
553 * DV distance to this peer (1 if no DV is used).
558 * Have we seen an PONG from this neighbour in the past (and
559 * not had a disconnect since)?
564 * Do we have a valid public key for this neighbour?
566 int public_key_valid;
569 * Performance data for the peer.
571 struct GNUNET_TRANSPORT_ATS_Information *ats;
574 * Identity of the neighbour.
576 struct GNUNET_PeerIdentity peer;
581 * Message used to ask a peer to validate receipt (to check an address
582 * from a HELLO). Followed by the address we are trying to validate,
583 * or an empty address if we are just sending a PING to confirm that a
584 * connection which the receiver (of the PING) initiated is still valid.
586 struct TransportPingMessage
590 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
592 struct GNUNET_MessageHeader header;
595 * Challenge code (to ensure fresh reply).
597 uint32_t challenge GNUNET_PACKED;
600 * Who is the intended recipient?
602 struct GNUNET_PeerIdentity target;
608 * Message used to validate a HELLO. The challenge is included in the
609 * confirmation to make matching of replies to requests possible. The
610 * signature signs our public key, an expiration time and our address.<p>
612 * This message is followed by our transport address that the PING tried
613 * to confirm (if we liked it). The address can be empty (zero bytes)
614 * if the PING had not address either (and we received the request via
615 * a connection that we initiated).
617 struct TransportPongMessage
621 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
623 struct GNUNET_MessageHeader header;
626 * Challenge code from PING (showing freshness). Not part of what
627 * is signed so that we can re-use signatures.
629 uint32_t challenge GNUNET_PACKED;
634 struct GNUNET_CRYPTO_RsaSignature signature;
637 * What are we signing and why? Two possible reason codes can be here:
638 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
639 * plausible address for this peer (pid is set to identity of signer); or
640 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
641 * an address we used to connect to the peer with the given pid.
643 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
646 * When does this signature expire?
648 struct GNUNET_TIME_AbsoluteNBO expiration;
651 * Either the identity of the peer Who signed this message, or the
652 * identity of the peer that we're connected to using the given
653 * address (depending on purpose.type).
655 struct GNUNET_PeerIdentity pid;
658 * Size of address appended to this message (part of what is
659 * being signed, hence not redundant).
667 * Linked list of messages to be transmitted to the client. Each
668 * entry is followed by the actual message.
670 struct ClientMessageQueueEntry
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *next;
678 * This is a doubly-linked list.
680 struct ClientMessageQueueEntry *prev;
685 * Client connected to the transport service.
687 struct TransportClient
691 * This is a linked list.
693 struct TransportClient *next;
696 * Handle to the client.
698 struct GNUNET_SERVER_Client *client;
701 * Linked list of messages yet to be transmitted to
704 struct ClientMessageQueueEntry *message_queue_head;
707 * Tail of linked list of messages yet to be transmitted to the
710 struct ClientMessageQueueEntry *message_queue_tail;
713 * Current transmit request handle.
715 struct GNUNET_CONNECTION_TransmitHandle *th;
718 * Is a call to "transmit_send_continuation" pending? If so, we
719 * must not free this struct (even if the corresponding client
720 * disconnects) and instead only remove it from the linked list and
721 * set the "client" field to NULL.
726 * Length of the list of messages pending for this client.
728 unsigned int message_count;
734 * Context of currently active requests to peerinfo
735 * for validation of HELLOs.
737 struct CheckHelloValidatedContext;
741 * Entry in map of all HELLOs awaiting validation.
743 struct ValidationEntry
747 * NULL if this entry is not part of a larger HELLO validation.
749 struct CheckHelloValidatedContext *chvc;
752 * The address, actually a pointer to the end
753 * of this struct. Do not free!
758 * Name of the transport.
760 char *transport_name;
763 * The public key of the peer.
765 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
768 * ID of task that will clean up this entry if we don't succeed
769 * with the validation first.
771 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
774 * At what time did we send this validation?
776 struct GNUNET_TIME_Absolute send_time;
779 * Session being validated (or NULL for none).
781 struct Session *session;
784 * Challenge number we used.
797 * Context of currently active requests to peerinfo
798 * for validation of HELLOs.
800 struct CheckHelloValidatedContext
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *next;
809 * This is a doubly-linked list.
811 struct CheckHelloValidatedContext *prev;
814 * Hello that we are validating.
816 const struct GNUNET_HELLO_Message *hello;
819 * Context for peerinfo iteration.
820 * NULL after we are done processing peerinfo's information.
822 struct GNUNET_PEERINFO_IteratorContext *piter;
825 * Was a HELLO known for this peer to peerinfo?
830 * Number of validation entries currently referring to this
833 unsigned int ve_count;
841 static struct GNUNET_HELLO_Message *our_hello;
846 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
851 static struct GNUNET_PeerIdentity my_identity;
856 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
861 const struct GNUNET_CONFIGURATION_Handle *cfg;
864 * Linked list of all clients to this service.
866 static struct TransportClient *clients;
869 * All loaded plugins.
871 static struct TransportPlugin *plugins;
874 * Handle to peerinfo service.
876 static struct GNUNET_PEERINFO_Handle *peerinfo;
879 * All known neighbours and their HELLOs.
881 static struct NeighbourList *neighbours;
884 * Number of neighbours we'd like to have.
886 static uint32_t max_connect_per_transport;
889 * Head of linked list.
891 static struct CheckHelloValidatedContext *chvc_head;
894 * Tail of linked list.
896 static struct CheckHelloValidatedContext *chvc_tail;
899 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
900 * of the given peer that we are currently validating).
902 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
905 * Handle for reporting statistics.
907 static struct GNUNET_STATISTICS_Handle *stats;
910 * Handle for ats information
912 static struct ATS_info *ats;
915 * The peer specified by the given neighbour has timed-out or a plugin
916 * has disconnected. We may either need to do nothing (other plugins
917 * still up), or trigger a full disconnect and clean up. This
918 * function updates our state and do the necessary notifications.
919 * Also notifies our clients that the neighbour is now officially
922 * @param n the neighbour list entry for the peer
923 * @param check should we just check if all plugins
924 * disconnected or must we ask all plugins to
927 static void disconnect_neighbour (struct NeighbourList *n, int check);
930 * Check the ready list for the given neighbour and if a plugin is
931 * ready for transmission (and if we have a message), do so!
933 * @param nexi target peer for which to transmit
935 static void try_transmission_to_peer (struct NeighbourList *n);
938 struct ATS_info * ats_init ();
940 void ats_shutdown ( );
942 void ats_notify_peer_connect (
943 const struct GNUNET_PeerIdentity *peer,
944 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
946 void ats_notify_peer_disconnect (
947 const struct GNUNET_PeerIdentity *peer);
949 void ats_notify_ats_data (
950 const struct GNUNET_PeerIdentity *peer,
951 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
953 struct ForeignAddressList * ats_get_preferred_address (
954 struct NeighbourList *n);
957 * Find an entry in the neighbour list for a particular peer.
959 * @return NULL if not found.
961 static struct NeighbourList *
962 find_neighbour (const struct GNUNET_PeerIdentity *key)
964 struct NeighbourList *head = neighbours;
966 while ((head != NULL) &&
967 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
974 * Find an entry in the transport list for a particular transport.
976 * @return NULL if not found.
978 static struct TransportPlugin *
979 find_transport (const char *short_name)
981 struct TransportPlugin *head = plugins;
982 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
988 * Is a particular peer blacklisted for a particular transport?
990 * @param peer the peer to check for
991 * @param plugin the plugin used to connect to the peer
993 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
996 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
999 if (plugin->blacklist != NULL)
1001 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1005 "Peer `%s:%s' is blacklisted!\n",
1006 plugin->short_name, GNUNET_i2s (peer));
1009 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1019 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1021 struct TransportPlugin *plugin;
1023 plugin = find_transport(transport_name);
1024 if (plugin == NULL) /* Nothing to do */
1026 if (plugin->blacklist == NULL)
1027 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1028 GNUNET_assert(plugin->blacklist != NULL);
1029 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1031 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1036 * Read the blacklist file, containing transport:peer entries.
1037 * Provided the transport is loaded, set up hashmap with these
1038 * entries to blacklist peers by transport.
1042 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1049 struct GNUNET_PeerIdentity pid;
1051 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1052 unsigned int entries_found;
1053 char *transport_name;
1056 GNUNET_CONFIGURATION_get_value_filename (cfg,
1062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1063 "Option `%s' in section `%s' not specified!\n",
1069 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1070 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1071 | GNUNET_DISK_PERM_USER_WRITE);
1072 if (0 != STAT (fn, &frstat))
1074 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1075 _("Could not read blacklist file `%s'\n"), fn);
1079 if (frstat.st_size == 0)
1082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1083 _("Blacklist file `%s' is empty.\n"),
1089 /* FIXME: use mmap */
1090 data = GNUNET_malloc_large (frstat.st_size);
1091 GNUNET_assert(data != NULL);
1092 if (frstat.st_size !=
1093 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1095 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1096 _("Failed to read blacklist from `%s'\n"), fn);
1103 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1105 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1106 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1109 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1112 if (colon_pos >= frstat.st_size)
1114 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1115 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1116 (unsigned long long) colon_pos);
1122 if (isspace( (unsigned char) data[colon_pos]))
1124 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1125 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1126 (unsigned long long) colon_pos);
1128 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1132 tsize = colon_pos - pos;
1133 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1135 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1136 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1137 (unsigned long long) colon_pos);
1146 transport_name = GNUNET_malloc(tsize + 1);
1147 memcpy(transport_name, &data[pos], tsize);
1148 pos = colon_pos + 1;
1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1151 "Read transport name %s in blacklist file.\n",
1154 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1155 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1157 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1158 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1159 (unsigned long long) pos);
1161 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1163 GNUNET_free_non_null(transport_name);
1166 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1167 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1169 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1170 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1171 (unsigned long long) pos,
1176 if (0 != memcmp (&pid,
1178 sizeof (struct GNUNET_PeerIdentity)))
1181 add_peer_to_blacklist (&pid,
1186 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1187 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1191 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1192 GNUNET_free_non_null(transport_name);
1193 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1196 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1203 * Function called to notify a client about the socket being ready to
1204 * queue more data. "buf" will be NULL and "size" zero if the socket
1205 * was closed for writing in the meantime.
1207 * @param cls closure
1208 * @param size number of bytes available in buf
1209 * @param buf where the callee should write the message
1210 * @return number of bytes written to buf
1213 transmit_to_client_callback (void *cls, size_t size, void *buf)
1215 struct TransportClient *client = cls;
1216 struct ClientMessageQueueEntry *q;
1219 const struct GNUNET_MessageHeader *msg;
1226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227 "Transmission to client failed, closing connection.\n");
1229 /* fatal error with client, free message queue! */
1230 while (NULL != (q = client->message_queue_head))
1232 GNUNET_STATISTICS_update (stats,
1233 gettext_noop ("# bytes discarded (could not transmit to client)"),
1234 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1236 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1237 client->message_queue_tail,
1241 client->message_count = 0;
1246 while (NULL != (q = client->message_queue_head))
1248 msg = (const struct GNUNET_MessageHeader *) &q[1];
1249 msize = ntohs (msg->size);
1250 if (msize + tsize > size)
1253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1254 "Transmitting message of type %u to client.\n",
1257 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1258 client->message_queue_tail,
1260 memcpy (&cbuf[tsize], msg, msize);
1263 client->message_count--;
1267 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1268 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1270 GNUNET_TIME_UNIT_FOREVER_REL,
1271 &transmit_to_client_callback,
1273 GNUNET_assert (client->th != NULL);
1280 * Convert an address to a string.
1282 * @param plugin name of the plugin responsible for the address
1283 * @param addr binary address
1284 * @param addr_len number of bytes in addr
1285 * @return NULL on error, otherwise address string
1288 a2s (const char *plugin,
1292 struct TransportPlugin *p;
1296 p = find_transport (plugin);
1299 return p->api->address_to_string (p->api->cls,
1306 * Mark the given FAL entry as 'connected' (and hence preferred for
1307 * sending); also mark all others for the same peer as 'not connected'
1308 * (since only one can be preferred).
1310 * @param fal address to set to 'connected'
1313 mark_address_connected (struct ForeignAddressList *fal)
1315 struct ForeignAddressList *pos;
1318 GNUNET_assert (GNUNET_YES == fal->validated);
1319 if (fal->connected == GNUNET_YES)
1320 return; /* nothing to do */
1322 pos = fal->ready_list->addresses;
1325 if (GNUNET_YES == pos->connected)
1328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1329 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1330 a2s (pos->ready_list->plugin->short_name,
1334 GNUNET_break (cnt == GNUNET_YES);
1336 pos->connected = GNUNET_NO;
1337 GNUNET_STATISTICS_update (stats,
1338 gettext_noop ("# connected addresses"),
1344 fal->connected = GNUNET_YES;
1345 if (GNUNET_YES == cnt)
1347 GNUNET_STATISTICS_update (stats,
1348 gettext_noop ("# connected addresses"),
1356 * Send the specified message to the specified client. Since multiple
1357 * messages may be pending for the same client at a time, this code
1358 * makes sure that no message is lost.
1360 * @param client client to transmit the message to
1361 * @param msg the message to send
1362 * @param may_drop can this message be dropped if the
1363 * message queue for this client is getting far too large?
1366 transmit_to_client (struct TransportClient *client,
1367 const struct GNUNET_MessageHeader *msg, int may_drop)
1369 struct ClientMessageQueueEntry *q;
1372 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1374 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1376 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1379 client->message_count,
1381 GNUNET_STATISTICS_update (stats,
1382 gettext_noop ("# messages dropped due to slow client"),
1387 msize = ntohs (msg->size);
1388 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1389 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1390 memcpy (&q[1], msg, msize);
1391 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1392 client->message_queue_tail,
1393 client->message_queue_tail,
1395 client->message_count++;
1396 if (client->th == NULL)
1398 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1400 GNUNET_TIME_UNIT_FOREVER_REL,
1401 &transmit_to_client_callback,
1403 GNUNET_assert (client->th != NULL);
1409 * Transmit a 'SEND_OK' notification to the given client for the
1412 * @param client who to notify
1413 * @param n neighbour to notify about, can be NULL (on failure)
1414 * @param target target of the transmission
1415 * @param result status code for the transmission request
1418 transmit_send_ok (struct TransportClient *client,
1419 struct NeighbourList *n,
1420 const struct GNUNET_PeerIdentity *target,
1423 struct SendOkMessage send_ok_msg;
1425 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1426 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1427 send_ok_msg.success = htonl (result);
1429 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1431 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1432 send_ok_msg.peer = *target;
1433 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1438 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1439 * upon "completion" of a send request. This tells the API
1440 * that it is now legal to send another message to the given
1443 * @param cls closure, identifies the entry on the
1444 * message queue that was transmitted and the
1445 * client responsible for queuing the message
1446 * @param target the peer receiving the message
1447 * @param result GNUNET_OK on success, if the transmission
1448 * failed, we should not tell the client to transmit
1452 transmit_send_continuation (void *cls,
1453 const struct GNUNET_PeerIdentity *target,
1456 struct MessageQueue *mq = cls;
1457 struct NeighbourList *n;
1459 GNUNET_STATISTICS_update (stats,
1460 gettext_noop ("# bytes pending with plugins"),
1461 - (int64_t) mq->message_buf_size,
1463 if (result == GNUNET_OK)
1465 GNUNET_STATISTICS_update (stats,
1466 gettext_noop ("# bytes successfully transmitted by plugins"),
1467 mq->message_buf_size,
1472 GNUNET_STATISTICS_update (stats,
1473 gettext_noop ("# bytes with transmission failure by plugins"),
1474 mq->message_buf_size,
1477 if (mq->specific_address != NULL)
1479 if (result == GNUNET_OK)
1481 mq->specific_address->timeout =
1482 GNUNET_TIME_relative_to_absolute
1483 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1484 if (mq->specific_address->validated == GNUNET_YES)
1485 mark_address_connected (mq->specific_address);
1489 if (mq->specific_address->connected != GNUNET_NO)
1492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1494 a2s (mq->specific_address->ready_list->plugin->short_name,
1495 mq->specific_address->addr,
1496 mq->specific_address->addrlen));
1498 GNUNET_STATISTICS_update (stats,
1499 gettext_noop ("# connected addresses"),
1502 mq->specific_address->connected = GNUNET_NO;
1505 if (! mq->internal_msg)
1506 mq->specific_address->in_transmit = GNUNET_NO;
1508 n = find_neighbour(&mq->neighbour_id);
1509 if (mq->client != NULL)
1510 transmit_send_ok (mq->client, n, target, result);
1513 try_transmission_to_peer (n);
1518 * Find an address in any of the available transports for
1519 * the given neighbour that would be good for message
1520 * transmission. This is essentially the transport selection
1523 * @param neighbour for whom to select an address
1524 * @return selected address, NULL if we have none
1526 struct ForeignAddressList *
1527 find_ready_address(struct NeighbourList *neighbour)
1529 struct ReadyList *head = neighbour->plugins;
1530 struct ForeignAddressList *addresses;
1531 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1532 struct ForeignAddressList *best_address;
1534 /* Hack to prefer unix domain sockets */
1535 struct ForeignAddressList *unix_address = NULL;
1537 best_address = NULL;
1538 while (head != NULL)
1540 addresses = head->addresses;
1541 while (addresses != NULL)
1543 if ( (addresses->timeout.abs_value < now.abs_value) &&
1544 (addresses->connected == GNUNET_YES) )
1547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1548 "Marking long-time inactive connection to `%4s' as down.\n",
1549 GNUNET_i2s (&neighbour->id));
1551 GNUNET_STATISTICS_update (stats,
1552 gettext_noop ("# connected addresses"),
1555 addresses->connected = GNUNET_NO;
1557 addresses = addresses->next;
1560 addresses = head->addresses;
1561 while (addresses != NULL)
1563 #if DEBUG_TRANSPORT > 1
1564 if (addresses->addr != NULL)
1565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1567 a2s (head->plugin->short_name,
1569 addresses->addrlen),
1570 GNUNET_i2s (&neighbour->id),
1571 addresses->connected,
1572 addresses->in_transmit,
1573 addresses->validated,
1574 addresses->connect_attempts,
1575 (unsigned long long) addresses->timeout.abs_value,
1576 (unsigned int) addresses->distance);
1578 if (0==strcmp(head->plugin->short_name,"unix"))
1580 if ((unix_address == NULL) || ((unix_address != NULL) &&
1581 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1582 unix_address = addresses;
1584 if ( ( (best_address == NULL) ||
1585 (addresses->connected == GNUNET_YES) ||
1586 (best_address->connected == GNUNET_NO) ) &&
1587 (addresses->in_transmit == GNUNET_NO) &&
1588 ( (best_address == NULL) ||
1589 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1590 best_address = addresses;
1591 /* FIXME: also give lower-latency addresses that are not
1592 connected a chance some times... */
1593 addresses = addresses->next;
1595 if (unix_address != NULL)
1599 if (unix_address != NULL)
1601 best_address = unix_address;
1603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1606 if (best_address != NULL)
1610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1611 "Best address found (`%s') has latency of %llu ms.\n",
1612 (best_address->addrlen > 0)
1613 ? a2s (best_address->ready_list->plugin->short_name,
1615 best_address->addrlen)
1617 best_address->latency.rel_value);
1622 GNUNET_STATISTICS_update (stats,
1623 gettext_noop ("# transmission attempts failed (no address)"),
1628 return best_address;
1634 * We should re-try transmitting to the given peer,
1635 * hopefully we've learned something in the meantime.
1638 retry_transmission_task (void *cls,
1639 const struct GNUNET_SCHEDULER_TaskContext *tc)
1641 struct NeighbourList *n = cls;
1643 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1644 try_transmission_to_peer (n);
1649 * Check the ready list for the given neighbour and if a plugin is
1650 * ready for transmission (and if we have a message), do so!
1652 * @param neighbour target peer for which to transmit
1655 try_transmission_to_peer (struct NeighbourList *n)
1657 struct ReadyList *rl;
1658 struct MessageQueue *mq;
1659 struct GNUNET_TIME_Relative timeout;
1663 if (n->messages_head == NULL)
1666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1667 "Transmission queue for `%4s' is empty\n",
1668 GNUNET_i2s (&neighbour->id));
1670 return; /* nothing to do */
1673 mq = n->messages_head;
1674 force_address = GNUNET_YES;
1675 if (mq->specific_address == NULL)
1678 mq->specific_address = ats_get_preferred_address(n);
1679 GNUNET_STATISTICS_update (stats,
1680 gettext_noop ("# transport selected peer address freely"),
1683 force_address = GNUNET_NO;
1685 if (mq->specific_address == NULL)
1687 GNUNET_STATISTICS_update (stats,
1688 gettext_noop ("# transport failed to selected peer address"),
1691 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1692 if (timeout.rel_value == 0)
1695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1696 "No destination address available to transmit message of size %u to peer `%4s'\n",
1697 mq->message_buf_size,
1698 GNUNET_i2s (&mq->neighbour_id));
1700 GNUNET_STATISTICS_update (stats,
1701 gettext_noop ("# bytes in message queue for other peers"),
1702 - (int64_t) mq->message_buf_size,
1704 GNUNET_STATISTICS_update (stats,
1705 gettext_noop ("# bytes discarded (no destination address available)"),
1706 mq->message_buf_size,
1708 if (mq->client != NULL)
1709 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1710 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1714 return; /* nobody ready */
1716 GNUNET_STATISTICS_update (stats,
1717 gettext_noop ("# message delivery deferred (no address)"),
1720 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1721 GNUNET_SCHEDULER_cancel (n->retry_task);
1722 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1723 &retry_transmission_task,
1726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1727 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1728 mq->message_buf_size,
1729 GNUNET_i2s (&mq->neighbour_id),
1732 /* FIXME: might want to trigger peerinfo lookup here
1733 (unless that's already pending...) */
1736 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1739 if (mq->specific_address->connected == GNUNET_NO)
1740 mq->specific_address->connect_attempts++;
1741 rl = mq->specific_address->ready_list;
1742 mq->plugin = rl->plugin;
1743 if (!mq->internal_msg)
1744 mq->specific_address->in_transmit = GNUNET_YES;
1746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1747 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1748 mq->message_buf_size,
1749 GNUNET_i2s (&neighbour->id),
1750 (mq->specific_address->addr != NULL)
1751 ? a2s (mq->plugin->short_name,
1752 mq->specific_address->addr,
1753 mq->specific_address->addrlen)
1755 rl->plugin->short_name);
1757 GNUNET_STATISTICS_update (stats,
1758 gettext_noop ("# bytes in message queue for other peers"),
1759 - (int64_t) mq->message_buf_size,
1761 GNUNET_STATISTICS_update (stats,
1762 gettext_noop ("# bytes pending with plugins"),
1763 mq->message_buf_size,
1765 ret = rl->plugin->api->send (rl->plugin->api->cls,
1768 mq->message_buf_size,
1770 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1771 mq->specific_address->session,
1772 mq->specific_address->addr,
1773 mq->specific_address->addrlen,
1775 &transmit_send_continuation, mq);
1778 /* failure, but 'send' would not call continuation in this case,
1779 so we need to do it here! */
1780 transmit_send_continuation (mq,
1788 * Send the specified message to the specified peer.
1790 * @param client source of the transmission request (can be NULL)
1791 * @param peer_address ForeignAddressList where we should send this message
1792 * @param priority how important is the message
1793 * @param timeout how long do we have to transmit?
1794 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1795 * @param message_buf_size total size of all messages in message_buf
1796 * @param is_internal is this an internal message; these are pre-pended and
1797 * also do not count for plugins being "ready" to transmit
1798 * @param neighbour handle to the neighbour for transmission
1801 transmit_to_peer (struct TransportClient *client,
1802 struct ForeignAddressList *peer_address,
1803 unsigned int priority,
1804 struct GNUNET_TIME_Relative timeout,
1805 const char *message_buf,
1806 size_t message_buf_size,
1807 int is_internal, struct NeighbourList *neighbour)
1809 struct MessageQueue *mq;
1814 /* check for duplicate submission */
1815 mq = neighbour->messages_head;
1818 if (mq->client == client)
1820 /* client transmitted to same peer twice
1821 before getting SEND_OK! */
1829 GNUNET_STATISTICS_update (stats,
1830 gettext_noop ("# bytes in message queue for other peers"),
1833 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1834 mq->specific_address = peer_address;
1835 mq->client = client;
1836 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1837 memcpy (&mq[1], message_buf, message_buf_size);
1838 mq->message_buf = (const char*) &mq[1];
1839 mq->message_buf_size = message_buf_size;
1840 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1841 mq->internal_msg = is_internal;
1842 mq->priority = priority;
1843 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1845 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1846 neighbour->messages_tail,
1849 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1850 neighbour->messages_tail,
1851 neighbour->messages_tail,
1853 try_transmission_to_peer (neighbour);
1860 struct GeneratorContext
1862 struct TransportPlugin *plug_pos;
1863 struct OwnAddressList *addr_pos;
1864 struct GNUNET_TIME_Absolute expiration;
1872 address_generator (void *cls, size_t max, void *buf)
1874 struct GeneratorContext *gc = cls;
1877 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1879 gc->plug_pos = gc->plug_pos->next;
1880 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1882 if (NULL == gc->plug_pos)
1887 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1890 gc->addr_pos->addrlen, buf, max);
1891 gc->addr_pos = gc->addr_pos->next;
1897 * Construct our HELLO message from all of the addresses of
1898 * all of the transports.
1903 struct GNUNET_HELLO_Message *hello;
1904 struct TransportClient *cpos;
1905 struct NeighbourList *npos;
1906 struct GeneratorContext gc;
1908 gc.plug_pos = plugins;
1909 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1910 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1911 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1914 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1916 GNUNET_STATISTICS_update (stats,
1917 gettext_noop ("# refreshed my HELLO"),
1921 while (cpos != NULL)
1923 transmit_to_client (cpos,
1924 (const struct GNUNET_MessageHeader *) hello,
1929 GNUNET_free_non_null (our_hello);
1931 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1933 while (npos != NULL)
1936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1937 "Transmitting updated `%s' to neighbour `%4s'\n",
1938 "HELLO", GNUNET_i2s (&npos->id));
1940 GNUNET_STATISTICS_update (stats,
1941 gettext_noop ("# transmitted my HELLO to other peers"),
1944 transmit_to_peer (NULL, NULL, 0,
1945 HELLO_ADDRESS_EXPIRATION,
1946 (const char *) our_hello,
1947 GNUNET_HELLO_size(our_hello),
1955 * Task used to clean up expired addresses for a plugin.
1957 * @param cls closure
1961 expire_address_task (void *cls,
1962 const struct GNUNET_SCHEDULER_TaskContext *tc);
1966 * Update the list of addresses for this plugin,
1967 * expiring those that are past their expiration date.
1969 * @param plugin addresses of which plugin should be recomputed?
1970 * @param fresh set to GNUNET_YES if a new address was added
1971 * and we need to regenerate the HELLO even if nobody
1975 update_addresses (struct TransportPlugin *plugin,
1978 static struct GNUNET_TIME_Absolute last_update;
1979 struct GNUNET_TIME_Relative min_remaining;
1980 struct GNUNET_TIME_Relative remaining;
1981 struct GNUNET_TIME_Absolute now;
1982 struct OwnAddressList *pos;
1983 struct OwnAddressList *prev;
1984 struct OwnAddressList *next;
1987 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1988 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1989 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1990 now = GNUNET_TIME_absolute_get ();
1991 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1992 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
1994 pos = plugin->addresses;
1998 if (pos->expires.abs_value < now.abs_value)
2000 expired = GNUNET_YES;
2002 plugin->addresses = pos->next;
2004 prev->next = pos->next;
2009 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2010 if (remaining.rel_value < min_remaining.rel_value)
2011 min_remaining = remaining;
2017 if (expired || fresh)
2022 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2023 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2025 plugin->address_update_task
2026 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2027 &expire_address_task, plugin);
2032 * Task used to clean up expired addresses for a plugin.
2034 * @param cls closure
2038 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2040 struct TransportPlugin *plugin = cls;
2042 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2043 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2044 update_addresses (plugin, GNUNET_NO);
2049 * Iterator over hash map entries that NULLs the session of validation
2050 * entries that match the given session.
2052 * @param cls closure (the 'struct Session*' to match against)
2053 * @param key current key code (peer ID, not used)
2054 * @param value value in the hash map ('struct ValidationEntry*')
2055 * @return GNUNET_YES (we should continue to iterate)
2058 remove_session_validations (void *cls,
2059 const GNUNET_HashCode * key,
2062 struct Session *session = cls;
2063 struct ValidationEntry *ve = value;
2065 if (session == ve->session)
2072 * We've been disconnected from the other peer (for some
2073 * connection-oriented transport). Either quickly
2074 * re-establish the connection or signal the disconnect
2077 * Only signal CORE level disconnect if ALL addresses
2078 * for the peer are exhausted.
2080 * @param p overall plugin context
2081 * @param nl neighbour that was disconnected
2084 try_fast_reconnect (struct TransportPlugin *p,
2085 struct NeighbourList *nl)
2087 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2088 /* Note: the idea here is to hide problems with transports (or
2089 switching between plugins) from the core to eliminate the need to
2090 re-negotiate session keys and the like; OTOH, we should tell core
2091 quickly (much faster than timeout) `if a connection was lost and
2092 could not be re-established (i.e. other peer went down or is
2093 unable / refuses to communicate);
2095 So we should consider:
2096 1) ideally: our own willingness / need to connect
2097 2) prior failures to connect to this peer (by plugin)
2098 3) ideally: reasons why other peer terminated (as far as knowable)
2100 Most importantly, it must be POSSIBLE for another peer to terminate
2101 a connection for a while (without us instantly re-establishing it).
2102 Similarly, if another peer is gone we should quickly notify CORE.
2103 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2104 on the other end), we should reconnect in such a way that BOTH CORE
2105 services never even notice.
2106 Furthermore, the same mechanism (or small variation) could be used
2107 to switch to a better-performing plugin (ATS).
2109 Finally, this needs to be tested throughly... */
2112 * GNUNET_NO in the call below makes transport disconnect the peer,
2113 * even if only a single address (out of say, six) went away. This
2114 * function must be careful to ONLY disconnect if the peer is gone,
2115 * not just a specifi address.
2117 * More specifically, half the places it was used had it WRONG.
2120 /* No reconnect, signal disconnect instead! */
2121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2122 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2123 "try_fast_reconnect");
2124 disconnect_neighbour (nl, GNUNET_YES);
2129 * Function that will be called whenever the plugin internally
2130 * cleans up a session pointer and hence the service needs to
2131 * discard all of those sessions as well. Plugins that do not
2132 * use sessions can simply omit calling this function and always
2133 * use NULL wherever a session pointer is needed.
2135 * @param cls closure
2136 * @param peer which peer was the session for
2137 * @param session which session is being destoyed
2140 plugin_env_session_end (void *cls,
2141 const struct GNUNET_PeerIdentity *peer,
2142 struct Session *session)
2144 struct TransportPlugin *p = cls;
2145 struct NeighbourList *nl;
2146 struct ReadyList *rl;
2147 struct ForeignAddressList *pos;
2148 struct ForeignAddressList *prev;
2150 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2151 &remove_session_validations,
2153 nl = find_neighbour (peer);
2155 return; /* was never marked as connected */
2159 if (rl->plugin == p)
2164 return; /* was never marked as connected */
2166 pos = rl->addresses;
2167 while ( (pos != NULL) &&
2168 (pos->session != session) )
2174 return; /* was never marked as connected */
2175 pos->session = NULL;
2176 if (pos->addrlen != 0)
2178 if (nl->received_pong != GNUNET_NO)
2179 try_fast_reconnect (p, nl);
2182 /* was inbound connection, free 'pos' */
2184 rl->addresses = pos->next;
2186 prev->next = pos->next;
2187 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2189 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2190 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2193 if (nl->received_pong == GNUNET_NO)
2194 return; /* nothing to do, never connected... */
2195 /* check if we have any validated addresses left */
2196 pos = rl->addresses;
2201 try_fast_reconnect (p, nl);
2206 /* no valid addresses left, signal disconnect! */
2208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2209 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2210 "plugin_env_session_end");
2211 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2212 * it means there aren't any left for this PLUGIN/PEER combination! So
2213 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2214 * when it isn't necessary. Using GNUNET_YES at least checks to see
2215 * if there are any addresses that work first, so as not to overdo it.
2218 disconnect_neighbour (nl, GNUNET_YES);
2223 * Function that must be called by each plugin to notify the
2224 * transport service about the addresses under which the transport
2225 * provided by the plugin can be reached.
2227 * @param cls closure
2228 * @param name name of the transport that generated the address
2229 * @param addr one of the addresses of the host, NULL for the last address
2230 * the specific address format depends on the transport
2231 * @param addrlen length of the address
2232 * @param expires when should this address automatically expire?
2235 plugin_env_notify_address (void *cls,
2239 struct GNUNET_TIME_Relative expires)
2241 struct TransportPlugin *p = cls;
2242 struct OwnAddressList *al;
2243 struct GNUNET_TIME_Absolute abex;
2245 GNUNET_assert (addr != NULL);
2246 abex = GNUNET_TIME_relative_to_absolute (expires);
2247 GNUNET_assert (p == find_transport (name));
2251 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2254 update_addresses (p, GNUNET_NO);
2260 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2261 al->next = p->addresses;
2264 al->addrlen = addrlen;
2265 memcpy (&al[1], addr, addrlen);
2266 update_addresses (p, GNUNET_YES);
2271 * Notify all of our clients about a peer connecting.
2274 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2275 struct GNUNET_TIME_Relative latency,
2278 struct ConnectInfoMessage * cim;
2279 struct TransportClient *cpos;
2284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2285 "Notifying clients about connection from `%s'\n",
2288 GNUNET_STATISTICS_update (stats,
2289 gettext_noop ("# peers connected"),
2294 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2295 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2299 cim = GNUNET_malloc (size);
2301 cim->header.size = htons (size);
2302 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2303 cim->ats_count = htonl(2);
2304 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2305 (&(cim->ats))[0].value = htonl (distance);
2306 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2307 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2308 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2309 (&(cim->ats))[2].value = htonl (0);
2310 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2312 /* notify ats about connecting peer */
2313 ats_notify_peer_connect (peer, &(cim->ats));
2316 while (cpos != NULL)
2318 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2327 * Notify all of our clients about a peer disconnecting.
2330 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2332 struct DisconnectInfoMessage dim;
2333 struct TransportClient *cpos;
2336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2337 "Notifying clients about lost connection to `%s'\n",
2340 GNUNET_STATISTICS_update (stats,
2341 gettext_noop ("# peers connected"),
2344 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2345 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2346 dim.reserved = htonl (0);
2347 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2349 /* notify ats about connecting peer */
2350 ats_notify_peer_disconnect (peer);
2353 while (cpos != NULL)
2355 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2362 * Find a ForeignAddressList entry for the given neighbour
2363 * that matches the given address and transport.
2365 * @param neighbour which peer we care about
2366 * @param tname name of the transport plugin
2367 * @param session session to look for, NULL for 'any'; otherwise
2368 * can be used for the service to "learn" this session ID
2370 * @param addr binary address
2371 * @param addrlen length of addr
2372 * @return NULL if no such entry exists
2374 static struct ForeignAddressList *
2375 find_peer_address(struct NeighbourList *neighbour,
2377 struct Session *session,
2381 struct ReadyList *head;
2382 struct ForeignAddressList *pos;
2384 head = neighbour->plugins;
2385 while (head != NULL)
2387 if (0 == strcmp (tname, head->plugin->short_name))
2393 pos = head->addresses;
2394 while ( (pos != NULL) &&
2395 ( (pos->addrlen != addrlen) ||
2396 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2398 if ( (session != NULL) &&
2399 (pos->session == session) )
2403 if ( (session != NULL) && (pos != NULL) )
2404 pos->session = session; /* learn it! */
2410 * Get the peer address struct for the given neighbour and
2411 * address. If it doesn't yet exist, create it.
2413 * @param neighbour which peer we care about
2414 * @param tname name of the transport plugin
2415 * @param session session of the plugin, or NULL for none
2416 * @param addr binary address
2417 * @param addrlen length of addr
2418 * @return NULL if we do not have a transport plugin for 'tname'
2420 static struct ForeignAddressList *
2421 add_peer_address (struct NeighbourList *neighbour,
2423 struct Session *session,
2427 struct ReadyList *head;
2428 struct ForeignAddressList *ret;
2430 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2433 head = neighbour->plugins;
2435 while (head != NULL)
2437 if (0 == strcmp (tname, head->plugin->short_name))
2443 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2444 ret->session = session;
2447 ret->addr = (const char*) &ret[1];
2448 memcpy (&ret[1], addr, addrlen);
2454 ret->addrlen = addrlen;
2455 ret->expires = GNUNET_TIME_relative_to_absolute
2456 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2457 ret->latency = GNUNET_TIME_relative_get_forever();
2459 ret->timeout = GNUNET_TIME_relative_to_absolute
2460 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2461 ret->ready_list = head;
2462 ret->next = head->addresses;
2463 head->addresses = ret;
2469 * Closure for 'add_validated_address'.
2471 struct AddValidatedAddressContext
2474 * Entry that has been validated.
2476 const struct ValidationEntry *ve;
2479 * Flag set after we have added the address so
2480 * that we terminate the iteration next time.
2487 * Callback function used to fill a buffer of max bytes with a list of
2488 * addresses in the format used by HELLOs. Should use
2489 * "GNUNET_HELLO_add_address" as a helper function.
2491 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2492 * @param max maximum number of bytes that can be written to buf
2493 * @param buf where to write the address information
2494 * @return number of bytes written, 0 to signal the
2495 * end of the iteration.
2498 add_validated_address (void *cls,
2499 size_t max, void *buf)
2501 struct AddValidatedAddressContext *avac = cls;
2502 const struct ValidationEntry *ve = avac->ve;
2504 if (GNUNET_YES == avac->done)
2506 avac->done = GNUNET_YES;
2507 return GNUNET_HELLO_add_address (ve->transport_name,
2508 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2518 * Closure for 'check_address_exists'.
2520 struct CheckAddressExistsClosure
2523 * Address to check for.
2528 * Name of the transport.
2535 struct Session *session;
2538 * Set to GNUNET_YES if the address exists.
2551 * Iterator over hash map entries. Checks if the given
2552 * validation entry is for the same address as what is given
2555 * @param cls the 'struct CheckAddressExistsClosure*'
2556 * @param key current key code (ignored)
2557 * @param value value in the hash map ('struct ValidationEntry')
2558 * @return GNUNET_YES if we should continue to
2559 * iterate (mismatch), GNUNET_NO if not (entry matched)
2562 check_address_exists (void *cls,
2563 const GNUNET_HashCode * key,
2566 struct CheckAddressExistsClosure *caec = cls;
2567 struct ValidationEntry *ve = value;
2569 if ( (0 == strcmp (caec->tname,
2570 ve->transport_name)) &&
2571 (caec->addrlen == ve->addrlen) &&
2572 (0 == memcmp (caec->addr,
2576 caec->exists = GNUNET_YES;
2579 if ( (ve->session != NULL) &&
2580 (caec->session == ve->session) )
2582 caec->exists = GNUNET_YES;
2591 * Iterator to free entries in the validation_map.
2593 * @param cls closure (unused)
2594 * @param key current key code
2595 * @param value value in the hash map (validation to abort)
2596 * @return GNUNET_YES (always)
2599 abort_validation (void *cls,
2600 const GNUNET_HashCode * key,
2603 struct ValidationEntry *va = value;
2605 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2606 GNUNET_SCHEDULER_cancel (va->timeout_task);
2607 GNUNET_free (va->transport_name);
2608 if (va->chvc != NULL)
2610 va->chvc->ve_count--;
2611 if (va->chvc->ve_count == 0)
2613 GNUNET_CONTAINER_DLL_remove (chvc_head,
2616 GNUNET_free (va->chvc);
2626 * HELLO validation cleanup task (validation failed).
2628 * @param cls the 'struct ValidationEntry' that failed
2629 * @param tc scheduler context (unused)
2632 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2634 struct ValidationEntry *va = cls;
2635 struct GNUNET_PeerIdentity pid;
2637 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2638 GNUNET_STATISTICS_update (stats,
2639 gettext_noop ("# address validation timeouts"),
2642 GNUNET_CRYPTO_hash (&va->publicKey,
2644 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2646 GNUNET_break (GNUNET_OK ==
2647 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2650 abort_validation (NULL, NULL, va);
2655 neighbour_timeout_task (void *cls,
2656 const struct GNUNET_SCHEDULER_TaskContext *tc)
2658 struct NeighbourList *n = cls;
2661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2662 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2664 GNUNET_STATISTICS_update (stats,
2665 gettext_noop ("# disconnects due to timeout"),
2668 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2669 disconnect_neighbour (n, GNUNET_NO);
2674 * Schedule the job that will cause us to send a PING to the
2675 * foreign address to evaluate its validity and latency.
2677 * @param fal address to PING
2680 schedule_next_ping (struct ForeignAddressList *fal);
2684 * Add the given address to the list of foreign addresses
2685 * available for the given peer (check for duplicates).
2687 * @param cls the respective 'struct NeighbourList' to update
2688 * @param tname name of the transport
2689 * @param expiration expiration time
2690 * @param addr the address
2691 * @param addrlen length of the address
2692 * @return GNUNET_OK (always)
2695 add_to_foreign_address_list (void *cls,
2697 struct GNUNET_TIME_Absolute expiration,
2701 struct NeighbourList *n = cls;
2702 struct ForeignAddressList *fal;
2705 GNUNET_STATISTICS_update (stats,
2706 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2710 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2713 #if DEBUG_TRANSPORT_HELLO
2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2716 a2s (tname, addr, addrlen),
2718 GNUNET_i2s (&n->id),
2719 expiration.abs_value);
2721 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2724 GNUNET_STATISTICS_update (stats,
2725 gettext_noop ("# previously validated addresses lacking transport"),
2731 fal->expires = GNUNET_TIME_absolute_max (expiration,
2733 schedule_next_ping (fal);
2739 fal->expires = GNUNET_TIME_absolute_max (expiration,
2744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2745 "Failed to add new address for `%4s'\n",
2746 GNUNET_i2s (&n->id));
2749 if (fal->validated == GNUNET_NO)
2751 fal->validated = GNUNET_YES;
2752 GNUNET_STATISTICS_update (stats,
2753 gettext_noop ("# peer addresses considered valid"),
2757 if (try == GNUNET_YES)
2759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2760 "Have new addresses, will try to trigger transmissions.\n");
2761 try_transmission_to_peer (n);
2768 * Add addresses in validated HELLO "h" to the set of addresses
2769 * we have for this peer.
2771 * @param cls closure ('struct NeighbourList*')
2772 * @param peer id of the peer, NULL for last call
2773 * @param h hello message for the peer (can be NULL)
2774 * @param err_msg NULL if successful, otherwise contains error message
2777 add_hello_for_peer (void *cls,
2778 const struct GNUNET_PeerIdentity *peer,
2779 const struct GNUNET_HELLO_Message *h,
2780 const char *err_msg)
2782 struct NeighbourList *n = cls;
2784 if (err_msg != NULL)
2786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2787 _("Error in communication with PEERINFO service\n"));
2792 GNUNET_STATISTICS_update (stats,
2793 gettext_noop ("# outstanding peerinfo iterate requests"),
2800 return; /* no HELLO available */
2802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2803 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2807 if (GNUNET_YES != n->public_key_valid)
2809 GNUNET_HELLO_get_key (h, &n->publicKey);
2810 n->public_key_valid = GNUNET_YES;
2812 GNUNET_HELLO_iterate_addresses (h,
2814 &add_to_foreign_address_list,
2820 * Create a fresh entry in our neighbour list for the given peer.
2821 * Will try to transmit our current HELLO to the new neighbour.
2822 * Do not call this function directly, use 'setup_peer_check_blacklist.
2824 * @param peer the peer for which we create the entry
2825 * @param do_hello should we schedule transmitting a HELLO
2826 * @return the new neighbour list entry
2828 static struct NeighbourList *
2829 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2832 struct NeighbourList *n;
2833 struct TransportPlugin *tp;
2834 struct ReadyList *rl;
2837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2838 "Setting up state for neighbour `%4s'\n",
2841 GNUNET_assert (our_hello != NULL);
2842 GNUNET_STATISTICS_update (stats,
2843 gettext_noop ("# active neighbours"),
2846 n = GNUNET_malloc (sizeof (struct NeighbourList));
2847 n->next = neighbours;
2851 GNUNET_TIME_relative_to_absolute
2852 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2853 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2854 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2855 MAX_BANDWIDTH_CARRY_S);
2859 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2861 rl = GNUNET_malloc (sizeof (struct ReadyList));
2863 rl->next = n->plugins;
2866 rl->addresses = NULL;
2870 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2872 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2873 &neighbour_timeout_task, n);
2876 GNUNET_STATISTICS_update (stats,
2877 gettext_noop ("# peerinfo new neighbor iterate requests"),
2880 GNUNET_STATISTICS_update (stats,
2881 gettext_noop ("# outstanding peerinfo iterate requests"),
2884 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2885 GNUNET_TIME_UNIT_FOREVER_REL,
2886 &add_hello_for_peer, n);
2888 GNUNET_STATISTICS_update (stats,
2889 gettext_noop ("# HELLO's sent to new neighbors"),
2892 transmit_to_peer (NULL, NULL, 0,
2893 HELLO_ADDRESS_EXPIRATION,
2894 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2902 * Function called after we have checked if communicating
2903 * with a given peer is acceptable.
2905 * @param cls closure
2906 * @param n NULL if communication is not acceptable
2908 typedef void (*SetupContinuation)(void *cls,
2909 struct NeighbourList *n);
2913 * Information kept for each client registered to perform
2919 * This is a linked list.
2921 struct Blacklisters *next;
2924 * This is a linked list.
2926 struct Blacklisters *prev;
2929 * Client responsible for this entry.
2931 struct GNUNET_SERVER_Client *client;
2934 * Blacklist check that we're currently performing.
2936 struct BlacklistCheck *bc;
2942 * Head of DLL of blacklisting clients.
2944 static struct Blacklisters *bl_head;
2947 * Tail of DLL of blacklisting clients.
2949 static struct Blacklisters *bl_tail;
2953 * Context we use when performing a blacklist check.
2955 struct BlacklistCheck
2959 * This is a linked list.
2961 struct BlacklistCheck *next;
2964 * This is a linked list.
2966 struct BlacklistCheck *prev;
2969 * Peer being checked.
2971 struct GNUNET_PeerIdentity peer;
2974 * Option for setup neighbour afterwards.
2979 * Continuation to call with the result.
2981 SetupContinuation cont;
2989 * Current transmission request handle for this client, or NULL if no
2990 * request is pending.
2992 struct GNUNET_CONNECTION_TransmitHandle *th;
2995 * Our current position in the blacklisters list.
2997 struct Blacklisters *bl_pos;
3000 * Current task performing the check.
3002 GNUNET_SCHEDULER_TaskIdentifier task;
3007 * Head of DLL of active blacklisting queries.
3009 static struct BlacklistCheck *bc_head;
3012 * Tail of DLL of active blacklisting queries.
3014 static struct BlacklistCheck *bc_tail;
3018 * Perform next action in the blacklist check.
3020 * @param cls the 'struct BlacklistCheck*'
3024 do_blacklist_check (void *cls,
3025 const struct GNUNET_SCHEDULER_TaskContext *tc);
3028 * Transmit blacklist query to the client.
3030 * @param cls the 'struct BlacklistCheck'
3031 * @param size number of bytes allowed
3032 * @param buf where to copy the message
3033 * @return number of bytes copied to buf
3036 transmit_blacklist_message (void *cls,
3040 struct BlacklistCheck *bc = cls;
3041 struct Blacklisters *bl;
3042 struct BlacklistMessage bm;
3047 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3048 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3053 bm.header.size = htons (sizeof (struct BlacklistMessage));
3054 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3055 bm.is_allowed = htonl (0);
3057 memcpy (buf, &bm, sizeof (bm));
3058 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3064 * Perform next action in the blacklist check.
3066 * @param cls the 'struct BlacklistCheck*'
3070 do_blacklist_check (void *cls,
3071 const struct GNUNET_SCHEDULER_TaskContext *tc)
3073 struct BlacklistCheck *bc = cls;
3074 struct Blacklisters *bl;
3076 bc->task = GNUNET_SCHEDULER_NO_TASK;
3080 bc->cont (bc->cont_cls,
3081 setup_new_neighbour (&bc->peer, bc->do_hello));
3088 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3089 sizeof (struct BlacklistMessage),
3090 GNUNET_TIME_UNIT_FOREVER_REL,
3091 &transmit_blacklist_message,
3098 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3099 * does not yet exist, check the blacklist. If the blacklist says creating
3100 * one is acceptable, create one and call the continuation; otherwise
3101 * call the continuation with NULL.
3103 * @param peer peer to setup or look up a struct NeighbourList for
3104 * @param do_hello should we also schedule sending our HELLO to the peer
3105 * if this is a new record
3106 * @param cont function to call with the 'struct NeigbhbourList*'
3107 * @param cont_cls closure for cont
3110 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3112 SetupContinuation cont,
3115 struct NeighbourList *n;
3116 struct BlacklistCheck *bc;
3118 n = find_neighbour(peer);
3125 if (bl_head == NULL)
3128 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3130 setup_new_neighbour(peer, do_hello);
3133 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3134 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3136 bc->do_hello = do_hello;
3138 bc->cont_cls = cont_cls;
3139 bc->bl_pos = bl_head;
3140 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3146 * Function called with the result of querying a new blacklister about
3147 * it being allowed (or not) to continue to talk to an existing neighbour.
3149 * @param cls the original 'struct NeighbourList'
3150 * @param n NULL if we need to disconnect
3153 confirm_or_drop_neighbour (void *cls,
3154 struct NeighbourList *n)
3156 struct NeighbourList * orig = cls;
3160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3161 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3162 "confirm_or_drop_neighboUr");
3163 disconnect_neighbour (orig, GNUNET_NO);
3169 * Handle a request to start a blacklist.
3171 * @param cls closure (always NULL)
3172 * @param client identification of the client
3173 * @param message the actual message
3176 handle_blacklist_init (void *cls,
3177 struct GNUNET_SERVER_Client *client,
3178 const struct GNUNET_MessageHeader *message)
3180 struct Blacklisters *bl;
3181 struct BlacklistCheck *bc;
3182 struct NeighbourList *n;
3187 if (bl->client == client)
3190 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3195 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3196 bl->client = client;
3197 GNUNET_SERVER_client_keep (client);
3198 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3199 /* confirm that all existing connections are OK! */
3203 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3204 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3206 bc->do_hello = GNUNET_NO;
3207 bc->cont = &confirm_or_drop_neighbour;
3210 if (n == neighbours) /* all would wait for the same client, no need to
3211 create more than just the first task right now */
3212 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3220 * Handle a request to blacklist a peer.
3222 * @param cls closure (always NULL)
3223 * @param client identification of the client
3224 * @param message the actual message
3227 handle_blacklist_reply (void *cls,
3228 struct GNUNET_SERVER_Client *client,
3229 const struct GNUNET_MessageHeader *message)
3231 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3232 struct Blacklisters *bl;
3233 struct BlacklistCheck *bc;
3236 while ( (bl != NULL) &&
3237 (bl->client != client) )
3241 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3246 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3248 bc->cont (bc->cont_cls, NULL);
3249 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3254 bc->bl_pos = bc->bl_pos->next;
3255 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3258 /* check if any other bc's are waiting for this blacklister */
3262 if ( (bc->bl_pos == bl) &&
3263 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3264 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3272 * Send periodic PING messages to a given foreign address.
3274 * @param cls our 'struct PeriodicValidationContext*'
3275 * @param tc task context
3278 send_periodic_ping (void *cls,
3279 const struct GNUNET_SCHEDULER_TaskContext *tc)
3281 struct ForeignAddressList *peer_address = cls;
3282 struct TransportPlugin *tp;
3283 struct ValidationEntry *va;
3284 struct NeighbourList *neighbour;
3285 struct TransportPingMessage ping;
3286 struct CheckAddressExistsClosure caec;
3288 uint16_t hello_size;
3292 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3293 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3295 tp = peer_address->ready_list->plugin;
3296 neighbour = peer_address->ready_list->neighbour;
3297 if (GNUNET_YES != neighbour->public_key_valid)
3299 /* no public key yet, try again later */
3300 schedule_next_ping (peer_address);
3303 caec.addr = peer_address->addr;
3304 caec.addrlen = peer_address->addrlen;
3305 caec.tname = tp->short_name;
3306 caec.session = peer_address->session;
3307 caec.exists = GNUNET_NO;
3308 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3309 &check_address_exists,
3311 if (caec.exists == GNUNET_YES)
3313 /* During validation attempts we will likely trigger the other
3314 peer trying to validate our address which in turn will cause
3315 it to send us its HELLO, so we expect to hit this case rather
3316 frequently. Only print something if we are very verbose. */
3317 #if DEBUG_TRANSPORT > 1
3318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3319 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3320 (peer_address->addr != NULL)
3321 ? a2s (tp->short_name,
3323 peer_address->addrlen)
3326 GNUNET_i2s (&neighbour->id));
3328 schedule_next_ping (peer_address);
3331 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3332 va->transport_name = GNUNET_strdup (tp->short_name);
3333 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3335 va->send_time = GNUNET_TIME_absolute_get();
3336 va->session = peer_address->session;
3337 if (peer_address->addr != NULL)
3339 va->addr = (const void*) &va[1];
3340 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3341 va->addrlen = peer_address->addrlen;
3343 memcpy(&va->publicKey,
3344 &neighbour->publicKey,
3345 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3347 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3348 &timeout_hello_validation,
3350 GNUNET_CONTAINER_multihashmap_put (validation_map,
3351 &neighbour->id.hashPubKey,
3353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3355 if (peer_address->validated != GNUNET_YES)
3356 hello_size = GNUNET_HELLO_size(our_hello);
3360 tsize = sizeof(struct TransportPingMessage) + hello_size;
3362 if (peer_address->addr != NULL)
3364 slen = strlen (tp->short_name) + 1;
3365 tsize += slen + peer_address->addrlen;
3369 slen = 0; /* make gcc happy */
3371 message_buf = GNUNET_malloc(tsize);
3372 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3373 ping.challenge = htonl(va->challenge);
3374 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3375 if (peer_address->validated != GNUNET_YES)
3377 memcpy(message_buf, our_hello, hello_size);
3380 if (peer_address->addr != NULL)
3382 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3383 peer_address->addrlen +
3385 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3388 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3390 peer_address->addrlen);
3394 ping.header.size = htons(sizeof(struct TransportPingMessage));
3397 memcpy(&message_buf[hello_size],
3399 sizeof(struct TransportPingMessage));
3401 #if DEBUG_TRANSPORT_REVALIDATION
3402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3403 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3404 (peer_address->addr != NULL)
3405 ? a2s (peer_address->plugin->short_name,
3407 peer_address->addrlen)
3410 GNUNET_i2s (&neighbour->id),
3411 "HELLO", hello_size,
3414 if (peer_address->validated != GNUNET_YES)
3415 GNUNET_STATISTICS_update (stats,
3416 gettext_noop ("# PING with HELLO messages sent"),
3420 GNUNET_STATISTICS_update (stats,
3421 gettext_noop ("# PING without HELLO messages sent"),
3424 GNUNET_STATISTICS_update (stats,
3425 gettext_noop ("# PING messages sent for re-validation"),
3428 transmit_to_peer (NULL, peer_address,
3429 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3430 HELLO_VERIFICATION_TIMEOUT,
3432 GNUNET_YES, neighbour);
3433 GNUNET_free(message_buf);
3434 schedule_next_ping (peer_address);
3439 * Schedule the job that will cause us to send a PING to the
3440 * foreign address to evaluate its validity and latency.
3442 * @param fal address to PING
3445 schedule_next_ping (struct ForeignAddressList *fal)
3447 struct GNUNET_TIME_Relative delay;
3449 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3451 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3452 delay.rel_value /= 2; /* do before expiration */
3453 delay = GNUNET_TIME_relative_min (delay,
3454 LATENCY_EVALUATION_MAX_DELAY);
3455 if (GNUNET_YES != fal->estimated)
3457 delay = GNUNET_TIME_UNIT_ZERO;
3458 fal->estimated = GNUNET_YES;
3460 if (GNUNET_YES == fal->connected)
3462 delay = GNUNET_TIME_relative_min (delay,
3463 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3465 /* FIXME: also adjust delay based on how close the last
3466 observed latency is to the latency of the best alternative */
3467 /* bound how fast we can go */
3468 delay = GNUNET_TIME_relative_max (delay,
3469 GNUNET_TIME_UNIT_SECONDS);
3470 /* randomize a bit (to avoid doing all at the same time) */
3471 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3472 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3473 &send_periodic_ping,
3481 * Function that will be called if we receive some payload
3482 * from another peer.
3484 * @param message the payload
3485 * @param n peer who claimed to be the sender
3488 handle_payload_message (const struct GNUNET_MessageHeader *message,
3489 struct NeighbourList *n)
3491 struct InboundMessage *im;
3492 struct TransportClient *cpos;
3495 msize = ntohs (message->size);
3496 if (n->received_pong == GNUNET_NO)
3498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3499 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3500 ntohs (message->type),
3501 ntohs (message->size),
3502 GNUNET_i2s (&n->id));
3503 GNUNET_free_non_null (n->pre_connect_message_buffer);
3504 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3505 memcpy (n->pre_connect_message_buffer, message, msize);
3510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3511 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3512 ntohs (message->type),
3513 ntohs (message->size),
3514 GNUNET_i2s (&n->id));
3516 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3519 n->quota_violation_count++;
3521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3522 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3523 n->in_tracker.available_bytes_per_s__,
3524 n->quota_violation_count);
3526 /* Discount 32k per violation */
3527 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3532 if (n->quota_violation_count > 0)
3534 /* try to add 32k back */
3535 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3537 n->quota_violation_count--;
3540 GNUNET_STATISTICS_update (stats,
3541 gettext_noop ("# payload received from other peers"),
3544 /* transmit message to all clients */
3545 uint32_t ats_count = 2;
3546 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3547 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3550 im = GNUNET_malloc (size);
3551 im->header.size = htons (size);
3552 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3554 im->ats_count = htonl(ats_count);
3555 /* Setting ATS data */
3556 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3557 (&(im->ats))[0].value = htonl (n->distance);
3558 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3559 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3560 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3561 (&(im->ats))[ats_count].value = htonl (0);
3563 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3565 while (cpos != NULL)
3567 transmit_to_client (cpos, &im->header, GNUNET_YES);
3575 * Iterator over hash map entries. Checks if the given validation
3576 * entry is for the same challenge as what is given in the PONG.
3578 * @param cls the 'struct TransportPongMessage*'
3579 * @param key peer identity
3580 * @param value value in the hash map ('struct ValidationEntry')
3581 * @return GNUNET_YES if we should continue to
3582 * iterate (mismatch), GNUNET_NO if not (entry matched)
3585 check_pending_validation (void *cls,
3586 const GNUNET_HashCode * key,
3589 const struct TransportPongMessage *pong = cls;
3590 struct ValidationEntry *ve = value;
3591 struct AddValidatedAddressContext avac;
3592 unsigned int challenge = ntohl(pong->challenge);
3593 struct GNUNET_HELLO_Message *hello;
3594 struct GNUNET_PeerIdentity target;
3595 struct NeighbourList *n;
3596 struct ForeignAddressList *fal;
3597 struct OwnAddressList *oal;
3598 struct TransportPlugin *tp;
3599 struct GNUNET_MessageHeader *prem;
3605 ps = ntohs (pong->header.size);
3606 if (ps < sizeof (struct TransportPongMessage))
3608 GNUNET_break_op (0);
3611 addr = (const char*) &pong[1];
3612 slen = strlen (ve->transport_name) + 1;
3613 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3614 (ve->challenge != challenge) ||
3615 (addr[slen-1] != '\0') ||
3616 (0 != strcmp (addr, ve->transport_name)) ||
3617 (ntohl (pong->purpose.size)
3618 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3620 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3621 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3626 alen = ps - sizeof (struct TransportPongMessage) - slen;
3627 switch (ntohl (pong->purpose.purpose))
3629 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3630 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3631 (0 != memcmp (&addr[slen],
3635 return GNUNET_YES; /* different entry, keep trying! */
3637 if (0 != memcmp (&pong->pid,
3639 sizeof (struct GNUNET_PeerIdentity)))
3641 GNUNET_break_op (0);
3645 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3650 GNUNET_break_op (0);
3655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3656 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3658 a2s (ve->transport_name,
3659 (const struct sockaddr *) ve->addr,
3661 ve->transport_name);
3664 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3665 if (0 != memcmp (&pong->pid,
3667 sizeof (struct GNUNET_PeerIdentity)))
3669 GNUNET_break_op (0);
3672 if (ve->addrlen != 0)
3674 /* must have been for a different validation entry */
3677 tp = find_transport (ve->transport_name);
3683 oal = tp->addresses;
3686 if ( (oal->addrlen == alen) &&
3687 (0 == memcmp (&oal[1],
3695 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3696 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3697 a2s (ve->transport_name,
3703 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3708 GNUNET_break_op (0);
3713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3714 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3716 a2s (ve->transport_name,
3719 ve->transport_name);
3723 GNUNET_break_op (0);
3726 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3728 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3729 _("Received expired signature. Check system time.\n"));
3732 GNUNET_STATISTICS_update (stats,
3733 gettext_noop ("# address validation successes"),
3736 /* create the updated HELLO */
3737 GNUNET_CRYPTO_hash (&ve->publicKey,
3738 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3739 &target.hashPubKey);
3740 if (ve->addr != NULL)
3742 avac.done = GNUNET_NO;
3744 hello = GNUNET_HELLO_create (&ve->publicKey,
3745 &add_validated_address,
3747 GNUNET_PEERINFO_add_peer (peerinfo,
3749 GNUNET_free (hello);
3751 n = find_neighbour (&target);
3754 n->publicKey = ve->publicKey;
3755 n->public_key_valid = GNUNET_YES;
3756 fal = add_peer_address (n,
3761 GNUNET_assert (fal != NULL);
3762 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3763 fal->validated = GNUNET_YES;
3764 mark_address_connected (fal);
3765 GNUNET_STATISTICS_update (stats,
3766 gettext_noop ("# peer addresses considered valid"),
3769 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3770 schedule_next_ping (fal);
3771 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3772 n->latency = fal->latency;
3774 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3776 n->distance = fal->distance;
3777 if (GNUNET_NO == n->received_pong)
3779 n->received_pong = GNUNET_YES;
3781 notify_clients_connect (&target, n->latency, n->distance);
3782 if (NULL != (prem = n->pre_connect_message_buffer))
3784 n->pre_connect_message_buffer = NULL;
3785 handle_payload_message (prem, n);
3789 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3791 GNUNET_SCHEDULER_cancel (n->retry_task);
3792 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3793 try_transmission_to_peer (n);
3797 /* clean up validation entry */
3798 GNUNET_assert (GNUNET_YES ==
3799 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3802 abort_validation (NULL, NULL, ve);
3808 * Function that will be called if we receive a validation
3809 * of an address challenge that we transmitted to another
3810 * peer. Note that the validation should only be considered
3811 * acceptable if the challenge matches AND if the sender
3812 * address is at least a plausible address for this peer
3813 * (otherwise we may be seeing a MiM attack).
3815 * @param cls closure
3816 * @param message the pong message
3817 * @param peer who responded to our challenge
3818 * @param sender_address string describing our sender address (as observed
3819 * by the other peer in binary format)
3820 * @param sender_address_len number of bytes in 'sender_address'
3823 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3824 const struct GNUNET_PeerIdentity *peer,
3825 const char *sender_address,
3826 size_t sender_address_len)
3828 #if DEBUG_TRANSPORT > 1
3829 /* we get tons of these that just get discarded, only log
3830 if we are quite verbose */
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "Receiving `%s' message from `%4s'.\n", "PONG",
3835 GNUNET_STATISTICS_update (stats,
3836 gettext_noop ("# PONG messages received"),
3839 if (GNUNET_SYSERR !=
3840 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3842 &check_pending_validation,
3845 /* This is *expected* to happen a lot since we send
3846 PONGs to *all* known addresses of the sender of
3847 the PING, so most likely we get multiple PONGs
3848 per PING, and all but the first PONG will end up
3849 here. So really we should not print anything here
3850 unless we want to be very, very verbose... */
3851 #if DEBUG_TRANSPORT > 2
3852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3853 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3865 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3867 * @param cls the 'struct ValidationEntry*'
3868 * @param neighbour neighbour to validate, NULL if validation failed
3871 transmit_hello_and_ping (void *cls,
3872 struct NeighbourList *neighbour)
3874 struct ValidationEntry *va = cls;
3875 struct ForeignAddressList *peer_address;
3876 struct TransportPingMessage ping;
3877 uint16_t hello_size;
3880 struct GNUNET_PeerIdentity id;
3883 GNUNET_CRYPTO_hash (&va->publicKey,
3884 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3886 if (neighbour == NULL)
3888 /* FIXME: stats... */
3889 GNUNET_break (GNUNET_OK ==
3890 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3893 abort_validation (NULL, NULL, va);
3896 neighbour->publicKey = va->publicKey;
3897 neighbour->public_key_valid = GNUNET_YES;
3898 peer_address = add_peer_address (neighbour,
3899 va->transport_name, NULL,
3900 (const void*) &va[1],
3902 if (peer_address == NULL)
3904 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3905 "Failed to add peer `%4s' for plugin `%s'\n",
3906 GNUNET_i2s (&neighbour->id),
3907 va->transport_name);
3908 GNUNET_break (GNUNET_OK ==
3909 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3912 abort_validation (NULL, NULL, va);
3915 hello_size = GNUNET_HELLO_size(our_hello);
3916 slen = strlen(va->transport_name) + 1;
3917 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3918 message_buf = GNUNET_malloc(tsize);
3919 ping.challenge = htonl(va->challenge);
3920 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3921 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3922 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3923 memcpy(message_buf, our_hello, hello_size);
3924 memcpy(&message_buf[hello_size],
3926 sizeof(struct TransportPingMessage));
3927 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3930 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3935 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3938 : a2s (va->transport_name,
3939 (const void*) &va[1], va->addrlen),
3941 GNUNET_i2s (&neighbour->id),
3942 "HELLO", hello_size,
3943 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3946 GNUNET_STATISTICS_update (stats,
3947 gettext_noop ("# PING messages sent for initial validation"),
3950 transmit_to_peer (NULL, peer_address,
3951 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3952 HELLO_VERIFICATION_TIMEOUT,
3954 GNUNET_YES, neighbour);
3955 GNUNET_free(message_buf);
3960 * Check if the given address is already being validated; if not,
3961 * append the given address to the list of entries that are being be
3962 * validated and initiate validation.
3964 * @param cls closure ('struct CheckHelloValidatedContext *')
3965 * @param tname name of the transport
3966 * @param expiration expiration time
3967 * @param addr the address
3968 * @param addrlen length of the address
3969 * @return GNUNET_OK (always)
3972 run_validation (void *cls,
3974 struct GNUNET_TIME_Absolute expiration,
3978 struct CheckHelloValidatedContext *chvc = cls;
3979 struct GNUNET_PeerIdentity id;
3980 struct TransportPlugin *tp;
3981 struct ValidationEntry *va;
3982 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3983 struct CheckAddressExistsClosure caec;
3984 struct OwnAddressList *oal;
3986 GNUNET_assert (addr != NULL);
3988 GNUNET_STATISTICS_update (stats,
3989 gettext_noop ("# peer addresses scheduled for validation"),
3992 tp = find_transport (tname);
3995 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3996 GNUNET_ERROR_TYPE_BULK,
3998 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4000 GNUNET_STATISTICS_update (stats,
4001 gettext_noop ("# peer addresses not validated (plugin not available)"),
4006 /* check if this is one of our own addresses */
4007 oal = tp->addresses;
4010 if ( (oal->addrlen == addrlen) &&
4011 (0 == memcmp (&oal[1],
4015 /* not plausible, this address is equivalent to our own address! */
4016 GNUNET_STATISTICS_update (stats,
4017 gettext_noop ("# peer addresses not validated (loopback)"),
4024 GNUNET_HELLO_get_key (chvc->hello, &pk);
4025 GNUNET_CRYPTO_hash (&pk,
4027 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4030 if (is_blacklisted(&id, tp))
4033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4034 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4042 caec.addrlen = addrlen;
4043 caec.session = NULL;
4045 caec.exists = GNUNET_NO;
4046 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4047 &check_address_exists,
4049 if (caec.exists == GNUNET_YES)
4051 /* During validation attempts we will likely trigger the other
4052 peer trying to validate our address which in turn will cause
4053 it to send us its HELLO, so we expect to hit this case rather
4054 frequently. Only print something if we are very verbose. */
4055 #if DEBUG_TRANSPORT > 1
4056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4057 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4058 a2s (tname, addr, addrlen),
4062 GNUNET_STATISTICS_update (stats,
4063 gettext_noop ("# peer addresses not validated (in progress)"),
4068 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4071 va->transport_name = GNUNET_strdup (tname);
4072 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4074 va->send_time = GNUNET_TIME_absolute_get();
4075 va->addr = (const void*) &va[1];
4076 memcpy (&va[1], addr, addrlen);
4077 va->addrlen = addrlen;
4078 GNUNET_HELLO_get_key (chvc->hello,
4080 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4081 &timeout_hello_validation,
4083 GNUNET_CONTAINER_multihashmap_put (validation_map,
4086 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4087 setup_peer_check_blacklist (&id, GNUNET_NO,
4088 &transmit_hello_and_ping,
4095 * Check if addresses in validated hello "h" overlap with
4096 * those in "chvc->hello" and validate the rest.
4098 * @param cls closure
4099 * @param peer id of the peer, NULL for last call
4100 * @param h hello message for the peer (can be NULL)
4101 * @param err_msg NULL if successful, otherwise contains error message
4104 check_hello_validated (void *cls,
4105 const struct GNUNET_PeerIdentity *peer,
4106 const struct GNUNET_HELLO_Message *h,
4107 const char *err_msg)
4109 struct CheckHelloValidatedContext *chvc = cls;
4110 struct GNUNET_HELLO_Message *plain_hello;
4111 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4112 struct GNUNET_PeerIdentity target;
4113 struct NeighbourList *n;
4115 if (err_msg != NULL)
4117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4118 _("Error in communication with PEERINFO service\n"));
4124 GNUNET_STATISTICS_update (stats,
4125 gettext_noop ("# outstanding peerinfo iterate requests"),
4129 if (GNUNET_NO == chvc->hello_known)
4131 /* notify PEERINFO about the peer now, so that we at least
4132 have the public key if some other component needs it */
4133 GNUNET_HELLO_get_key (chvc->hello, &pk);
4134 GNUNET_CRYPTO_hash (&pk,
4135 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4136 &target.hashPubKey);
4137 plain_hello = GNUNET_HELLO_create (&pk,
4140 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4141 GNUNET_free (plain_hello);
4142 #if DEBUG_TRANSPORT_HELLO
4143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4144 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4146 GNUNET_i2s (&target));
4148 GNUNET_STATISTICS_update (stats,
4149 gettext_noop ("# new HELLOs requiring full validation"),
4152 GNUNET_HELLO_iterate_addresses (chvc->hello,
4159 GNUNET_STATISTICS_update (stats,
4160 gettext_noop ("# duplicate HELLO (peer known)"),
4165 if (chvc->ve_count == 0)
4167 GNUNET_CONTAINER_DLL_remove (chvc_head,
4176 #if DEBUG_TRANSPORT_HELLO
4177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4178 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4182 chvc->hello_known = GNUNET_YES;
4183 n = find_neighbour (peer);
4186 #if DEBUG_TRANSPORT_HELLO
4187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4188 "Calling hello_iterate_addresses for %s!\n",
4191 GNUNET_HELLO_iterate_addresses (h,
4193 &add_to_foreign_address_list,
4195 try_transmission_to_peer (n);
4199 #if DEBUG_TRANSPORT_HELLO
4200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4201 "No existing neighbor record for %s!\n",
4204 GNUNET_STATISTICS_update (stats,
4205 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4209 GNUNET_STATISTICS_update (stats,
4210 gettext_noop ("# HELLO validations (update case)"),
4213 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4215 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4222 * Process HELLO-message.
4224 * @param plugin transport involved, may be NULL
4225 * @param message the actual message
4226 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4229 process_hello (struct TransportPlugin *plugin,
4230 const struct GNUNET_MessageHeader *message)
4233 struct GNUNET_PeerIdentity target;
4234 const struct GNUNET_HELLO_Message *hello;
4235 struct CheckHelloValidatedContext *chvc;
4236 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4237 #if DEBUG_TRANSPORT_HELLO > 2
4240 hsize = ntohs (message->size);
4241 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4242 (hsize < sizeof (struct GNUNET_MessageHeader)))
4245 return GNUNET_SYSERR;
4247 GNUNET_STATISTICS_update (stats,
4248 gettext_noop ("# HELLOs received for validation"),
4252 /* first, check if load is too high */
4253 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4255 GNUNET_STATISTICS_update (stats,
4256 gettext_noop ("# HELLOs ignored due to high load"),
4259 #if DEBUG_TRANSPORT_HELLO
4260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4261 "Ignoring `%s' for `%4s', load too high.\n",
4263 GNUNET_i2s (&target));
4267 hello = (const struct GNUNET_HELLO_Message *) message;
4268 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4270 #if DEBUG_TRANSPORT_HELLO
4271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4272 "Unable to get public key from `%s' for `%4s'!\n",
4274 GNUNET_i2s (&target));
4276 GNUNET_break_op (0);
4277 return GNUNET_SYSERR;
4280 GNUNET_CRYPTO_hash (&publicKey,
4281 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4282 &target.hashPubKey);
4284 #if DEBUG_TRANSPORT_HELLO
4285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4286 "Received `%s' message for `%4s'\n",
4288 GNUNET_i2s (&target));
4291 if (0 == memcmp (&my_identity,
4293 sizeof (struct GNUNET_PeerIdentity)))
4295 GNUNET_STATISTICS_update (stats,
4296 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4302 while (NULL != chvc)
4304 if (GNUNET_HELLO_equals (hello,
4306 GNUNET_TIME_absolute_get ()).abs_value > 0)
4308 #if DEBUG_TRANSPORT_HELLO > 2
4309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4310 "Received duplicate `%s' message for `%4s'; ignored\n",
4312 GNUNET_i2s (&target));
4314 return GNUNET_OK; /* validation already pending */
4316 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4317 GNUNET_break (0 != memcmp (hello, chvc->hello,
4318 GNUNET_HELLO_size(hello)));
4323 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4324 if ((NULL != temp_neighbor))
4326 fprintf(stderr, "Already know peer, ignoring hello\n");
4331 #if DEBUG_TRANSPORT_HELLO > 2
4334 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4336 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4339 GNUNET_i2s (&target),
4341 GNUNET_HELLO_size(hello));
4345 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4347 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4348 memcpy (&chvc[1], hello, hsize);
4349 GNUNET_CONTAINER_DLL_insert (chvc_head,
4352 /* finally, check if HELLO was previously validated
4353 (continuation will then schedule actual validation) */
4354 GNUNET_STATISTICS_update (stats,
4355 gettext_noop ("# peerinfo process hello iterate requests"),
4358 GNUNET_STATISTICS_update (stats,
4359 gettext_noop ("# outstanding peerinfo iterate requests"),
4362 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4364 HELLO_VERIFICATION_TIMEOUT,
4365 &check_hello_validated, chvc);
4371 * The peer specified by the given neighbour has timed-out or a plugin
4372 * has disconnected. We may either need to do nothing (other plugins
4373 * still up), or trigger a full disconnect and clean up. This
4374 * function updates our state and does the necessary notifications.
4375 * Also notifies our clients that the neighbour is now officially
4378 * @param n the neighbour list entry for the peer
4379 * @param check GNUNET_YES to check if ALL addresses for this peer
4380 * are gone, GNUNET_NO to force a disconnect of the peer
4381 * regardless of whether other addresses exist.
4384 disconnect_neighbour (struct NeighbourList *n, int check)
4386 struct ReadyList *rpos;
4387 struct NeighbourList *npos;
4388 struct NeighbourList *nprev;
4389 struct MessageQueue *mq;
4390 struct ForeignAddressList *peer_addresses;
4391 struct ForeignAddressList *peer_pos;
4393 if (GNUNET_YES == check)
4396 while (NULL != rpos)
4398 peer_addresses = rpos->addresses;
4399 while (peer_addresses != NULL)
4401 if (GNUNET_YES == peer_addresses->connected)
4403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4404 "NOT Disconnecting from `%4s', still have live addresses!\n",
4405 GNUNET_i2s (&n->id));
4406 return; /* still connected */
4408 peer_addresses = peer_addresses->next;
4414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4415 "Disconnecting from `%4s'\n",
4416 GNUNET_i2s (&n->id));
4418 /* remove n from neighbours list */
4421 while ((npos != NULL) && (npos != n))
4426 GNUNET_assert (npos != NULL);
4428 neighbours = n->next;
4430 nprev->next = n->next;
4432 /* notify all clients about disconnect */
4433 if (GNUNET_YES == n->received_pong)
4434 notify_clients_disconnect (&n->id);
4436 /* clean up all plugins, cancel connections and pending transmissions */
4437 while (NULL != (rpos = n->plugins))
4439 n->plugins = rpos->next;
4440 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4441 while (rpos->addresses != NULL)
4443 peer_pos = rpos->addresses;
4444 rpos->addresses = peer_pos->next;
4445 if (peer_pos->connected == GNUNET_YES)
4446 GNUNET_STATISTICS_update (stats,
4447 gettext_noop ("# connected addresses"),
4450 if (GNUNET_YES == peer_pos->validated)
4451 GNUNET_STATISTICS_update (stats,
4452 gettext_noop ("# peer addresses considered valid"),
4455 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4457 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4458 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4460 GNUNET_free(peer_pos);
4465 /* free all messages on the queue */
4466 while (NULL != (mq = n->messages_head))
4468 GNUNET_STATISTICS_update (stats,
4469 gettext_noop ("# bytes in message queue for other peers"),
4470 - (int64_t) mq->message_buf_size,
4472 GNUNET_STATISTICS_update (stats,
4473 gettext_noop ("# bytes discarded due to disconnect"),
4474 mq->message_buf_size,
4476 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4479 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4481 sizeof(struct GNUNET_PeerIdentity)));
4484 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4486 GNUNET_SCHEDULER_cancel (n->timeout_task);
4487 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4489 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4491 GNUNET_SCHEDULER_cancel (n->retry_task);
4492 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4494 if (n->piter != NULL)
4496 GNUNET_PEERINFO_iterate_cancel (n->piter);
4497 GNUNET_STATISTICS_update (stats,
4498 gettext_noop ("# outstanding peerinfo iterate requests"),
4503 /* finally, free n itself */
4504 GNUNET_STATISTICS_update (stats,
4505 gettext_noop ("# active neighbours"),
4508 GNUNET_free_non_null (n->pre_connect_message_buffer);
4514 * We have received a PING message from someone. Need to send a PONG message
4515 * in response to the peer by any means necessary.
4518 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4519 const struct GNUNET_PeerIdentity *peer,
4520 struct Session *session,
4521 const char *sender_address,
4522 uint16_t sender_address_len)
4524 struct TransportPlugin *plugin = cls;
4525 struct SessionHeader *session_header = (struct SessionHeader*) session;
4526 struct TransportPingMessage *ping;
4527 struct TransportPongMessage *pong;
4528 struct NeighbourList *n;
4529 struct ReadyList *rl;
4530 struct ForeignAddressList *fal;
4531 struct OwnAddressList *oal;
4536 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4538 GNUNET_break_op (0);
4539 return GNUNET_SYSERR;
4542 ping = (struct TransportPingMessage *) message;
4543 if (0 != memcmp (&ping->target,
4544 plugin->env.my_identity,
4545 sizeof (struct GNUNET_PeerIdentity)))
4547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4548 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4550 (sender_address != NULL)
4551 ? a2s (plugin->short_name,
4552 (const struct sockaddr *)sender_address,
4555 GNUNET_i2s (&ping->target));
4556 return GNUNET_SYSERR;
4559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4560 "Processing `%s' from `%s'\n",
4562 (sender_address != NULL)
4563 ? a2s (plugin->short_name,
4564 (const struct sockaddr *)sender_address,
4568 GNUNET_STATISTICS_update (stats,
4569 gettext_noop ("# PING messages received"),
4572 addr = (const char*) &ping[1];
4573 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4574 slen = strlen (plugin->short_name) + 1;
4577 /* peer wants to confirm that we have an outbound connection to him */
4578 if (session == NULL)
4580 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4581 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4583 return GNUNET_SYSERR;
4585 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4586 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4587 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4588 pong->purpose.size =
4589 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4591 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4592 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4593 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4594 pong->challenge = ping->challenge;
4595 pong->addrlen = htonl(sender_address_len + slen);
4598 sizeof(struct GNUNET_PeerIdentity));
4602 if ((sender_address!=NULL) && (sender_address_len > 0))
4603 memcpy (&((char*)&pong[1])[slen],
4605 sender_address_len);
4606 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4608 /* create / update cached sig */
4610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4611 "Creating PONG signature to indicate active connection.\n");
4613 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4614 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4615 GNUNET_assert (GNUNET_OK ==
4616 GNUNET_CRYPTO_rsa_sign (my_private_key,
4618 &session_header->pong_signature));
4622 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4624 memcpy (&pong->signature,
4625 &session_header->pong_signature,
4626 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4632 /* peer wants to confirm that this is one of our addresses */
4636 plugin->api->check_address (plugin->api->cls,
4640 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4641 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4642 a2s (plugin->short_name,
4647 oal = plugin->addresses;
4650 if ( (oal->addrlen == alen) &&
4657 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4658 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4659 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4660 pong->purpose.size =
4661 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4663 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4664 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4665 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4666 pong->challenge = ping->challenge;
4667 pong->addrlen = htonl(alen + slen);
4670 sizeof(struct GNUNET_PeerIdentity));
4671 memcpy (&pong[1], plugin->short_name, slen);
4672 memcpy (&((char*)&pong[1])[slen], addr, alen);
4673 if ( (oal != NULL) &&
4674 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4676 /* create / update cached sig */
4678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4679 "Creating PONG signature to indicate ownership.\n");
4681 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4682 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4683 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4684 GNUNET_assert (GNUNET_OK ==
4685 GNUNET_CRYPTO_rsa_sign (my_private_key,
4687 &oal->pong_signature));
4688 memcpy (&pong->signature,
4689 &oal->pong_signature,
4690 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4692 else if (oal == NULL)
4694 /* not using cache (typically DV-only) */
4695 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4696 GNUNET_assert (GNUNET_OK ==
4697 GNUNET_CRYPTO_rsa_sign (my_private_key,
4703 /* can used cached version */
4704 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4705 memcpy (&pong->signature,
4706 &oal->pong_signature,
4707 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4710 n = find_neighbour(peer);
4711 GNUNET_assert (n != NULL);
4712 /* first try reliable response transmission */
4716 fal = rl->addresses;
4719 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4722 ntohs (pong->header.size),
4723 TRANSPORT_PONG_PRIORITY,
4724 HELLO_VERIFICATION_TIMEOUT,
4732 GNUNET_STATISTICS_update (stats,
4733 gettext_noop ("# PONGs unicast via reliable transport"),
4743 /* no reliable method found, do multicast */
4744 GNUNET_STATISTICS_update (stats,
4745 gettext_noop ("# PONGs multicast to all available addresses"),
4751 fal = rl->addresses;
4754 transmit_to_peer(NULL, fal,
4755 TRANSPORT_PONG_PRIORITY,
4756 HELLO_VERIFICATION_TIMEOUT,
4758 ntohs(pong->header.size),
4771 * Function called by the plugin for each received message.
4772 * Update data volumes, possibly notify plugins about
4773 * reducing the rate at which they read from the socket
4774 * and generally forward to our receive callback.
4776 * @param cls the "struct TransportPlugin *" we gave to the plugin
4777 * @param peer (claimed) identity of the other peer
4778 * @param message the message, NULL if we only care about
4779 * learning about the delay until we should receive again
4780 * @param ats_data information for automatic transport selection
4781 * @param ats_count number of elements in ats not including 0-terminator
4782 * @param session identifier used for this session (can be NULL)
4783 * @param sender_address binary address of the sender (if observed)
4784 * @param sender_address_len number of bytes in sender_address
4785 * @return how long in ms the plugin should wait until receiving more data
4786 * (plugins that do not support this, can ignore the return value)
4788 static struct GNUNET_TIME_Relative
4789 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4790 const struct GNUNET_MessageHeader *message,
4791 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4793 struct Session *session,
4794 const char *sender_address,
4795 uint16_t sender_address_len)
4797 struct TransportPlugin *plugin = cls;
4798 struct ReadyList *service_context;
4799 struct ForeignAddressList *peer_address;
4801 struct NeighbourList *n;
4802 struct GNUNET_TIME_Relative ret;
4803 if (is_blacklisted (peer, plugin))
4804 return GNUNET_TIME_UNIT_FOREVER_REL;
4808 n = find_neighbour (peer);
4810 n = setup_new_neighbour (peer, GNUNET_YES);
4811 service_context = n->plugins;
4812 while ((service_context != NULL) && (plugin != service_context->plugin))
4813 service_context = service_context->next;
4814 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4815 peer_address = NULL;
4817 for (c=0; c<ats_count; c++)
4819 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4821 distance = ntohl(ats_data[c].value);
4824 /* notify ATS about incoming data */
4825 ats_notify_ats_data(peer, ats_data);
4827 if (message != NULL)
4829 if ( (session != NULL) ||
4830 (sender_address != NULL) )
4831 peer_address = add_peer_address (n,
4835 sender_address_len);
4836 if (peer_address != NULL)
4838 peer_address->distance = distance;
4839 if (GNUNET_YES == peer_address->validated)
4840 mark_address_connected (peer_address);
4841 peer_address->timeout
4843 GNUNET_TIME_relative_to_absolute
4844 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4845 schedule_next_ping (peer_address);
4847 /* update traffic received amount ... */
4848 msize = ntohs (message->size);
4849 GNUNET_STATISTICS_update (stats,
4850 gettext_noop ("# bytes received from other peers"),
4853 n->distance = distance;
4855 GNUNET_TIME_relative_to_absolute
4856 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4857 GNUNET_SCHEDULER_cancel (n->timeout_task);
4859 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4860 &neighbour_timeout_task, n);
4861 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4863 /* dropping message due to frequent inbound volume violations! */
4864 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4865 GNUNET_ERROR_TYPE_BULK,
4867 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4868 n->in_tracker.available_bytes_per_s__,
4869 n->quota_violation_count);
4870 GNUNET_STATISTICS_update (stats,
4871 gettext_noop ("# bandwidth quota violations by other peers"),
4874 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4879 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4880 ntohs (message->type),
4881 ntohs (message->size),
4884 switch (ntohs (message->type))
4886 case GNUNET_MESSAGE_TYPE_HELLO:
4887 GNUNET_STATISTICS_update (stats,
4888 gettext_noop ("# HELLO messages received from other peers"),
4891 process_hello (plugin, message);
4893 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4894 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4896 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4897 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4900 handle_payload_message (message, n);
4904 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4905 if (ret.rel_value > 0)
4907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4908 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4909 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4910 (unsigned int) n->in_tracker.available_bytes_per_s__,
4911 (unsigned long long) ret.rel_value);
4912 GNUNET_STATISTICS_update (stats,
4913 gettext_noop ("# ms throttling suggested"),
4914 (int64_t) ret.rel_value,
4921 * Handle START-message. This is the first message sent to us
4922 * by any client which causes us to add it to our list.
4924 * @param cls closure (always NULL)
4925 * @param client identification of the client
4926 * @param message the actual message
4929 handle_start (void *cls,
4930 struct GNUNET_SERVER_Client *client,
4931 const struct GNUNET_MessageHeader *message)
4933 const struct StartMessage *start;
4934 struct TransportClient *c;
4935 struct ConnectInfoMessage * cim;
4936 struct NeighbourList *n;
4940 start = (const struct StartMessage*) message;
4942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4943 "Received `%s' request from client\n", "START");
4948 if (c->client == client)
4950 /* client already on our list! */
4952 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4957 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4958 (0 != memcmp (&start->self,
4960 sizeof (struct GNUNET_PeerIdentity))) )
4962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4963 _("Rejecting control connection from peer `%s', which is not me!\n"),
4964 GNUNET_i2s (&start->self));
4965 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4968 c = GNUNET_malloc (sizeof (struct TransportClient));
4972 if (our_hello != NULL)
4975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4976 "Sending our own `%s' to new client\n", "HELLO");
4978 transmit_to_client (c,
4979 (const struct GNUNET_MessageHeader *) our_hello,
4981 /* tell new client about all existing connections */
4983 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4984 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4988 cim = GNUNET_malloc (size);
4989 cim->header.size = htons (size);
4990 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4991 cim->ats_count = htonl(ats_count);
4992 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4993 (&(cim->ats))[2].value = htonl (0);
4997 if (GNUNET_YES == n->received_pong)
4999 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5000 (&(cim->ats))[0].value = htonl (n->distance);
5001 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5002 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5004 transmit_to_client (c, &cim->header, GNUNET_NO);
5010 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5015 * Handle HELLO-message.
5017 * @param cls closure (always NULL)
5018 * @param client identification of the client
5019 * @param message the actual message
5022 handle_hello (void *cls,
5023 struct GNUNET_SERVER_Client *client,
5024 const struct GNUNET_MessageHeader *message)
5028 GNUNET_STATISTICS_update (stats,
5029 gettext_noop ("# HELLOs received from clients"),
5032 ret = process_hello (NULL, message);
5033 GNUNET_SERVER_receive_done (client, ret);
5038 * Closure for 'transmit_client_message'; followed by
5039 * 'msize' bytes of the actual message.
5041 struct TransmitClientMessageContext
5044 * Client on whom's behalf we are sending.
5046 struct GNUNET_SERVER_Client *client;
5049 * Timeout for the transmission.
5051 struct GNUNET_TIME_Absolute timeout;
5059 * Size of the message in bytes.
5066 * Schedule transmission of a message we got from a client to a peer.
5068 * @param cls the 'struct TransmitClientMessageContext*'
5069 * @param n destination, or NULL on error (in that case, drop the message)
5072 transmit_client_message (void *cls,
5073 struct NeighbourList *n)
5075 struct TransmitClientMessageContext *tcmc = cls;
5076 struct TransportClient *tc;
5079 while ((tc != NULL) && (tc->client != tcmc->client))
5084 transmit_to_peer (tc, NULL, tcmc->priority,
5085 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5087 tcmc->msize, GNUNET_NO, n);
5089 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5090 GNUNET_SERVER_client_drop (tcmc->client);
5096 * Handle SEND-message.
5098 * @param cls closure (always NULL)
5099 * @param client identification of the client
5100 * @param message the actual message
5103 handle_send (void *cls,
5104 struct GNUNET_SERVER_Client *client,
5105 const struct GNUNET_MessageHeader *message)
5107 const struct OutboundMessage *obm;
5108 const struct GNUNET_MessageHeader *obmm;
5109 struct TransmitClientMessageContext *tcmc;
5113 size = ntohs (message->size);
5115 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5118 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5121 GNUNET_STATISTICS_update (stats,
5122 gettext_noop ("# payload received for other peers"),
5125 obm = (const struct OutboundMessage *) message;
5126 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5127 msize = size - sizeof (struct OutboundMessage);
5129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5130 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5131 "SEND", GNUNET_i2s (&obm->peer),
5135 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5136 tcmc->client = client;
5137 tcmc->priority = ntohl (obm->priority);
5138 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5139 tcmc->msize = msize;
5140 /* FIXME: this memcpy can be up to 7% of our total runtime */
5141 memcpy (&tcmc[1], obmm, msize);
5142 GNUNET_SERVER_client_keep (client);
5143 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5144 &transmit_client_message,
5150 * Handle request connect message
5152 * @param cls closure (always NULL)
5153 * @param client identification of the client
5154 * @param message the actual message
5157 handle_request_connect (void *cls,
5158 struct GNUNET_SERVER_Client *client,
5159 const struct GNUNET_MessageHeader *message)
5161 const struct TransportRequestConnectMessage *trcm =
5162 (const struct TransportRequestConnectMessage *) message;
5164 GNUNET_STATISTICS_update (stats,
5165 gettext_noop ("# REQUEST CONNECT messages received"),
5168 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5169 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5171 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5175 * Handle SET_QUOTA-message.
5177 * @param cls closure (always NULL)
5178 * @param client identification of the client
5179 * @param message the actual message
5182 handle_set_quota (void *cls,
5183 struct GNUNET_SERVER_Client *client,
5184 const struct GNUNET_MessageHeader *message)
5186 const struct QuotaSetMessage *qsm =
5187 (const struct QuotaSetMessage *) message;
5188 struct NeighbourList *n;
5190 GNUNET_STATISTICS_update (stats,
5191 gettext_noop ("# SET QUOTA messages received"),
5194 n = find_neighbour (&qsm->peer);
5197 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5198 GNUNET_STATISTICS_update (stats,
5199 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5206 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5208 (unsigned int) ntohl (qsm->quota.value__),
5209 (unsigned int) n->in_tracker.available_bytes_per_s__,
5210 GNUNET_i2s (&qsm->peer));
5212 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5214 if (0 == ntohl (qsm->quota.value__))
5216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5217 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5219 disconnect_neighbour (n, GNUNET_NO);
5221 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5226 * Take the given address and append it to the set of results sent back to
5229 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5230 * @param address the resolved name, NULL to indicate the last response
5233 transmit_address_to_client (void *cls, const char *address)
5235 struct GNUNET_SERVER_TransmitContext *tc = cls;
5238 if (NULL == address)
5241 slen = strlen (address) + 1;
5243 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5244 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5245 if (NULL == address)
5246 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5251 * Handle AddressLookup-message.
5253 * @param cls closure (always NULL)
5254 * @param client identification of the client
5255 * @param message the actual message
5258 handle_address_lookup (void *cls,
5259 struct GNUNET_SERVER_Client *client,
5260 const struct GNUNET_MessageHeader *message)
5262 const struct AddressLookupMessage *alum;
5263 struct TransportPlugin *lsPlugin;
5264 const char *nameTransport;
5265 const char *address;
5267 struct GNUNET_SERVER_TransmitContext *tc;
5268 struct GNUNET_TIME_Absolute timeout;
5269 struct GNUNET_TIME_Relative rtimeout;
5272 size = ntohs (message->size);
5273 if (size < sizeof (struct AddressLookupMessage))
5275 GNUNET_break_op (0);
5276 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5279 alum = (const struct AddressLookupMessage *) message;
5280 uint32_t addressLen = ntohl (alum->addrlen);
5281 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5283 GNUNET_break_op (0);
5284 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5287 address = (const char *) &alum[1];
5288 nameTransport = (const char *) &address[addressLen];
5290 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5292 GNUNET_break_op (0);
5293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5296 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5297 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5298 numeric = ntohl (alum->numeric_only);
5299 lsPlugin = find_transport (nameTransport);
5300 if (NULL == lsPlugin)
5302 tc = GNUNET_SERVER_transmit_context_create (client);
5303 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5304 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5305 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5308 tc = GNUNET_SERVER_transmit_context_create (client);
5309 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5311 address, addressLen,
5314 &transmit_address_to_client, tc);
5319 * Setup the environment for this plugin.
5322 create_environment (struct TransportPlugin *plug)
5324 plug->env.cfg = cfg;
5325 plug->env.my_identity = &my_identity;
5326 plug->env.our_hello = &our_hello;
5327 plug->env.cls = plug;
5328 plug->env.receive = &plugin_env_receive;
5329 plug->env.notify_address = &plugin_env_notify_address;
5330 plug->env.session_end = &plugin_env_session_end;
5331 plug->env.max_connections = max_connect_per_transport;
5332 plug->env.stats = stats;
5337 * Start the specified transport (load the plugin).
5340 start_transport (struct GNUNET_SERVER_Handle *server,
5343 struct TransportPlugin *plug;
5346 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5347 _("Loading `%s' transport plugin\n"), name);
5348 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5349 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5350 create_environment (plug);
5351 plug->short_name = GNUNET_strdup (name);
5352 plug->lib_name = libname;
5353 plug->next = plugins;
5355 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5356 if (plug->api == NULL)
5358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5359 _("Failed to load transport plugin for `%s'\n"), name);
5360 GNUNET_free (plug->short_name);
5361 plugins = plug->next;
5362 GNUNET_free (libname);
5369 * Called whenever a client is disconnected. Frees our
5370 * resources associated with that client.
5372 * @param cls closure
5373 * @param client identification of the client
5376 client_disconnect_notification (void *cls,
5377 struct GNUNET_SERVER_Client *client)
5379 struct TransportClient *pos;
5380 struct TransportClient *prev;
5381 struct ClientMessageQueueEntry *mqe;
5382 struct Blacklisters *bl;
5383 struct BlacklistCheck *bc;
5388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5389 "Client disconnected, cleaning up.\n");
5391 /* clean up blacklister */
5395 if (bl->client == client)
5400 if (bc->bl_pos == bl)
5402 bc->bl_pos = bl->next;
5405 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5408 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5409 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5415 GNUNET_CONTAINER_DLL_remove (bl_head,
5418 GNUNET_SERVER_client_drop (bl->client);
5424 /* clean up 'normal' clients */
5427 while ((pos != NULL) && (pos->client != client))
5434 while (NULL != (mqe = pos->message_queue_head))
5436 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5437 pos->message_queue_tail,
5439 pos->message_count--;
5443 clients = pos->next;
5445 prev->next = pos->next;
5446 if (GNUNET_YES == pos->tcs_pending)
5451 if (pos->th != NULL)
5453 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5456 GNUNET_break (0 == pos->message_count);
5462 * Function called when the service shuts down. Unloads our plugins
5463 * and cancels pending validations.
5465 * @param cls closure, unused
5466 * @param tc task context (unused)
5469 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5471 struct TransportPlugin *plug;
5472 struct OwnAddressList *al;
5473 struct CheckHelloValidatedContext *chvc;
5475 while (neighbours != NULL)
5477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5478 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5480 disconnect_neighbour (neighbours, GNUNET_NO);
5483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5484 "Transport service is unloading plugins...\n");
5486 while (NULL != (plug = plugins))
5488 plugins = plug->next;
5489 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5491 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5492 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5494 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5495 GNUNET_free (plug->lib_name);
5496 GNUNET_free (plug->short_name);
5497 while (NULL != (al = plug->addresses))
5499 plug->addresses = al->next;
5504 if (my_private_key != NULL)
5505 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5506 GNUNET_free_non_null (our_hello);
5508 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5511 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5512 validation_map = NULL;
5516 /* free 'chvc' data structure */
5517 while (NULL != (chvc = chvc_head))
5519 chvc_head = chvc->next;
5520 if (chvc->piter != NULL)
5522 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5523 GNUNET_STATISTICS_update (stats,
5524 gettext_noop ("# outstanding peerinfo iterate requests"),
5530 GNUNET_assert (chvc->ve_count == 0);
5537 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5540 if (peerinfo != NULL)
5542 GNUNET_PEERINFO_disconnect (peerinfo);
5545 /* Can we assume those are gone by now, or do we need to clean up
5547 GNUNET_break (bl_head == NULL);
5548 GNUNET_break (bc_head == NULL);
5551 struct ATS_mechanism
5553 struct ATS_mechanism * prev;
5554 struct ATS_mechanism * next;
5555 struct ForeignAddressList * addr;
5556 struct TransportPlugin * plugin;
5557 struct ATS_peer * peer;
5567 struct GNUNET_PeerIdentity peer;
5568 struct NeighbourList * n;
5569 struct ATS_mechanism * m_head;
5570 struct ATS_mechanism * m_tail;
5572 /* preference value f */
5577 #define DEBUG_ATS GNUNET_YES
5578 #define VERBOSE_ATS GNUNET_YES
5581 static int ats_create_problem (int max_it, int max_dur )
5584 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5587 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5598 int c_c_ressources = 0;
5599 int c_q_metrics = 0;
5601 double v_b_min = 100;
5604 //double M = 10000000000; // ~10 GB
5607 // This are values that are later set from extern
5612 double Q[c_q_metrics+1];
5613 for (c=1; c<=c_q_metrics; c++)
5618 struct NeighbourList *next = neighbours;
5621 struct ReadyList *r_next = next->plugins;
5622 while (r_next != NULL)
5624 struct ForeignAddressList * a_next = r_next->addresses;
5625 while (a_next != NULL)
5628 a_next = a_next->next;
5630 r_next = r_next->next;
5638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5642 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5643 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5645 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
5651 peers[c_peers].peer = next->id;
5652 peers[c_peers].m_head = NULL;
5653 peers[c_peers].m_tail = NULL;
5655 peers[c_peers].f = 1.0 / c_mechs;
5657 struct ReadyList *r_next = next->plugins;
5658 while (r_next != NULL)
5660 struct ForeignAddressList * a_next = r_next->addresses;
5661 while (a_next != NULL)
5663 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id),
5665 mechanisms[c_mechs].addr = a_next;
5666 mechanisms[c_mechs].col_index = c_mechs;
5667 mechanisms[c_mechs].peer = &peers[c_peers];
5668 mechanisms[c_mechs].next = NULL;
5670 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5672 a_next = a_next->next;
5674 r_next = r_next->next;
5682 if (v_n_min > c_peers)
5685 /* number of variables == coloumns */
5686 //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
5687 /* number of constraints == rows */
5688 //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
5690 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms\n", c_peers, c_mechs);
5692 int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers;
5695 int * ia = GNUNET_malloc (size * sizeof (int));
5696 int * ja = GNUNET_malloc (size * sizeof (int));
5697 double * ar = GNUNET_malloc(size* sizeof (double));
5699 prob = glp_create_prob();
5700 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5701 glp_set_obj_dir(prob, GLP_MAX);
5703 /* adding columns */
5705 glp_add_cols(prob, 2 * c_mechs);
5706 /* adding b_t cols */
5707 for (c=1; c <= c_mechs; c++)
5709 GNUNET_asprintf(&name, "b%i",c);
5710 glp_set_col_name(prob, c, name);
5712 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5713 glp_set_obj_coef(prob, c, 1);
5716 /* adding n_t cols */
5717 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5719 GNUNET_asprintf(&name, "n%i",(c-c_mechs));
5720 glp_set_col_name(prob, c, name);
5722 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5723 glp_set_col_kind(prob, c, GLP_IV);
5724 glp_set_obj_coef(prob, c, 0);
5727 /* feasibility constraints */
5728 /* Constraint 1: one address per peer*/
5729 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
5731 glp_add_rows(prob, c_peers);
5732 for (c=1; c<=c_peers; c++)
5734 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
5736 struct ATS_mechanism *m = peers[c].m_head;
5739 ia[array_index] = row_index;
5740 ja[array_index] = (c_mechs + m->col_index);
5741 ar[array_index] = 1;
5742 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]);
5748 GNUNET_assert (row_index-1==c_peers);
5749 GNUNET_assert (array_index-1==c_mechs);
5751 /* Constraint 2: only active mechanism gets bandwidth assigned */
5752 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
5753 glp_add_rows(prob, c_mechs);
5754 for (c=1; c<=c_mechs; c++)
5756 /* b_t - n_t * M <= 0 */
5757 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5758 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5760 ia[array_index] = row_index;
5761 ja[array_index] = mechanisms[c].col_index;
5762 ar[array_index] = 1;
5763 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]);
5765 ia[array_index] = row_index;
5766 ja[array_index] = c_mechs + mechanisms[c].col_index;
5767 ar[array_index] = -M;
5768 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]);
5772 GNUNET_assert (row_index-1==c_peers+c_mechs);
5773 GNUNET_assert (array_index-1==c_mechs+(2*c_mechs));
5775 /* Constraint 3: minimum bandwidth*/
5776 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5777 glp_add_rows(prob, c_mechs);
5778 for (c=1; c<=c_mechs; c++)
5780 /* b_t - n_t * b_min <= 0 */
5781 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5782 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5784 ia[array_index] = row_index;
5785 ja[array_index] = mechanisms[c].col_index;
5786 ar[array_index] = 1;
5787 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]);
5789 ia[array_index] = row_index;
5790 ja[array_index] = c_mechs + mechanisms[c].col_index;
5791 ar[array_index] = -v_b_min;
5792 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]);
5796 GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
5797 GNUNET_assert (array_index-1==c_mechs+(4*c_mechs));
5799 /* Constraint 4: max ressource capacity */
5801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5802 glp_add_rows(prob, c_mechs);
5803 for (c=1; c<=c_mechs; c++)
5805 // b_t - n_t * b_min >= 0
5806 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5807 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5809 ia[array_index] = row_index;
5810 ja[array_index] = mechanisms[c].col_index;
5811 ar[array_index] = 1;
5812 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]);
5814 ia[array_index] = row_index;
5815 ja[array_index] = c_mechs + mechanisms[c].col_index;
5816 ar[array_index] = -v_b_min;
5817 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]);
5821 GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
5822 GNUNET_assert (array_index==5*c_mechs);
5825 /* Constraint 5: min number of connections*/
5826 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
5827 glp_add_rows(prob, 1);
5828 for (c=1; c<=c_mechs; c++)
5830 // b_t - n_t * b_min >= 0
5831 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5832 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
5834 ia[array_index] = row_index;
5835 ja[array_index] = c_mechs + mechanisms[c].col_index;
5836 ar[array_index] = 1;
5837 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]);
5841 GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+1);
5842 GNUNET_assert (array_index-1==6*c_mechs);
5844 /* optimisation constraints*/
5846 /* adding columns */
5847 glp_add_cols(prob, 3 + c_q_metrics);
5848 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
5849 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
5850 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
5851 //glp_set_col_kind(prob, c, GLP_IV);
5852 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
5853 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
5854 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
5855 //glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5856 //glp_set_col_kind(prob, c, GLP_IV);
5857 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
5858 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
5859 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
5860 //glp_set_col_kind(prob, c, GLP_IV);
5861 for (c=1; c<= c_q_metrics; c++)
5863 GNUNET_asprintf(&name, "q%i",c);
5864 glp_set_col_name(prob, c, name);
5865 glp_set_col_name(prob, (2*c_mechs) + 3 +c, name);
5867 glp_set_obj_coef(prob, (2*c_mechs) + 3 +c, Q[c]);
5870 // Constraint 6: optimize for diversity
5871 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 6\n");
5872 glp_add_rows(prob, 1);
5873 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5874 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
5875 //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5876 for (c=1; c<=c_mechs; c++)
5878 // b_t - n_t * b_min >= 0
5879 ia[array_index] = row_index;
5880 ja[array_index] = c_mechs + mechanisms[c].col_index;
5881 ar[array_index] = 1;
5882 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]);
5885 ia[array_index] = row_index;
5886 ja[array_index] = (2*c_mechs) + 1;
5887 ar[array_index] = -1;
5888 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]);
5891 GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+2);
5892 GNUNET_assert (array_index-1==7*c_mechs+1);
5894 // Constraint 7: optimize for quality
5896 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 7\n");
5897 glp_add_rows(prob, 1);
5898 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5899 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
5900 //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5901 for (c=1; c<=c_mechs; c++)
5903 // b_t - n_t * b_min >= 0
5904 ia[array_index] = row_index;
5905 ja[array_index] = c_mechs + mechanisms[c].col_index;
5906 ar[array_index] = 1;
5907 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]);
5910 ia[array_index] = row_index;
5911 ja[array_index] = (2*c_mechs) + 1;
5912 ar[array_index] = -1;
5913 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]);
5916 GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+2);
5917 GNUNET_assert (array_index-1==7*c_mechs+1);
5920 // Constraint 8: optimize bandwidth utility
5921 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 8\n");
5922 glp_add_rows(prob, 1);
5923 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5924 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
5925 for (c=1; c<=c_mechs; c++)
5927 ia[array_index] = row_index;
5928 ja[array_index] = c;
5929 ar[array_index] = mechanisms[c].peer->f;
5930 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]);
5933 ia[array_index] = row_index;
5934 ja[array_index] = (2*c_mechs) + 2;
5935 ar[array_index] = -1;
5936 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]);
5941 GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+3);
5942 GNUNET_assert (array_index-1==8*c_mechs+2);
5944 // Constraint 9: optimize relativity
5945 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 9\n");
5946 glp_add_rows(prob, c_peers);
5947 for (c=1; c<=c_peers; c++)
5949 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5951 struct ATS_mechanism *m = peers[c].m_head;
5954 ia[array_index] = row_index;
5955 ja[array_index] = m->col_index;
5956 ar[array_index] = 1;
5957 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]);
5961 ia[array_index] = row_index;
5962 ja[array_index] = (2*c_mechs) + 3;
5963 ar[array_index] = -1;
5964 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]);
5969 GNUNET_assert (row_index-1==2*c_peers+(2*c_mechs)+3);
5970 GNUNET_assert (array_index-1==9*c_mechs+2+c_peers);
5972 glp_load_matrix(prob, array_index-1, ia, ja, ar);
5976 glp_init_smcp(&opt_lp);
5978 opt_lp.msg_lev = GLP_MSG_ALL;
5980 opt_lp.msg_lev = GLP_MSG_OFF;
5981 result = glp_simplex(prob, &opt_lp);
5984 glp_init_iocp(&opt_mlp);
5985 /* maximum duration */
5986 opt_mlp.tm_lim = max_dur;
5989 opt_mlp.msg_lev = GLP_MSG_ALL;
5991 opt_mlp.msg_lev = GLP_MSG_OFF;
5993 result = glp_intopt (prob, &opt_mlp);
5994 solution = glp_mip_status (prob);
5996 if (VERBOSE_ATS) glp_write_lp(prob, NULL, "ats_mlp.lp");
5998 case GLP_ESTOP : /* search terminated by application */
5999 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Search terminated by application ");
6001 case GLP_EITLIM : /* iteration limit exceeded */
6002 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Iteration limit exceeded ");
6005 case GLP_ETMLIM : /* time limit exceeded */
6006 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Time limit exceeded ");
6008 case GLP_ENOPFS : /* no primal feasible solution */
6009 case GLP_ENODFS : /* no dual feasible solution */
6010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No feasible solution");
6013 case GLP_EBADB : /* invalid basis */
6014 case GLP_ESING : /* singular matrix */
6015 case GLP_ECOND : /* ill-conditioned matrix */
6016 case GLP_EBOUND : /* invalid bounds */
6017 case GLP_EFAIL : /* solver failed */
6018 case GLP_EOBJLL : /* objective lower limit reached */
6019 case GLP_EOBJUL : /* objective upper limit reached */
6020 case GLP_EROOT : /* root LP optimum not provided */
6021 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid Input data\n");
6026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem has been solved\n");
6032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is undefined\n");
6035 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer optimal\n");
6038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n");
6041 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MI problem has no integer feasible solution\n");
6048 char * debug_solution = NULL;
6050 for (c=1; c<= (2*c_mechs) +3; c++ )
6052 old = debug_solution;
6053 GNUNET_asprintf(&debug_solution, "%s %s = %g;", (debug_solution!=NULL) ? debug_solution : "", glp_get_col_name(prob,c), glp_get_col_prim(prob, c));
6054 if (old!=NULL) GNUNET_free(old);
6056 old = debug_solution;
6057 GNUNET_asprintf(&debug_solution, "%s z = %g; \n", debug_solution, glp_get_obj_val(prob));
6058 if (old!=NULL) GNUNET_free(old);
6059 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s \n",debug_solution);
6063 GNUNET_free(debug_solution);
6064 glp_delete_prob(prob);
6070 GNUNET_free(mechanisms);
6076 /* To remove: just for testing */
6077 void ats_benchmark (int peers, int transports, int start_peers, int end_peers)
6079 static int glpk = GNUNET_YES;
6080 struct GNUNET_TIME_Absolute start;
6081 struct GNUNET_TIME_Relative duration;
6084 if (glpk==GNUNET_YES)
6086 start = GNUNET_TIME_absolute_get();
6087 c_mechs = ats_create_problem(5000,5000);
6090 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6091 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);
6092 //GNUNET_STATISTICS_set (stats, "ATS execution time 100 peers", duration.rel_value, GNUNET_NO);
6094 else glpk = GNUNET_NO;
6098 void ats_calculate_bandwidth_distribution ()
6100 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6101 if (delta.rel_value < ats->min_delta.rel_value)
6104 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6109 struct GNUNET_TIME_Absolute start;
6111 int mlp = GNUNET_NO;
6120 int it = ATS_MAX_ITERATIONS;
6123 if (INT_MAX < ats->max_exec_duration.rel_value)
6126 dur = (int) ats->max_exec_duration.rel_value;
6128 struct ATS_mechanism * tl = NULL;
6129 struct ATS_peer * pl = NULL;
6131 start = GNUNET_TIME_absolute_get();
6132 ats_benchmark(100,3,100,100);
6133 //ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur, mlp);
6135 GNUNET_free_non_null (pl);
6136 GNUNET_free_non_null (tl);
6138 ats->last = GNUNET_TIME_absolute_get();
6144 ats_schedule_calculation (void *cls,
6145 const struct GNUNET_SCHEDULER_TaskContext *tc)
6147 struct ATS_info *ats = (struct ATS_info *) cls;
6151 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6152 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6158 ats_calculate_bandwidth_distribution (ats);
6160 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6161 &ats_schedule_calculation, ats);
6165 int ats_map_remove_peer (void *cls,
6166 const GNUNET_HashCode * key,
6170 struct ATS_peer * p = (struct ATS_peer *) value;
6172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
6181 struct ATS_info * ats_init ()
6183 struct ATS_info * ats;
6185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
6187 ats = GNUNET_malloc(sizeof (struct ATS_info));
6188 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
6189 GNUNET_assert(ats->peers!=NULL);
6191 ats->min_delta = ATS_MIN_INTERVAL;
6192 ats->exec_intervall = ATS_EXEC_INTERVAL;
6193 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6194 ats->max_iterations = ATS_MAX_ITERATIONS;
6196 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6198 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
6199 &schedule_calculation, NULL);
6201 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
6202 &schedule_calculation, NULL);
6204 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6210 void ats_shutdown ()
6213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6215 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6216 GNUNET_SCHEDULER_cancel(ats->ats_task);
6217 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6219 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
6220 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
6225 void ats_notify_peer_connect (
6226 const struct GNUNET_PeerIdentity *peer,
6227 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6234 while (ntohl(ats_data[c].type)!=0)
6237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6241 /* check if peer is already known */
6242 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
6244 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
6245 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
6246 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
6249 ats_calculate_bandwidth_distribution(ats);
6252 void ats_notify_peer_disconnect (
6253 const struct GNUNET_PeerIdentity *peer)
6256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6259 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
6261 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
6262 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
6265 ats_calculate_bandwidth_distribution (ats);
6269 void ats_notify_ats_data (
6270 const struct GNUNET_PeerIdentity *peer,
6271 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6274 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6276 ats_calculate_bandwidth_distribution(ats);
6279 struct ForeignAddressList * ats_get_preferred_address (
6280 struct NeighbourList *n)
6283 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6285 struct ReadyList *next = n->plugins;
6286 while (next != NULL)
6289 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6293 return find_ready_address(n);
6297 * Initiate transport service.
6299 * @param cls closure
6300 * @param server the initialized server
6301 * @param c configuration to use
6305 struct GNUNET_SERVER_Handle *server,
6306 const struct GNUNET_CONFIGURATION_Handle *c)
6308 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6309 {&handle_start, NULL,
6310 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6311 {&handle_hello, NULL,
6312 GNUNET_MESSAGE_TYPE_HELLO, 0},
6313 {&handle_send, NULL,
6314 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6315 {&handle_request_connect, NULL,
6316 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6317 {&handle_set_quota, NULL,
6318 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6319 {&handle_address_lookup, NULL,
6320 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6322 {&handle_blacklist_init, NULL,
6323 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6324 {&handle_blacklist_reply, NULL,
6325 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6331 unsigned long long tneigh;
6335 stats = GNUNET_STATISTICS_create ("transport", cfg);
6336 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6337 /* parse configuration */
6339 GNUNET_CONFIGURATION_get_value_number (c,
6344 GNUNET_CONFIGURATION_get_value_filename (c,
6346 "HOSTKEY", &keyfile)))
6348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6350 ("Transport service is lacking key configuration settings. Exiting.\n"));
6351 GNUNET_SCHEDULER_shutdown ();
6354 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6357 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6358 validation_map = NULL;
6363 max_connect_per_transport = (uint32_t) tneigh;
6364 peerinfo = GNUNET_PEERINFO_connect (cfg);
6365 if (peerinfo == NULL)
6367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6368 _("Could not access PEERINFO service. Exiting.\n"));
6369 GNUNET_SCHEDULER_shutdown ();
6372 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6375 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6376 validation_map = NULL;
6377 GNUNET_free (keyfile);
6380 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6381 GNUNET_free (keyfile);
6382 if (my_private_key == NULL)
6384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6386 ("Transport service could not access hostkey. Exiting.\n"));
6387 GNUNET_SCHEDULER_shutdown ();
6390 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6393 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6394 validation_map = NULL;
6397 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6398 GNUNET_CRYPTO_hash (&my_public_key,
6399 sizeof (my_public_key), &my_identity.hashPubKey);
6400 /* setup notification */
6401 GNUNET_SERVER_disconnect_notify (server,
6402 &client_disconnect_notification, NULL);
6403 /* load plugins... */
6406 GNUNET_CONFIGURATION_get_value_string (c,
6407 "TRANSPORT", "PLUGINS", &plugs))
6409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6410 _("Starting transport plugins `%s'\n"), plugs);
6411 pos = strtok (plugs, " ");
6414 start_transport (server, pos);
6416 pos = strtok (NULL, " ");
6418 GNUNET_free (plugs);
6420 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6421 &shutdown_task, NULL);
6426 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6428 /* If we have a blacklist file, read from it */
6429 read_blacklist_file(cfg);
6430 /* process client requests */
6431 GNUNET_SERVER_add_handlers (server, handlers);
6436 * The main function for the transport service.
6438 * @param argc number of arguments from the command line
6439 * @param argv command line arguments
6440 * @return 0 ok, 1 on error
6443 main (int argc, char *const *argv)
6445 a2s (NULL, NULL, 0); /* make compiler happy */
6446 return (GNUNET_OK ==
6447 GNUNET_SERVICE_run (argc,
6450 GNUNET_SERVICE_OPTION_NONE,
6451 &run, NULL)) ? 0 : 1;
6454 /* end of gnunet-service-transport.c */