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_YES
47 #define DEBUG_PING_PONG GNUNET_YES
49 #define DEBUG_TRANSPORT_HELLO GNUNET_YES
52 #define DEBUG_ATS GNUNET_YES
55 #define DEBUG_ATS GNUNET_YES
58 #define VERBOSE_ATS GNUNET_NO
61 * Should we do some additional checks (to validate behavior
64 #define EXTRA_CHECKS GNUNET_YES
67 * How many messages can we have pending for a given client process
68 * before we start to drop incoming messages? We typically should
69 * have only one client and so this would be the primary buffer for
70 * messages, so the number should be chosen rather generously.
72 * The expectation here is that most of the time the queue is large
73 * enough so that a drop is virtually never required. Note that
74 * this value must be about as large as 'TOTAL_MSGS' in the
75 * 'test_transport_api_reliability.c', otherwise that testcase may
78 #define MAX_PENDING (128 * 1024)
81 * Size of the per-transport blacklist hash maps.
83 #define TRANSPORT_BLACKLIST_HT_SIZE 16
86 * How often should we try to reconnect to a peer using a particular
87 * transport plugin before giving up? Note that the plugin may be
88 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
90 #define MAX_CONNECT_RETRY 3
93 * Limit on the number of ready-to-run tasks when validating
94 * HELLOs. If more tasks are ready to run, we will drop
95 * HELLOs instead of validating them.
97 #define MAX_HELLO_LOAD 4
100 * How often must a peer violate bandwidth quotas before we start
101 * to simply drop its messages?
103 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
106 * How long until a HELLO verification attempt should time out?
107 * Must be rather small, otherwise a partially successful HELLO
108 * validation (some addresses working) might not be available
109 * before a client's request for a connection fails for good.
110 * Besides, if a single request to an address takes a long time,
111 * then the peer is unlikely worthwhile anyway.
113 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
116 * How long is a PONG signature valid? We'll recycle a signature until
117 * 1/4 of this time is remaining. PONGs should expire so that if our
118 * external addresses change an adversary cannot replay them indefinitely.
119 * OTOH, we don't want to spend too much time generating PONG signatures,
120 * so they must have some lifetime to reduce our CPU usage.
122 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
125 * Priority to use for PONG messages.
127 #define TRANSPORT_PONG_PRIORITY 4
130 * How often do we re-add (cheaper) plugins to our list of plugins
131 * to try for a given connected peer?
133 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
136 * After how long do we expire an address in a HELLO that we just
137 * validated? This value is also used for our own addresses when we
140 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
144 * How long before an existing address expires should we again try to
145 * validate it? Must be (significantly) smaller than
146 * HELLO_ADDRESS_EXPIRATION.
148 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
151 * Maximum frequency for re-evaluating latencies for all transport addresses.
153 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
156 * Maximum frequency for re-evaluating latencies for connected addresses.
158 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
162 * List of addresses of other peers
164 struct ForeignAddressList
167 * This is a linked list.
169 struct ForeignAddressList *next;
172 * Which ready list does this entry belong to.
174 struct ReadyList *ready_list;
177 * How long until we auto-expire this address (unless it is
178 * re-confirmed by the transport)?
180 struct GNUNET_TIME_Absolute expires;
183 * Task used to re-validate addresses, updates latencies and
186 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
194 * Session (or NULL if no valid session currently exists or if the
195 * plugin does not use sessions).
197 struct Session *session;
200 * What was the last latency observed for this address, plugin and peer?
202 struct GNUNET_TIME_Relative latency;
205 * If we did not successfully transmit a message to the given peer
206 * via this connection during the specified time, we should consider
207 * the connection to be dead. This is used in the case that a TCP
208 * transport simply stalls writing to the stream but does not
209 * formerly get a signal that the other peer died.
211 struct GNUNET_TIME_Absolute timeout;
214 * How often have we tried to connect using this plugin? Used to
215 * discriminate against addresses that do not work well.
216 * FIXME: not yet used, but should be!
218 unsigned int connect_attempts;
221 * DV distance to this peer (1 if no DV is used).
222 * FIXME: need to set this from transport plugins!
232 * Have we ever estimated the latency of this address? Used to
233 * ensure that the first time we add an address, we immediately
239 * Are we currently connected via this address? The first time we
240 * successfully transmit or receive data to a peer via a particular
241 * address, we set this to GNUNET_YES. If we later get an error
242 * (disconnect notification, transmission failure, timeout), we set
243 * it back to GNUNET_NO.
248 * Is this plugin currently busy transmitting to the specific target?
249 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
250 * messages do not count as 'in transmit'.
255 * Has this address been validated yet?
263 * Entry in linked list of network addresses for ourselves. Also
264 * includes a cached signature for 'struct TransportPongMessage's.
266 struct OwnAddressList
269 * This is a linked list.
271 struct OwnAddressList *next;
274 * How long until we actually auto-expire this address (unless it is
275 * re-confirmed by the transport)?
277 struct GNUNET_TIME_Absolute expires;
280 * How long until the current signature expires? (ZERO if the
281 * signature was never created).
283 struct GNUNET_TIME_Absolute pong_sig_expires;
286 * Signature for a 'struct TransportPongMessage' for this address.
288 struct GNUNET_CRYPTO_RsaSignature pong_signature;
299 * Entry in linked list of all of our plugins.
301 struct TransportPlugin
305 * This is a linked list.
307 struct TransportPlugin *next;
310 * API of the transport as returned by the plugin's
311 * initialization function.
313 struct GNUNET_TRANSPORT_PluginFunctions *api;
316 * Short name for the plugin (i.e. "tcp").
321 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
326 * List of our known addresses for this transport.
328 struct OwnAddressList *addresses;
331 * Environment this transport service is using
334 struct GNUNET_TRANSPORT_PluginEnvironment env;
337 * ID of task that is used to clean up expired addresses.
339 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
342 * Set to GNUNET_YES if we need to scrap the existing list of
343 * "addresses" and start fresh when we receive the next address
344 * update from a transport. Set to GNUNET_NO if we should just add
345 * the new address to the list and wait for the commit call.
350 * Hashmap of blacklisted peers for this particular transport.
352 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
355 struct NeighbourList;
358 * For each neighbour we keep a list of messages
359 * that we still want to transmit to the neighbour.
365 * This is a doubly linked list.
367 struct MessageQueue *next;
370 * This is a doubly linked list.
372 struct MessageQueue *prev;
375 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
376 * stuck together in memory. Allocated at the end of this struct.
378 const char *message_buf;
381 * Size of the message buf
383 size_t message_buf_size;
386 * Client responsible for queueing the message;
387 * used to check that a client has no two messages
388 * pending for the same target. Can be NULL.
390 struct TransportClient *client;
393 * Using which specific address should we send this message?
395 struct ForeignAddressList *specific_address;
398 * Peer ID of the Neighbour this entry belongs to.
400 struct GNUNET_PeerIdentity neighbour_id;
403 * Plugin that we used for the transmission.
404 * NULL until we scheduled a transmission.
406 struct TransportPlugin *plugin;
409 * At what time should we fail?
411 struct GNUNET_TIME_Absolute timeout;
414 * Internal message of the transport system that should not be
415 * included in the usual SEND-SEND_OK transmission confirmation
416 * traffic management scheme. Typically, "internal_msg" will
417 * be set whenever "client" is NULL (but it is not strictly
423 * How important is the message?
425 unsigned int priority;
431 * For a given Neighbour, which plugins are available
432 * to talk to this peer and what are their costs?
437 * This is a linked list.
439 struct ReadyList *next;
442 * Which of our transport plugins does this entry
445 struct TransportPlugin *plugin;
448 * Transport addresses, latency, and readiness for
449 * this particular plugin.
451 struct ForeignAddressList *addresses;
454 * To which neighbour does this ready list belong to?
456 struct NeighbourList *neighbour;
462 * Entry in linked list of all of our current neighbours.
468 * This is a linked list.
470 struct NeighbourList *next;
473 * Which of our transports is connected to this peer
474 * and what is their status?
476 struct ReadyList *plugins;
479 * Head of list of messages we would like to send to this peer;
480 * must contain at most one message per client.
482 struct MessageQueue *messages_head;
485 * Tail of list of messages we would like to send to this peer; must
486 * contain at most one message per client.
488 struct MessageQueue *messages_tail;
491 * Buffer for at most one payload message used when we receive
492 * payload data before our PING-PONG has succeeded. We then
493 * store such messages in this intermediary buffer until the
494 * connection is fully up.
496 struct GNUNET_MessageHeader *pre_connect_message_buffer;
499 * Context for peerinfo iteration.
500 * NULL after we are done processing peerinfo's information.
502 struct GNUNET_PEERINFO_IteratorContext *piter;
505 * Public key for this peer. Valid only if the respective flag is set below.
507 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
510 * Identity of this neighbour.
512 struct GNUNET_PeerIdentity id;
515 * ID of task scheduled to run when this peer is about to
516 * time out (will free resources associated with the peer).
518 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
521 * ID of task scheduled to run when we should retry transmitting
522 * the head of the message queue. Actually triggered when the
523 * transmission is timing out (we trigger instantly when we have
524 * a chance of success).
526 GNUNET_SCHEDULER_TaskIdentifier retry_task;
529 * How long until we should consider this peer dead
530 * (if we don't receive another message in the
533 struct GNUNET_TIME_Absolute peer_timeout;
536 * Tracker for inbound bandwidth.
538 struct GNUNET_BANDWIDTH_Tracker in_tracker;
541 * The latency we have seen for this particular address for
542 * this particular peer. This latency may have been calculated
543 * over multiple transports. This value reflects how long it took
544 * us to receive a response when SENDING via this particular
545 * transport/neighbour/address combination!
547 * FIXME: we need to periodically send PINGs to update this
548 * latency (at least more often than the current "huge" (11h?)
551 struct GNUNET_TIME_Relative latency;
554 * How often has the other peer (recently) violated the
555 * inbound traffic limit? Incremented by 10 per violation,
556 * decremented by 1 per non-violation (for each
559 unsigned int quota_violation_count;
562 * DV distance to this peer (1 if no DV is used).
567 * Have we seen an PONG from this neighbour in the past (and
568 * not had a disconnect since)?
573 * Do we have a valid public key for this neighbour?
575 int public_key_valid;
578 * Performance data for the peer.
580 struct GNUNET_TRANSPORT_ATS_Information *ats;
583 * Identity of the neighbour.
585 struct GNUNET_PeerIdentity peer;
590 * Message used to ask a peer to validate receipt (to check an address
591 * from a HELLO). Followed by the address we are trying to validate,
592 * or an empty address if we are just sending a PING to confirm that a
593 * connection which the receiver (of the PING) initiated is still valid.
595 struct TransportPingMessage
599 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
601 struct GNUNET_MessageHeader header;
604 * Challenge code (to ensure fresh reply).
606 uint32_t challenge GNUNET_PACKED;
609 * Who is the intended recipient?
611 struct GNUNET_PeerIdentity target;
617 * Message used to validate a HELLO. The challenge is included in the
618 * confirmation to make matching of replies to requests possible. The
619 * signature signs our public key, an expiration time and our address.<p>
621 * This message is followed by our transport address that the PING tried
622 * to confirm (if we liked it). The address can be empty (zero bytes)
623 * if the PING had not address either (and we received the request via
624 * a connection that we initiated).
626 struct TransportPongMessage
630 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
632 struct GNUNET_MessageHeader header;
635 * Challenge code from PING (showing freshness). Not part of what
636 * is signed so that we can re-use signatures.
638 uint32_t challenge GNUNET_PACKED;
643 struct GNUNET_CRYPTO_RsaSignature signature;
646 * What are we signing and why? Two possible reason codes can be here:
647 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
648 * plausible address for this peer (pid is set to identity of signer); or
649 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
650 * an address we used to connect to the peer with the given pid.
652 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
655 * When does this signature expire?
657 struct GNUNET_TIME_AbsoluteNBO expiration;
660 * Either the identity of the peer Who signed this message, or the
661 * identity of the peer that we're connected to using the given
662 * address (depending on purpose.type).
664 struct GNUNET_PeerIdentity pid;
667 * Size of address appended to this message (part of what is
668 * being signed, hence not redundant).
676 * Linked list of messages to be transmitted to the client. Each
677 * entry is followed by the actual message.
679 struct ClientMessageQueueEntry
682 * This is a doubly-linked list.
684 struct ClientMessageQueueEntry *next;
687 * This is a doubly-linked list.
689 struct ClientMessageQueueEntry *prev;
694 * Client connected to the transport service.
696 struct TransportClient
700 * This is a linked list.
702 struct TransportClient *next;
705 * Handle to the client.
707 struct GNUNET_SERVER_Client *client;
710 * Linked list of messages yet to be transmitted to
713 struct ClientMessageQueueEntry *message_queue_head;
716 * Tail of linked list of messages yet to be transmitted to the
719 struct ClientMessageQueueEntry *message_queue_tail;
722 * Current transmit request handle.
724 struct GNUNET_CONNECTION_TransmitHandle *th;
727 * Is a call to "transmit_send_continuation" pending? If so, we
728 * must not free this struct (even if the corresponding client
729 * disconnects) and instead only remove it from the linked list and
730 * set the "client" field to NULL.
735 * Length of the list of messages pending for this client.
737 unsigned int message_count;
743 * Context of currently active requests to peerinfo
744 * for validation of HELLOs.
746 struct CheckHelloValidatedContext;
750 * Entry in map of all HELLOs awaiting validation.
752 struct ValidationEntry
756 * NULL if this entry is not part of a larger HELLO validation.
758 struct CheckHelloValidatedContext *chvc;
761 * The address, actually a pointer to the end
762 * of this struct. Do not free!
767 * Name of the transport.
769 char *transport_name;
772 * The public key of the peer.
774 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
777 * ID of task that will clean up this entry if we don't succeed
778 * with the validation first.
780 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
783 * At what time did we send this validation?
785 struct GNUNET_TIME_Absolute send_time;
788 * Session being validated (or NULL for none).
790 struct Session *session;
793 * Challenge number we used.
806 * Context of currently active requests to peerinfo
807 * for validation of HELLOs.
809 struct CheckHelloValidatedContext
813 * This is a doubly-linked list.
815 struct CheckHelloValidatedContext *next;
818 * This is a doubly-linked list.
820 struct CheckHelloValidatedContext *prev;
823 * Hello that we are validating.
825 const struct GNUNET_HELLO_Message *hello;
828 * Context for peerinfo iteration.
829 * NULL after we are done processing peerinfo's information.
831 struct GNUNET_PEERINFO_IteratorContext *piter;
834 * Was a HELLO known for this peer to peerinfo?
839 * Number of validation entries currently referring to this
842 unsigned int ve_count;
850 static struct GNUNET_HELLO_Message *our_hello;
855 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
860 static struct GNUNET_PeerIdentity my_identity;
865 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
870 const struct GNUNET_CONFIGURATION_Handle *cfg;
873 * Linked list of all clients to this service.
875 static struct TransportClient *clients;
878 * All loaded plugins.
880 static struct TransportPlugin *plugins;
883 * Handle to peerinfo service.
885 static struct GNUNET_PEERINFO_Handle *peerinfo;
888 * All known neighbours and their HELLOs.
890 static struct NeighbourList *neighbours;
893 * Number of neighbours we'd like to have.
895 static uint32_t max_connect_per_transport;
898 * Head of linked list.
900 static struct CheckHelloValidatedContext *chvc_head;
903 * Tail of linked list.
905 static struct CheckHelloValidatedContext *chvc_tail;
908 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
909 * of the given peer that we are currently validating).
911 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
914 * Handle for reporting statistics.
916 static struct GNUNET_STATISTICS_Handle *stats;
919 * Handle for ats information
921 static struct ATS_info *ats;
924 * The peer specified by the given neighbour has timed-out or a plugin
925 * has disconnected. We may either need to do nothing (other plugins
926 * still up), or trigger a full disconnect and clean up. This
927 * function updates our state and do the necessary notifications.
928 * Also notifies our clients that the neighbour is now officially
931 * @param n the neighbour list entry for the peer
932 * @param check should we just check if all plugins
933 * disconnected or must we ask all plugins to
936 static void disconnect_neighbour (struct NeighbourList *n, int check);
939 * Check the ready list for the given neighbour and if a plugin is
940 * ready for transmission (and if we have a message), do so!
942 * @param neighbour target peer for which to transmit
944 static void try_transmission_to_peer (struct NeighbourList *n);
947 struct ATS_info * ats_init ();
949 void ats_shutdown ( );
951 void ats_notify_peer_connect (
952 const struct GNUNET_PeerIdentity *peer,
953 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
955 void ats_notify_peer_disconnect (
956 const struct GNUNET_PeerIdentity *peer);
958 void ats_notify_ats_data (
959 const struct GNUNET_PeerIdentity *peer,
960 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
962 struct ForeignAddressList * ats_get_preferred_address (
963 struct NeighbourList *n);
966 * Find an entry in the neighbour list for a particular peer.
968 * @return NULL if not found.
970 static struct NeighbourList *
971 find_neighbour (const struct GNUNET_PeerIdentity *key)
973 struct NeighbourList *head = neighbours;
975 while ((head != NULL) &&
976 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
983 * Find an entry in the transport list for a particular transport.
985 * @return NULL if not found.
987 static struct TransportPlugin *
988 find_transport (const char *short_name)
990 struct TransportPlugin *head = plugins;
991 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
997 * Is a particular peer blacklisted for a particular transport?
999 * @param peer the peer to check for
1000 * @param plugin the plugin used to connect to the peer
1002 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1005 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1008 if (plugin->blacklist != NULL)
1010 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Peer `%s:%s' is blacklisted!\n",
1015 plugin->short_name, GNUNET_i2s (peer));
1018 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1028 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1030 struct TransportPlugin *plugin;
1032 plugin = find_transport(transport_name);
1033 if (plugin == NULL) /* Nothing to do */
1035 if (plugin->blacklist == NULL)
1036 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1037 GNUNET_assert(plugin->blacklist != NULL);
1038 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1040 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1045 * Read the blacklist file, containing transport:peer entries.
1046 * Provided the transport is loaded, set up hashmap with these
1047 * entries to blacklist peers by transport.
1051 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1058 struct GNUNET_PeerIdentity pid;
1060 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1061 unsigned int entries_found;
1062 char *transport_name;
1065 GNUNET_CONFIGURATION_get_value_filename (cfg,
1071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072 "Option `%s' in section `%s' not specified!\n",
1078 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1079 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1080 | GNUNET_DISK_PERM_USER_WRITE);
1081 if (0 != STAT (fn, &frstat))
1083 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1084 _("Could not read blacklist file `%s'\n"), fn);
1088 if (frstat.st_size == 0)
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 _("Blacklist file `%s' is empty.\n"),
1098 /* FIXME: use mmap */
1099 data = GNUNET_malloc_large (frstat.st_size);
1100 GNUNET_assert(data != NULL);
1101 if (frstat.st_size !=
1102 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1105 _("Failed to read blacklist from `%s'\n"), fn);
1112 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1114 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1115 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1118 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1121 if (colon_pos >= frstat.st_size)
1123 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1124 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1125 (unsigned long long) colon_pos);
1131 if (isspace( (unsigned char) data[colon_pos]))
1133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1134 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1135 (unsigned long long) colon_pos);
1137 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1141 tsize = colon_pos - pos;
1142 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1144 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1145 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1146 (unsigned long long) colon_pos);
1155 transport_name = GNUNET_malloc(tsize + 1);
1156 memcpy(transport_name, &data[pos], tsize);
1157 pos = colon_pos + 1;
1159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160 "Read transport name %s in blacklist file.\n",
1163 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1164 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1167 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1168 (unsigned long long) pos);
1170 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1172 GNUNET_free_non_null(transport_name);
1175 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1176 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1178 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1179 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1180 (unsigned long long) pos,
1185 if (0 != memcmp (&pid,
1187 sizeof (struct GNUNET_PeerIdentity)))
1190 add_peer_to_blacklist (&pid,
1195 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1196 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1200 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1201 GNUNET_free_non_null(transport_name);
1202 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1205 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1212 * Function called to notify a client about the socket being ready to
1213 * queue more data. "buf" will be NULL and "size" zero if the socket
1214 * was closed for writing in the meantime.
1216 * @param cls closure
1217 * @param size number of bytes available in buf
1218 * @param buf where the callee should write the message
1219 * @return number of bytes written to buf
1222 transmit_to_client_callback (void *cls, size_t size, void *buf)
1224 struct TransportClient *client = cls;
1225 struct ClientMessageQueueEntry *q;
1228 const struct GNUNET_MessageHeader *msg;
1235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236 "Transmission to client failed, closing connection.\n");
1238 /* fatal error with client, free message queue! */
1239 while (NULL != (q = client->message_queue_head))
1241 GNUNET_STATISTICS_update (stats,
1242 gettext_noop ("# bytes discarded (could not transmit to client)"),
1243 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1245 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1246 client->message_queue_tail,
1250 client->message_count = 0;
1255 while (NULL != (q = client->message_queue_head))
1257 msg = (const struct GNUNET_MessageHeader *) &q[1];
1258 msize = ntohs (msg->size);
1259 if (msize + tsize > size)
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "Transmitting message of type %u to client.\n",
1266 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1267 client->message_queue_tail,
1269 memcpy (&cbuf[tsize], msg, msize);
1272 client->message_count--;
1276 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1277 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1279 GNUNET_TIME_UNIT_FOREVER_REL,
1280 &transmit_to_client_callback,
1282 GNUNET_assert (client->th != NULL);
1289 * Convert an address to a string.
1291 * @param plugin name of the plugin responsible for the address
1292 * @param addr binary address
1293 * @param addr_len number of bytes in addr
1294 * @return NULL on error, otherwise address string
1297 a2s (const char *plugin,
1301 struct TransportPlugin *p;
1305 p = find_transport (plugin);
1308 return p->api->address_to_string (p->api->cls,
1315 * Mark the given FAL entry as 'connected' (and hence preferred for
1316 * sending); also mark all others for the same peer as 'not connected'
1317 * (since only one can be preferred).
1319 * @param fal address to set to 'connected'
1322 mark_address_connected (struct ForeignAddressList *fal)
1324 struct ForeignAddressList *pos;
1327 GNUNET_assert (GNUNET_YES == fal->validated);
1328 if (fal->connected == GNUNET_YES)
1329 return; /* nothing to do */
1331 pos = fal->ready_list->addresses;
1334 if (GNUNET_YES == pos->connected)
1337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1338 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1339 a2s (pos->ready_list->plugin->short_name,
1343 GNUNET_break (cnt == GNUNET_YES);
1345 pos->connected = GNUNET_NO;
1346 GNUNET_STATISTICS_update (stats,
1347 gettext_noop ("# connected addresses"),
1353 fal->connected = GNUNET_YES;
1354 if (GNUNET_YES == cnt)
1356 GNUNET_STATISTICS_update (stats,
1357 gettext_noop ("# connected addresses"),
1365 * Send the specified message to the specified client. Since multiple
1366 * messages may be pending for the same client at a time, this code
1367 * makes sure that no message is lost.
1369 * @param client client to transmit the message to
1370 * @param msg the message to send
1371 * @param may_drop can this message be dropped if the
1372 * message queue for this client is getting far too large?
1375 transmit_to_client (struct TransportClient *client,
1376 const struct GNUNET_MessageHeader *msg, int may_drop)
1378 struct ClientMessageQueueEntry *q;
1381 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1385 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1388 client->message_count,
1390 GNUNET_STATISTICS_update (stats,
1391 gettext_noop ("# messages dropped due to slow client"),
1396 msize = ntohs (msg->size);
1397 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1398 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1399 memcpy (&q[1], msg, msize);
1400 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1401 client->message_queue_tail,
1402 client->message_queue_tail,
1404 client->message_count++;
1405 if (client->th == NULL)
1407 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1409 GNUNET_TIME_UNIT_FOREVER_REL,
1410 &transmit_to_client_callback,
1412 GNUNET_assert (client->th != NULL);
1418 * Transmit a 'SEND_OK' notification to the given client for the
1421 * @param client who to notify
1422 * @param n neighbour to notify about, can be NULL (on failure)
1423 * @param target target of the transmission
1424 * @param result status code for the transmission request
1427 transmit_send_ok (struct TransportClient *client,
1428 struct NeighbourList *n,
1429 const struct GNUNET_PeerIdentity *target,
1432 struct SendOkMessage send_ok_msg;
1434 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1435 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1436 send_ok_msg.success = htonl (result);
1438 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1440 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1441 send_ok_msg.peer = *target;
1442 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1447 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1448 * upon "completion" of a send request. This tells the API
1449 * that it is now legal to send another message to the given
1452 * @param cls closure, identifies the entry on the
1453 * message queue that was transmitted and the
1454 * client responsible for queuing the message
1455 * @param target the peer receiving the message
1456 * @param result GNUNET_OK on success, if the transmission
1457 * failed, we should not tell the client to transmit
1461 transmit_send_continuation (void *cls,
1462 const struct GNUNET_PeerIdentity *target,
1465 struct MessageQueue *mq = cls;
1466 struct NeighbourList *n;
1468 GNUNET_STATISTICS_update (stats,
1469 gettext_noop ("# bytes pending with plugins"),
1470 - (int64_t) mq->message_buf_size,
1472 if (result == GNUNET_OK)
1474 GNUNET_STATISTICS_update (stats,
1475 gettext_noop ("# bytes successfully transmitted by plugins"),
1476 mq->message_buf_size,
1481 GNUNET_STATISTICS_update (stats,
1482 gettext_noop ("# bytes with transmission failure by plugins"),
1483 mq->message_buf_size,
1486 if (mq->specific_address != NULL)
1488 if (result == GNUNET_OK)
1490 mq->specific_address->timeout =
1491 GNUNET_TIME_relative_to_absolute
1492 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1493 if (mq->specific_address->validated == GNUNET_YES)
1494 mark_address_connected (mq->specific_address);
1498 if (mq->specific_address->connected != GNUNET_NO)
1501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1502 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1503 a2s (mq->specific_address->ready_list->plugin->short_name,
1504 mq->specific_address->addr,
1505 mq->specific_address->addrlen));
1507 GNUNET_STATISTICS_update (stats,
1508 gettext_noop ("# connected addresses"),
1511 mq->specific_address->connected = GNUNET_NO;
1514 if (! mq->internal_msg)
1515 mq->specific_address->in_transmit = GNUNET_NO;
1517 n = find_neighbour(&mq->neighbour_id);
1518 if (mq->client != NULL)
1519 transmit_send_ok (mq->client, n, target, result);
1522 try_transmission_to_peer (n);
1527 * Find an address in any of the available transports for
1528 * the given neighbour that would be good for message
1529 * transmission. This is essentially the transport selection
1532 * @param neighbour for whom to select an address
1533 * @return selected address, NULL if we have none
1535 struct ForeignAddressList *
1536 find_ready_address(struct NeighbourList *neighbour)
1538 struct ReadyList *head = neighbour->plugins;
1539 struct ForeignAddressList *addresses;
1540 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1541 struct ForeignAddressList *best_address;
1543 /* Hack to prefer unix domain sockets */
1544 struct ForeignAddressList *unix_address = NULL;
1546 best_address = NULL;
1547 while (head != NULL)
1549 addresses = head->addresses;
1550 while (addresses != NULL)
1552 if ( (addresses->timeout.abs_value < now.abs_value) &&
1553 (addresses->connected == GNUNET_YES) )
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Marking long-time inactive connection to `%4s' as down.\n",
1558 GNUNET_i2s (&neighbour->id));
1560 GNUNET_STATISTICS_update (stats,
1561 gettext_noop ("# connected addresses"),
1564 addresses->connected = GNUNET_NO;
1566 addresses = addresses->next;
1569 addresses = head->addresses;
1570 while (addresses != NULL)
1572 #if DEBUG_TRANSPORT > 1
1573 if (addresses->addr != NULL)
1574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1576 a2s (head->plugin->short_name,
1578 addresses->addrlen),
1579 GNUNET_i2s (&neighbour->id),
1580 addresses->connected,
1581 addresses->in_transmit,
1582 addresses->validated,
1583 addresses->connect_attempts,
1584 (unsigned long long) addresses->timeout.abs_value,
1585 (unsigned int) addresses->distance);
1587 if (0==strcmp(head->plugin->short_name,"unix"))
1589 if ((unix_address == NULL) || ((unix_address != NULL) &&
1590 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1591 unix_address = addresses;
1593 if ( ( (best_address == NULL) ||
1594 (addresses->connected == GNUNET_YES) ||
1595 (best_address->connected == GNUNET_NO) ) &&
1596 (addresses->in_transmit == GNUNET_NO) &&
1597 ( (best_address == NULL) ||
1598 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1599 best_address = addresses;
1600 /* FIXME: also give lower-latency addresses that are not
1601 connected a chance some times... */
1602 addresses = addresses->next;
1604 if (unix_address != NULL)
1608 if (unix_address != NULL)
1610 best_address = unix_address;
1612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1615 if (best_address != NULL)
1619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1620 "Best address found (`%s') has latency of %llu ms.\n",
1621 (best_address->addrlen > 0)
1622 ? a2s (best_address->ready_list->plugin->short_name,
1624 best_address->addrlen)
1626 best_address->latency.rel_value);
1631 GNUNET_STATISTICS_update (stats,
1632 gettext_noop ("# transmission attempts failed (no address)"),
1637 return best_address;
1643 * We should re-try transmitting to the given peer,
1644 * hopefully we've learned something in the meantime.
1647 retry_transmission_task (void *cls,
1648 const struct GNUNET_SCHEDULER_TaskContext *tc)
1650 struct NeighbourList *n = cls;
1652 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1653 try_transmission_to_peer (n);
1658 * Check the ready list for the given neighbour and if a plugin is
1659 * ready for transmission (and if we have a message), do so!
1661 * @param neighbour target peer for which to transmit
1664 try_transmission_to_peer (struct NeighbourList *n)
1666 struct ReadyList *rl;
1667 struct MessageQueue *mq;
1668 struct GNUNET_TIME_Relative timeout;
1672 if (n->messages_head == NULL)
1675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1676 "Transmission queue for `%4s' is empty\n",
1677 GNUNET_i2s (&neighbour->id));
1679 return; /* nothing to do */
1682 mq = n->messages_head;
1683 force_address = GNUNET_YES;
1684 if (mq->specific_address == NULL)
1687 mq->specific_address = ats_get_preferred_address(n);
1688 GNUNET_STATISTICS_update (stats,
1689 gettext_noop ("# transport selected peer address freely"),
1692 force_address = GNUNET_NO;
1694 if (mq->specific_address == NULL)
1696 GNUNET_STATISTICS_update (stats,
1697 gettext_noop ("# transport failed to selected peer address"),
1700 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1701 if (timeout.rel_value == 0)
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "No destination address available to transmit message of size %u to peer `%4s'\n",
1706 mq->message_buf_size,
1707 GNUNET_i2s (&mq->neighbour_id));
1709 GNUNET_STATISTICS_update (stats,
1710 gettext_noop ("# bytes in message queue for other peers"),
1711 - (int64_t) mq->message_buf_size,
1713 GNUNET_STATISTICS_update (stats,
1714 gettext_noop ("# bytes discarded (no destination address available)"),
1715 mq->message_buf_size,
1717 if (mq->client != NULL)
1718 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1719 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1723 return; /* nobody ready */
1725 GNUNET_STATISTICS_update (stats,
1726 gettext_noop ("# message delivery deferred (no address)"),
1729 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1730 GNUNET_SCHEDULER_cancel (n->retry_task);
1731 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1732 &retry_transmission_task,
1735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1736 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1737 mq->message_buf_size,
1738 GNUNET_i2s (&mq->neighbour_id),
1741 /* FIXME: might want to trigger peerinfo lookup here
1742 (unless that's already pending...) */
1745 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1748 if (mq->specific_address->connected == GNUNET_NO)
1749 mq->specific_address->connect_attempts++;
1750 rl = mq->specific_address->ready_list;
1751 mq->plugin = rl->plugin;
1752 if (!mq->internal_msg)
1753 mq->specific_address->in_transmit = GNUNET_YES;
1755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1756 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1757 mq->message_buf_size,
1758 GNUNET_i2s (&neighbour->id),
1759 (mq->specific_address->addr != NULL)
1760 ? a2s (mq->plugin->short_name,
1761 mq->specific_address->addr,
1762 mq->specific_address->addrlen)
1764 rl->plugin->short_name);
1766 GNUNET_STATISTICS_update (stats,
1767 gettext_noop ("# bytes in message queue for other peers"),
1768 - (int64_t) mq->message_buf_size,
1770 GNUNET_STATISTICS_update (stats,
1771 gettext_noop ("# bytes pending with plugins"),
1772 mq->message_buf_size,
1774 ret = rl->plugin->api->send (rl->plugin->api->cls,
1777 mq->message_buf_size,
1779 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1780 mq->specific_address->session,
1781 mq->specific_address->addr,
1782 mq->specific_address->addrlen,
1784 &transmit_send_continuation, mq);
1787 /* failure, but 'send' would not call continuation in this case,
1788 so we need to do it here! */
1789 transmit_send_continuation (mq,
1797 * Send the specified message to the specified peer.
1799 * @param client source of the transmission request (can be NULL)
1800 * @param peer_address ForeignAddressList where we should send this message
1801 * @param priority how important is the message
1802 * @param timeout how long do we have to transmit?
1803 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1804 * @param message_buf_size total size of all messages in message_buf
1805 * @param is_internal is this an internal message; these are pre-pended and
1806 * also do not count for plugins being "ready" to transmit
1807 * @param neighbour handle to the neighbour for transmission
1810 transmit_to_peer (struct TransportClient *client,
1811 struct ForeignAddressList *peer_address,
1812 unsigned int priority,
1813 struct GNUNET_TIME_Relative timeout,
1814 const char *message_buf,
1815 size_t message_buf_size,
1816 int is_internal, struct NeighbourList *neighbour)
1818 struct MessageQueue *mq;
1823 /* check for duplicate submission */
1824 mq = neighbour->messages_head;
1827 if (mq->client == client)
1829 /* client transmitted to same peer twice
1830 before getting SEND_OK! */
1838 GNUNET_STATISTICS_update (stats,
1839 gettext_noop ("# bytes in message queue for other peers"),
1842 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1843 mq->specific_address = peer_address;
1844 mq->client = client;
1845 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1846 memcpy (&mq[1], message_buf, message_buf_size);
1847 mq->message_buf = (const char*) &mq[1];
1848 mq->message_buf_size = message_buf_size;
1849 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1850 mq->internal_msg = is_internal;
1851 mq->priority = priority;
1852 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1854 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1855 neighbour->messages_tail,
1858 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1859 neighbour->messages_tail,
1860 neighbour->messages_tail,
1862 try_transmission_to_peer (neighbour);
1869 struct GeneratorContext
1871 struct TransportPlugin *plug_pos;
1872 struct OwnAddressList *addr_pos;
1873 struct GNUNET_TIME_Absolute expiration;
1881 address_generator (void *cls, size_t max, void *buf)
1883 struct GeneratorContext *gc = cls;
1886 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1888 gc->plug_pos = gc->plug_pos->next;
1889 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1891 if (NULL == gc->plug_pos)
1896 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1899 gc->addr_pos->addrlen, buf, max);
1900 gc->addr_pos = gc->addr_pos->next;
1906 * Construct our HELLO message from all of the addresses of
1907 * all of the transports.
1912 struct GNUNET_HELLO_Message *hello;
1913 struct TransportClient *cpos;
1914 struct NeighbourList *npos;
1915 struct GeneratorContext gc;
1917 gc.plug_pos = plugins;
1918 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1919 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1920 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1923 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1925 GNUNET_STATISTICS_update (stats,
1926 gettext_noop ("# refreshed my HELLO"),
1930 while (cpos != NULL)
1932 transmit_to_client (cpos,
1933 (const struct GNUNET_MessageHeader *) hello,
1938 GNUNET_free_non_null (our_hello);
1940 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1942 while (npos != NULL)
1945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1946 "Transmitting updated `%s' to neighbour `%4s'\n",
1947 "HELLO", GNUNET_i2s (&npos->id));
1949 GNUNET_STATISTICS_update (stats,
1950 gettext_noop ("# transmitted my HELLO to other peers"),
1953 transmit_to_peer (NULL, NULL, 0,
1954 HELLO_ADDRESS_EXPIRATION,
1955 (const char *) our_hello,
1956 GNUNET_HELLO_size(our_hello),
1964 * Task used to clean up expired addresses for a plugin.
1966 * @param cls closure
1970 expire_address_task (void *cls,
1971 const struct GNUNET_SCHEDULER_TaskContext *tc);
1975 * Update the list of addresses for this plugin,
1976 * expiring those that are past their expiration date.
1978 * @param plugin addresses of which plugin should be recomputed?
1979 * @param fresh set to GNUNET_YES if a new address was added
1980 * and we need to regenerate the HELLO even if nobody
1984 update_addresses (struct TransportPlugin *plugin,
1987 static struct GNUNET_TIME_Absolute last_update;
1988 struct GNUNET_TIME_Relative min_remaining;
1989 struct GNUNET_TIME_Relative remaining;
1990 struct GNUNET_TIME_Absolute now;
1991 struct OwnAddressList *pos;
1992 struct OwnAddressList *prev;
1993 struct OwnAddressList *next;
1996 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1997 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1998 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1999 now = GNUNET_TIME_absolute_get ();
2000 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2001 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2003 pos = plugin->addresses;
2007 if (pos->expires.abs_value < now.abs_value)
2009 expired = GNUNET_YES;
2011 plugin->addresses = pos->next;
2013 prev->next = pos->next;
2018 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2019 if (remaining.rel_value < min_remaining.rel_value)
2020 min_remaining = remaining;
2026 if (expired || fresh)
2031 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2032 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2034 plugin->address_update_task
2035 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2036 &expire_address_task, plugin);
2041 * Task used to clean up expired addresses for a plugin.
2043 * @param cls closure
2047 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2049 struct TransportPlugin *plugin = cls;
2051 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2052 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2053 update_addresses (plugin, GNUNET_NO);
2058 * Iterator over hash map entries that NULLs the session of validation
2059 * entries that match the given session.
2061 * @param cls closure (the 'struct Session*' to match against)
2062 * @param key current key code (peer ID, not used)
2063 * @param value value in the hash map ('struct ValidationEntry*')
2064 * @return GNUNET_YES (we should continue to iterate)
2067 remove_session_validations (void *cls,
2068 const GNUNET_HashCode * key,
2071 struct Session *session = cls;
2072 struct ValidationEntry *ve = value;
2074 if (session == ve->session)
2081 * We've been disconnected from the other peer (for some
2082 * connection-oriented transport). Either quickly
2083 * re-establish the connection or signal the disconnect
2086 * Only signal CORE level disconnect if ALL addresses
2087 * for the peer are exhausted.
2089 * @param p overall plugin context
2090 * @param nl neighbour that was disconnected
2093 try_fast_reconnect (struct TransportPlugin *p,
2094 struct NeighbourList *nl)
2096 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2097 /* Note: the idea here is to hide problems with transports (or
2098 switching between plugins) from the core to eliminate the need to
2099 re-negotiate session keys and the like; OTOH, we should tell core
2100 quickly (much faster than timeout) `if a connection was lost and
2101 could not be re-established (i.e. other peer went down or is
2102 unable / refuses to communicate);
2104 So we should consider:
2105 1) ideally: our own willingness / need to connect
2106 2) prior failures to connect to this peer (by plugin)
2107 3) ideally: reasons why other peer terminated (as far as knowable)
2109 Most importantly, it must be POSSIBLE for another peer to terminate
2110 a connection for a while (without us instantly re-establishing it).
2111 Similarly, if another peer is gone we should quickly notify CORE.
2112 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2113 on the other end), we should reconnect in such a way that BOTH CORE
2114 services never even notice.
2115 Furthermore, the same mechanism (or small variation) could be used
2116 to switch to a better-performing plugin (ATS).
2118 Finally, this needs to be tested throughly... */
2121 * GNUNET_NO in the call below makes transport disconnect the peer,
2122 * even if only a single address (out of say, six) went away. This
2123 * function must be careful to ONLY disconnect if the peer is gone,
2124 * not just a specifi address.
2126 * More specifically, half the places it was used had it WRONG.
2129 /* No reconnect, signal disconnect instead! */
2130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2131 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2132 "try_fast_reconnect");
2133 disconnect_neighbour (nl, GNUNET_YES);
2138 * Function that will be called whenever the plugin internally
2139 * cleans up a session pointer and hence the service needs to
2140 * discard all of those sessions as well. Plugins that do not
2141 * use sessions can simply omit calling this function and always
2142 * use NULL wherever a session pointer is needed.
2144 * @param cls closure
2145 * @param peer which peer was the session for
2146 * @param session which session is being destoyed
2149 plugin_env_session_end (void *cls,
2150 const struct GNUNET_PeerIdentity *peer,
2151 struct Session *session)
2153 struct TransportPlugin *p = cls;
2154 struct NeighbourList *nl;
2155 struct ReadyList *rl;
2156 struct ForeignAddressList *pos;
2157 struct ForeignAddressList *prev;
2159 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2160 &remove_session_validations,
2162 nl = find_neighbour (peer);
2164 return; /* was never marked as connected */
2168 if (rl->plugin == p)
2173 return; /* was never marked as connected */
2175 pos = rl->addresses;
2176 while ( (pos != NULL) &&
2177 (pos->session != session) )
2183 return; /* was never marked as connected */
2184 pos->session = NULL;
2185 if (pos->addrlen != 0)
2187 if (nl->received_pong != GNUNET_NO)
2188 try_fast_reconnect (p, nl);
2191 /* was inbound connection, free 'pos' */
2193 rl->addresses = pos->next;
2195 prev->next = pos->next;
2196 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2198 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2199 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2202 if (nl->received_pong == GNUNET_NO)
2203 return; /* nothing to do, never connected... */
2204 /* check if we have any validated addresses left */
2205 pos = rl->addresses;
2210 try_fast_reconnect (p, nl);
2215 /* no valid addresses left, signal disconnect! */
2217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2218 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2219 "plugin_env_session_end");
2220 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2221 * it means there aren't any left for this PLUGIN/PEER combination! So
2222 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2223 * when it isn't necessary. Using GNUNET_YES at least checks to see
2224 * if there are any addresses that work first, so as not to overdo it.
2227 disconnect_neighbour (nl, GNUNET_YES);
2232 * Function that must be called by each plugin to notify the
2233 * transport service about the addresses under which the transport
2234 * provided by the plugin can be reached.
2236 * @param cls closure
2237 * @param name name of the transport that generated the address
2238 * @param addr one of the addresses of the host, NULL for the last address
2239 * the specific address format depends on the transport
2240 * @param addrlen length of the address
2241 * @param expires when should this address automatically expire?
2244 plugin_env_notify_address (void *cls,
2248 struct GNUNET_TIME_Relative expires)
2250 struct TransportPlugin *p = cls;
2251 struct OwnAddressList *al;
2252 struct GNUNET_TIME_Absolute abex;
2254 GNUNET_assert (addr != NULL);
2255 abex = GNUNET_TIME_relative_to_absolute (expires);
2256 GNUNET_assert (p == find_transport (name));
2260 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2263 update_addresses (p, GNUNET_NO);
2269 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2270 al->next = p->addresses;
2273 al->addrlen = addrlen;
2274 memcpy (&al[1], addr, addrlen);
2275 update_addresses (p, GNUNET_YES);
2280 * Notify all of our clients about a peer connecting.
2283 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2284 struct GNUNET_TIME_Relative latency,
2287 struct ConnectInfoMessage * cim;
2288 struct TransportClient *cpos;
2293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2294 "Notifying clients about connection from `%s'\n",
2297 GNUNET_STATISTICS_update (stats,
2298 gettext_noop ("# peers connected"),
2303 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2304 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2308 cim = GNUNET_malloc (size);
2310 cim->header.size = htons (size);
2311 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2312 cim->ats_count = htonl(2);
2313 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2314 (&(cim->ats))[0].value = htonl (distance);
2315 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2316 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2317 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2318 (&(cim->ats))[2].value = htonl (0);
2319 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2321 /* notify ats about connecting peer */
2322 ats_notify_peer_connect (peer, &(cim->ats));
2325 while (cpos != NULL)
2327 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2336 * Notify all of our clients about a peer disconnecting.
2339 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2341 struct DisconnectInfoMessage dim;
2342 struct TransportClient *cpos;
2345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2346 "Notifying clients about lost connection to `%s'\n",
2349 GNUNET_STATISTICS_update (stats,
2350 gettext_noop ("# peers connected"),
2353 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2354 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2355 dim.reserved = htonl (0);
2356 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2358 /* notify ats about connecting peer */
2359 ats_notify_peer_disconnect (peer);
2362 while (cpos != NULL)
2364 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2371 * Find a ForeignAddressList entry for the given neighbour
2372 * that matches the given address and transport.
2374 * @param neighbour which peer we care about
2375 * @param tname name of the transport plugin
2376 * @param session session to look for, NULL for 'any'; otherwise
2377 * can be used for the service to "learn" this session ID
2379 * @param addr binary address
2380 * @param addrlen length of addr
2381 * @return NULL if no such entry exists
2383 static struct ForeignAddressList *
2384 find_peer_address(struct NeighbourList *neighbour,
2386 struct Session *session,
2390 struct ReadyList *head;
2391 struct ForeignAddressList *pos;
2393 head = neighbour->plugins;
2394 while (head != NULL)
2396 if (0 == strcmp (tname, head->plugin->short_name))
2402 pos = head->addresses;
2403 while ( (pos != NULL) &&
2404 ( (pos->addrlen != addrlen) ||
2405 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2407 if ( (session != NULL) &&
2408 (pos->session == session) )
2412 if ( (session != NULL) && (pos != NULL) )
2413 pos->session = session; /* learn it! */
2419 * Get the peer address struct for the given neighbour and
2420 * address. If it doesn't yet exist, create it.
2422 * @param neighbour which peer we care about
2423 * @param tname name of the transport plugin
2424 * @param session session of the plugin, or NULL for none
2425 * @param addr binary address
2426 * @param addrlen length of addr
2427 * @return NULL if we do not have a transport plugin for 'tname'
2429 static struct ForeignAddressList *
2430 add_peer_address (struct NeighbourList *neighbour,
2432 struct Session *session,
2436 struct ReadyList *head;
2437 struct ForeignAddressList *ret;
2439 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2442 head = neighbour->plugins;
2444 while (head != NULL)
2446 if (0 == strcmp (tname, head->plugin->short_name))
2452 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2453 ret->session = session;
2456 ret->addr = (const char*) &ret[1];
2457 memcpy (&ret[1], addr, addrlen);
2463 ret->addrlen = addrlen;
2464 ret->expires = GNUNET_TIME_relative_to_absolute
2465 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2466 ret->latency = GNUNET_TIME_relative_get_forever();
2468 ret->timeout = GNUNET_TIME_relative_to_absolute
2469 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2470 ret->ready_list = head;
2471 ret->next = head->addresses;
2472 head->addresses = ret;
2478 * Closure for 'add_validated_address'.
2480 struct AddValidatedAddressContext
2483 * Entry that has been validated.
2485 const struct ValidationEntry *ve;
2488 * Flag set after we have added the address so
2489 * that we terminate the iteration next time.
2496 * Callback function used to fill a buffer of max bytes with a list of
2497 * addresses in the format used by HELLOs. Should use
2498 * "GNUNET_HELLO_add_address" as a helper function.
2500 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2501 * @param max maximum number of bytes that can be written to buf
2502 * @param buf where to write the address information
2503 * @return number of bytes written, 0 to signal the
2504 * end of the iteration.
2507 add_validated_address (void *cls,
2508 size_t max, void *buf)
2510 struct AddValidatedAddressContext *avac = cls;
2511 const struct ValidationEntry *ve = avac->ve;
2513 if (GNUNET_YES == avac->done)
2515 avac->done = GNUNET_YES;
2516 return GNUNET_HELLO_add_address (ve->transport_name,
2517 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2527 * Closure for 'check_address_exists'.
2529 struct CheckAddressExistsClosure
2532 * Address to check for.
2537 * Name of the transport.
2544 struct Session *session;
2547 * Set to GNUNET_YES if the address exists.
2560 * Iterator over hash map entries. Checks if the given
2561 * validation entry is for the same address as what is given
2564 * @param cls the 'struct CheckAddressExistsClosure*'
2565 * @param key current key code (ignored)
2566 * @param value value in the hash map ('struct ValidationEntry')
2567 * @return GNUNET_YES if we should continue to
2568 * iterate (mismatch), GNUNET_NO if not (entry matched)
2571 check_address_exists (void *cls,
2572 const GNUNET_HashCode * key,
2575 struct CheckAddressExistsClosure *caec = cls;
2576 struct ValidationEntry *ve = value;
2578 if ( (0 == strcmp (caec->tname,
2579 ve->transport_name)) &&
2580 (caec->addrlen == ve->addrlen) &&
2581 (0 == memcmp (caec->addr,
2585 caec->exists = GNUNET_YES;
2588 if ( (ve->session != NULL) &&
2589 (caec->session == ve->session) )
2591 caec->exists = GNUNET_YES;
2600 * Iterator to free entries in the validation_map.
2602 * @param cls closure (unused)
2603 * @param key current key code
2604 * @param value value in the hash map (validation to abort)
2605 * @return GNUNET_YES (always)
2608 abort_validation (void *cls,
2609 const GNUNET_HashCode * key,
2612 struct ValidationEntry *va = value;
2614 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2615 GNUNET_SCHEDULER_cancel (va->timeout_task);
2616 GNUNET_free (va->transport_name);
2617 if (va->chvc != NULL)
2619 va->chvc->ve_count--;
2620 if (va->chvc->ve_count == 0)
2622 GNUNET_CONTAINER_DLL_remove (chvc_head,
2625 GNUNET_free (va->chvc);
2635 * HELLO validation cleanup task (validation failed).
2637 * @param cls the 'struct ValidationEntry' that failed
2638 * @param tc scheduler context (unused)
2641 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2643 struct ValidationEntry *va = cls;
2644 struct GNUNET_PeerIdentity pid;
2646 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2647 GNUNET_STATISTICS_update (stats,
2648 gettext_noop ("# address validation timeouts"),
2651 GNUNET_CRYPTO_hash (&va->publicKey,
2653 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2655 GNUNET_break (GNUNET_OK ==
2656 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2659 abort_validation (NULL, NULL, va);
2664 neighbour_timeout_task (void *cls,
2665 const struct GNUNET_SCHEDULER_TaskContext *tc)
2667 struct NeighbourList *n = cls;
2670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2671 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2673 GNUNET_STATISTICS_update (stats,
2674 gettext_noop ("# disconnects due to timeout"),
2677 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2678 disconnect_neighbour (n, GNUNET_NO);
2683 * Schedule the job that will cause us to send a PING to the
2684 * foreign address to evaluate its validity and latency.
2686 * @param fal address to PING
2689 schedule_next_ping (struct ForeignAddressList *fal);
2693 * Add the given address to the list of foreign addresses
2694 * available for the given peer (check for duplicates).
2696 * @param cls the respective 'struct NeighbourList' to update
2697 * @param tname name of the transport
2698 * @param expiration expiration time
2699 * @param addr the address
2700 * @param addrlen length of the address
2701 * @return GNUNET_OK (always)
2704 add_to_foreign_address_list (void *cls,
2706 struct GNUNET_TIME_Absolute expiration,
2710 struct NeighbourList *n = cls;
2711 struct ForeignAddressList *fal;
2714 GNUNET_STATISTICS_update (stats,
2715 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2719 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2722 #if DEBUG_TRANSPORT_HELLO
2723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2724 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2725 a2s (tname, addr, addrlen),
2727 GNUNET_i2s (&n->id),
2728 expiration.abs_value);
2730 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2733 GNUNET_STATISTICS_update (stats,
2734 gettext_noop ("# previously validated addresses lacking transport"),
2740 fal->expires = GNUNET_TIME_absolute_max (expiration,
2742 schedule_next_ping (fal);
2748 fal->expires = GNUNET_TIME_absolute_max (expiration,
2753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2754 "Failed to add new address for `%4s'\n",
2755 GNUNET_i2s (&n->id));
2758 if (fal->validated == GNUNET_NO)
2760 fal->validated = GNUNET_YES;
2761 GNUNET_STATISTICS_update (stats,
2762 gettext_noop ("# peer addresses considered valid"),
2766 if (try == GNUNET_YES)
2768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2769 "Have new addresses, will try to trigger transmissions.\n");
2770 try_transmission_to_peer (n);
2777 * Add addresses in validated HELLO "h" to the set of addresses
2778 * we have for this peer.
2780 * @param cls closure ('struct NeighbourList*')
2781 * @param peer id of the peer, NULL for last call
2782 * @param h hello message for the peer (can be NULL)
2783 * @param err_msg NULL if successful, otherwise contains error message
2786 add_hello_for_peer (void *cls,
2787 const struct GNUNET_PeerIdentity *peer,
2788 const struct GNUNET_HELLO_Message *h,
2789 const char *err_msg)
2791 struct NeighbourList *n = cls;
2793 if (err_msg != NULL)
2795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2796 _("Error in communication with PEERINFO service\n"));
2801 GNUNET_STATISTICS_update (stats,
2802 gettext_noop ("# outstanding peerinfo iterate requests"),
2809 return; /* no HELLO available */
2811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2812 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2816 if (GNUNET_YES != n->public_key_valid)
2818 GNUNET_HELLO_get_key (h, &n->publicKey);
2819 n->public_key_valid = GNUNET_YES;
2821 GNUNET_HELLO_iterate_addresses (h,
2823 &add_to_foreign_address_list,
2829 * Create a fresh entry in our neighbour list for the given peer.
2830 * Will try to transmit our current HELLO to the new neighbour.
2831 * Do not call this function directly, use 'setup_peer_check_blacklist.
2833 * @param peer the peer for which we create the entry
2834 * @param do_hello should we schedule transmitting a HELLO
2835 * @return the new neighbour list entry
2837 static struct NeighbourList *
2838 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2841 struct NeighbourList *n;
2842 struct TransportPlugin *tp;
2843 struct ReadyList *rl;
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "Setting up state for neighbour `%4s'\n",
2850 GNUNET_assert (our_hello != NULL);
2851 GNUNET_STATISTICS_update (stats,
2852 gettext_noop ("# active neighbours"),
2855 n = GNUNET_malloc (sizeof (struct NeighbourList));
2856 n->next = neighbours;
2860 GNUNET_TIME_relative_to_absolute
2861 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2862 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2863 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2864 MAX_BANDWIDTH_CARRY_S);
2868 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2870 rl = GNUNET_malloc (sizeof (struct ReadyList));
2872 rl->next = n->plugins;
2875 rl->addresses = NULL;
2879 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2881 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2882 &neighbour_timeout_task, n);
2885 GNUNET_STATISTICS_update (stats,
2886 gettext_noop ("# peerinfo new neighbor iterate requests"),
2889 GNUNET_STATISTICS_update (stats,
2890 gettext_noop ("# outstanding peerinfo iterate requests"),
2893 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2894 GNUNET_TIME_UNIT_FOREVER_REL,
2895 &add_hello_for_peer, n);
2897 GNUNET_STATISTICS_update (stats,
2898 gettext_noop ("# HELLO's sent to new neighbors"),
2901 transmit_to_peer (NULL, NULL, 0,
2902 HELLO_ADDRESS_EXPIRATION,
2903 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2911 * Function called after we have checked if communicating
2912 * with a given peer is acceptable.
2914 * @param cls closure
2915 * @param n NULL if communication is not acceptable
2917 typedef void (*SetupContinuation)(void *cls,
2918 struct NeighbourList *n);
2922 * Information kept for each client registered to perform
2928 * This is a linked list.
2930 struct Blacklisters *next;
2933 * This is a linked list.
2935 struct Blacklisters *prev;
2938 * Client responsible for this entry.
2940 struct GNUNET_SERVER_Client *client;
2943 * Blacklist check that we're currently performing.
2945 struct BlacklistCheck *bc;
2951 * Head of DLL of blacklisting clients.
2953 static struct Blacklisters *bl_head;
2956 * Tail of DLL of blacklisting clients.
2958 static struct Blacklisters *bl_tail;
2962 * Context we use when performing a blacklist check.
2964 struct BlacklistCheck
2968 * This is a linked list.
2970 struct BlacklistCheck *next;
2973 * This is a linked list.
2975 struct BlacklistCheck *prev;
2978 * Peer being checked.
2980 struct GNUNET_PeerIdentity peer;
2983 * Option for setup neighbour afterwards.
2988 * Continuation to call with the result.
2990 SetupContinuation cont;
2998 * Current transmission request handle for this client, or NULL if no
2999 * request is pending.
3001 struct GNUNET_CONNECTION_TransmitHandle *th;
3004 * Our current position in the blacklisters list.
3006 struct Blacklisters *bl_pos;
3009 * Current task performing the check.
3011 GNUNET_SCHEDULER_TaskIdentifier task;
3016 * Head of DLL of active blacklisting queries.
3018 static struct BlacklistCheck *bc_head;
3021 * Tail of DLL of active blacklisting queries.
3023 static struct BlacklistCheck *bc_tail;
3027 * Perform next action in the blacklist check.
3029 * @param cls the 'struct BlacklistCheck*'
3033 do_blacklist_check (void *cls,
3034 const struct GNUNET_SCHEDULER_TaskContext *tc);
3037 * Transmit blacklist query to the client.
3039 * @param cls the 'struct BlacklistCheck'
3040 * @param size number of bytes allowed
3041 * @param buf where to copy the message
3042 * @return number of bytes copied to buf
3045 transmit_blacklist_message (void *cls,
3049 struct BlacklistCheck *bc = cls;
3050 struct Blacklisters *bl;
3051 struct BlacklistMessage bm;
3056 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3057 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3062 bm.header.size = htons (sizeof (struct BlacklistMessage));
3063 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3064 bm.is_allowed = htonl (0);
3066 memcpy (buf, &bm, sizeof (bm));
3067 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3073 * Perform next action in the blacklist check.
3075 * @param cls the 'struct BlacklistCheck*'
3079 do_blacklist_check (void *cls,
3080 const struct GNUNET_SCHEDULER_TaskContext *tc)
3082 struct BlacklistCheck *bc = cls;
3083 struct Blacklisters *bl;
3085 bc->task = GNUNET_SCHEDULER_NO_TASK;
3089 bc->cont (bc->cont_cls,
3090 setup_new_neighbour (&bc->peer, bc->do_hello));
3097 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3098 sizeof (struct BlacklistMessage),
3099 GNUNET_TIME_UNIT_FOREVER_REL,
3100 &transmit_blacklist_message,
3107 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3108 * does not yet exist, check the blacklist. If the blacklist says creating
3109 * one is acceptable, create one and call the continuation; otherwise
3110 * call the continuation with NULL.
3112 * @param peer peer to setup or look up a struct NeighbourList for
3113 * @param do_hello should we also schedule sending our HELLO to the peer
3114 * if this is a new record
3115 * @param cont function to call with the 'struct NeigbhbourList*'
3116 * @param cont_cls closure for cont
3119 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3121 SetupContinuation cont,
3124 struct NeighbourList *n;
3125 struct BlacklistCheck *bc;
3127 n = find_neighbour(peer);
3134 if (bl_head == NULL)
3137 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3139 setup_new_neighbour(peer, do_hello);
3142 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3143 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3145 bc->do_hello = do_hello;
3147 bc->cont_cls = cont_cls;
3148 bc->bl_pos = bl_head;
3149 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3155 * Function called with the result of querying a new blacklister about
3156 * it being allowed (or not) to continue to talk to an existing neighbour.
3158 * @param cls the original 'struct NeighbourList'
3159 * @param n NULL if we need to disconnect
3162 confirm_or_drop_neighbour (void *cls,
3163 struct NeighbourList *n)
3165 struct NeighbourList * orig = cls;
3169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3170 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3171 "confirm_or_drop_neighboUr");
3172 disconnect_neighbour (orig, GNUNET_NO);
3178 * Handle a request to start a blacklist.
3180 * @param cls closure (always NULL)
3181 * @param client identification of the client
3182 * @param message the actual message
3185 handle_blacklist_init (void *cls,
3186 struct GNUNET_SERVER_Client *client,
3187 const struct GNUNET_MessageHeader *message)
3189 struct Blacklisters *bl;
3190 struct BlacklistCheck *bc;
3191 struct NeighbourList *n;
3196 if (bl->client == client)
3199 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3204 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3205 bl->client = client;
3206 GNUNET_SERVER_client_keep (client);
3207 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3208 /* confirm that all existing connections are OK! */
3212 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3213 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3215 bc->do_hello = GNUNET_NO;
3216 bc->cont = &confirm_or_drop_neighbour;
3219 if (n == neighbours) /* all would wait for the same client, no need to
3220 create more than just the first task right now */
3221 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3229 * Handle a request to blacklist a peer.
3231 * @param cls closure (always NULL)
3232 * @param client identification of the client
3233 * @param message the actual message
3236 handle_blacklist_reply (void *cls,
3237 struct GNUNET_SERVER_Client *client,
3238 const struct GNUNET_MessageHeader *message)
3240 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3241 struct Blacklisters *bl;
3242 struct BlacklistCheck *bc;
3245 while ( (bl != NULL) &&
3246 (bl->client != client) )
3250 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3255 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3257 bc->cont (bc->cont_cls, NULL);
3258 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3263 bc->bl_pos = bc->bl_pos->next;
3264 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3267 /* check if any other bc's are waiting for this blacklister */
3271 if ( (bc->bl_pos == bl) &&
3272 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3273 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3281 * Send periodic PING messages to a given foreign address.
3283 * @param cls our 'struct PeriodicValidationContext*'
3284 * @param tc task context
3287 send_periodic_ping (void *cls,
3288 const struct GNUNET_SCHEDULER_TaskContext *tc)
3290 struct ForeignAddressList *peer_address = cls;
3291 struct TransportPlugin *tp;
3292 struct ValidationEntry *va;
3293 struct NeighbourList *neighbour;
3294 struct TransportPingMessage ping;
3295 struct CheckAddressExistsClosure caec;
3297 uint16_t hello_size;
3301 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3302 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3304 tp = peer_address->ready_list->plugin;
3305 neighbour = peer_address->ready_list->neighbour;
3306 if (GNUNET_YES != neighbour->public_key_valid)
3308 /* no public key yet, try again later */
3309 schedule_next_ping (peer_address);
3312 caec.addr = peer_address->addr;
3313 caec.addrlen = peer_address->addrlen;
3314 caec.tname = tp->short_name;
3315 caec.session = peer_address->session;
3316 caec.exists = GNUNET_NO;
3317 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3318 &check_address_exists,
3320 if (caec.exists == GNUNET_YES)
3322 /* During validation attempts we will likely trigger the other
3323 peer trying to validate our address which in turn will cause
3324 it to send us its HELLO, so we expect to hit this case rather
3325 frequently. Only print something if we are very verbose. */
3326 #if DEBUG_TRANSPORT > 1
3327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3328 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3329 (peer_address->addr != NULL)
3330 ? a2s (tp->short_name,
3332 peer_address->addrlen)
3335 GNUNET_i2s (&neighbour->id));
3337 schedule_next_ping (peer_address);
3340 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3341 va->transport_name = GNUNET_strdup (tp->short_name);
3342 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3344 va->send_time = GNUNET_TIME_absolute_get();
3345 va->session = peer_address->session;
3346 if (peer_address->addr != NULL)
3348 va->addr = (const void*) &va[1];
3349 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3350 va->addrlen = peer_address->addrlen;
3352 memcpy(&va->publicKey,
3353 &neighbour->publicKey,
3354 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3356 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3357 &timeout_hello_validation,
3359 GNUNET_CONTAINER_multihashmap_put (validation_map,
3360 &neighbour->id.hashPubKey,
3362 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3364 if (peer_address->validated != GNUNET_YES)
3365 hello_size = GNUNET_HELLO_size(our_hello);
3369 tsize = sizeof(struct TransportPingMessage) + hello_size;
3371 if (peer_address->addr != NULL)
3373 slen = strlen (tp->short_name) + 1;
3374 tsize += slen + peer_address->addrlen;
3378 slen = 0; /* make gcc happy */
3380 message_buf = GNUNET_malloc(tsize);
3381 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3382 ping.challenge = htonl(va->challenge);
3383 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3384 if (peer_address->validated != GNUNET_YES)
3386 memcpy(message_buf, our_hello, hello_size);
3389 if (peer_address->addr != NULL)
3391 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3392 peer_address->addrlen +
3394 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3397 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3399 peer_address->addrlen);
3403 ping.header.size = htons(sizeof(struct TransportPingMessage));
3406 memcpy(&message_buf[hello_size],
3408 sizeof(struct TransportPingMessage));
3410 #if DEBUG_TRANSPORT_REVALIDATION
3411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3412 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3413 (peer_address->addr != NULL)
3414 ? a2s (peer_address->plugin->short_name,
3416 peer_address->addrlen)
3419 GNUNET_i2s (&neighbour->id),
3420 "HELLO", hello_size,
3423 if (peer_address->validated != GNUNET_YES)
3424 GNUNET_STATISTICS_update (stats,
3425 gettext_noop ("# PING with HELLO messages sent"),
3429 GNUNET_STATISTICS_update (stats,
3430 gettext_noop ("# PING without HELLO messages sent"),
3433 GNUNET_STATISTICS_update (stats,
3434 gettext_noop ("# PING messages sent for re-validation"),
3437 transmit_to_peer (NULL, peer_address,
3438 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3439 HELLO_VERIFICATION_TIMEOUT,
3441 GNUNET_YES, neighbour);
3442 GNUNET_free(message_buf);
3443 schedule_next_ping (peer_address);
3448 * Schedule the job that will cause us to send a PING to the
3449 * foreign address to evaluate its validity and latency.
3451 * @param fal address to PING
3454 schedule_next_ping (struct ForeignAddressList *fal)
3456 struct GNUNET_TIME_Relative delay;
3458 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3460 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3461 delay.rel_value /= 2; /* do before expiration */
3462 delay = GNUNET_TIME_relative_min (delay,
3463 LATENCY_EVALUATION_MAX_DELAY);
3464 if (GNUNET_YES != fal->estimated)
3466 delay = GNUNET_TIME_UNIT_ZERO;
3467 fal->estimated = GNUNET_YES;
3469 if (GNUNET_YES == fal->connected)
3471 delay = GNUNET_TIME_relative_min (delay,
3472 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3474 /* FIXME: also adjust delay based on how close the last
3475 observed latency is to the latency of the best alternative */
3476 /* bound how fast we can go */
3477 delay = GNUNET_TIME_relative_max (delay,
3478 GNUNET_TIME_UNIT_SECONDS);
3479 /* randomize a bit (to avoid doing all at the same time) */
3480 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3481 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3482 &send_periodic_ping,
3490 * Function that will be called if we receive some payload
3491 * from another peer.
3493 * @param message the payload
3494 * @param n peer who claimed to be the sender
3497 handle_payload_message (const struct GNUNET_MessageHeader *message,
3498 struct NeighbourList *n)
3500 struct InboundMessage *im;
3501 struct TransportClient *cpos;
3504 msize = ntohs (message->size);
3505 if (n->received_pong == GNUNET_NO)
3507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3508 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3509 ntohs (message->type),
3510 ntohs (message->size),
3511 GNUNET_i2s (&n->id));
3512 GNUNET_free_non_null (n->pre_connect_message_buffer);
3513 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3514 memcpy (n->pre_connect_message_buffer, message, msize);
3519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3520 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3521 ntohs (message->type),
3522 ntohs (message->size),
3523 GNUNET_i2s (&n->id));
3525 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3528 n->quota_violation_count++;
3530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3531 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3532 n->in_tracker.available_bytes_per_s__,
3533 n->quota_violation_count);
3535 /* Discount 32k per violation */
3536 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3541 if (n->quota_violation_count > 0)
3543 /* try to add 32k back */
3544 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3546 n->quota_violation_count--;
3549 GNUNET_STATISTICS_update (stats,
3550 gettext_noop ("# payload received from other peers"),
3553 /* transmit message to all clients */
3554 uint32_t ats_count = 2;
3555 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3556 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3559 im = GNUNET_malloc (size);
3560 im->header.size = htons (size);
3561 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3563 im->ats_count = htonl(ats_count);
3564 /* Setting ATS data */
3565 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3566 (&(im->ats))[0].value = htonl (n->distance);
3567 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3568 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3569 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3570 (&(im->ats))[ats_count].value = htonl (0);
3572 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3574 while (cpos != NULL)
3576 transmit_to_client (cpos, &im->header, GNUNET_YES);
3584 * Iterator over hash map entries. Checks if the given validation
3585 * entry is for the same challenge as what is given in the PONG.
3587 * @param cls the 'struct TransportPongMessage*'
3588 * @param key peer identity
3589 * @param value value in the hash map ('struct ValidationEntry')
3590 * @return GNUNET_YES if we should continue to
3591 * iterate (mismatch), GNUNET_NO if not (entry matched)
3594 check_pending_validation (void *cls,
3595 const GNUNET_HashCode * key,
3598 const struct TransportPongMessage *pong = cls;
3599 struct ValidationEntry *ve = value;
3600 struct AddValidatedAddressContext avac;
3601 unsigned int challenge = ntohl(pong->challenge);
3602 struct GNUNET_HELLO_Message *hello;
3603 struct GNUNET_PeerIdentity target;
3604 struct NeighbourList *n;
3605 struct ForeignAddressList *fal;
3606 struct OwnAddressList *oal;
3607 struct TransportPlugin *tp;
3608 struct GNUNET_MessageHeader *prem;
3614 ps = ntohs (pong->header.size);
3615 if (ps < sizeof (struct TransportPongMessage))
3617 GNUNET_break_op (0);
3620 addr = (const char*) &pong[1];
3621 slen = strlen (ve->transport_name) + 1;
3622 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3623 (ve->challenge != challenge) ||
3624 (addr[slen-1] != '\0') ||
3625 (0 != strcmp (addr, ve->transport_name)) ||
3626 (ntohl (pong->purpose.size)
3627 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3629 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3630 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3635 alen = ps - sizeof (struct TransportPongMessage) - slen;
3636 switch (ntohl (pong->purpose.purpose))
3638 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3639 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3640 (0 != memcmp (&addr[slen],
3644 return GNUNET_YES; /* different entry, keep trying! */
3646 if (0 != memcmp (&pong->pid,
3648 sizeof (struct GNUNET_PeerIdentity)))
3650 GNUNET_break_op (0);
3654 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3659 GNUNET_break_op (0);
3664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3665 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3667 a2s (ve->transport_name,
3668 (const struct sockaddr *) ve->addr,
3670 ve->transport_name);
3673 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3674 if (0 != memcmp (&pong->pid,
3676 sizeof (struct GNUNET_PeerIdentity)))
3678 GNUNET_break_op (0);
3681 if (ve->addrlen != 0)
3683 /* must have been for a different validation entry */
3686 tp = find_transport (ve->transport_name);
3692 oal = tp->addresses;
3695 if ( (oal->addrlen == alen) &&
3696 (0 == memcmp (&oal[1],
3704 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3705 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3706 a2s (ve->transport_name,
3712 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3717 GNUNET_break_op (0);
3722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3723 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3725 a2s (ve->transport_name,
3728 ve->transport_name);
3732 GNUNET_break_op (0);
3735 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3737 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3738 _("Received expired signature. Check system time.\n"));
3741 GNUNET_STATISTICS_update (stats,
3742 gettext_noop ("# address validation successes"),
3745 /* create the updated HELLO */
3746 GNUNET_CRYPTO_hash (&ve->publicKey,
3747 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3748 &target.hashPubKey);
3749 if (ve->addr != NULL)
3751 avac.done = GNUNET_NO;
3753 hello = GNUNET_HELLO_create (&ve->publicKey,
3754 &add_validated_address,
3756 GNUNET_PEERINFO_add_peer (peerinfo,
3758 GNUNET_free (hello);
3760 n = find_neighbour (&target);
3763 n->publicKey = ve->publicKey;
3764 n->public_key_valid = GNUNET_YES;
3765 fal = add_peer_address (n,
3770 GNUNET_assert (fal != NULL);
3771 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3772 fal->validated = GNUNET_YES;
3773 mark_address_connected (fal);
3774 GNUNET_STATISTICS_update (stats,
3775 gettext_noop ("# peer addresses considered valid"),
3778 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3779 schedule_next_ping (fal);
3780 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3781 n->latency = fal->latency;
3783 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3785 n->distance = fal->distance;
3786 if (GNUNET_NO == n->received_pong)
3788 n->received_pong = GNUNET_YES;
3790 notify_clients_connect (&target, n->latency, n->distance);
3791 if (NULL != (prem = n->pre_connect_message_buffer))
3793 n->pre_connect_message_buffer = NULL;
3794 handle_payload_message (prem, n);
3798 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3800 GNUNET_SCHEDULER_cancel (n->retry_task);
3801 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3802 try_transmission_to_peer (n);
3806 /* clean up validation entry */
3807 GNUNET_assert (GNUNET_YES ==
3808 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3811 abort_validation (NULL, NULL, ve);
3817 * Function that will be called if we receive a validation
3818 * of an address challenge that we transmitted to another
3819 * peer. Note that the validation should only be considered
3820 * acceptable if the challenge matches AND if the sender
3821 * address is at least a plausible address for this peer
3822 * (otherwise we may be seeing a MiM attack).
3824 * @param cls closure
3825 * @param message the pong message
3826 * @param peer who responded to our challenge
3827 * @param sender_address string describing our sender address (as observed
3828 * by the other peer in binary format)
3829 * @param sender_address_len number of bytes in 'sender_address'
3832 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3833 const struct GNUNET_PeerIdentity *peer,
3834 const char *sender_address,
3835 size_t sender_address_len)
3837 #if DEBUG_TRANSPORT > 1
3838 /* we get tons of these that just get discarded, only log
3839 if we are quite verbose */
3840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3841 "Receiving `%s' message from `%4s'.\n", "PONG",
3844 GNUNET_STATISTICS_update (stats,
3845 gettext_noop ("# PONG messages received"),
3848 if (GNUNET_SYSERR !=
3849 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3851 &check_pending_validation,
3854 /* This is *expected* to happen a lot since we send
3855 PONGs to *all* known addresses of the sender of
3856 the PING, so most likely we get multiple PONGs
3857 per PING, and all but the first PONG will end up
3858 here. So really we should not print anything here
3859 unless we want to be very, very verbose... */
3860 #if DEBUG_TRANSPORT > 2
3861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3862 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3874 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3876 * @param cls the 'struct ValidationEntry*'
3877 * @param neighbour neighbour to validate, NULL if validation failed
3880 transmit_hello_and_ping (void *cls,
3881 struct NeighbourList *neighbour)
3883 struct ValidationEntry *va = cls;
3884 struct ForeignAddressList *peer_address;
3885 struct TransportPingMessage ping;
3886 uint16_t hello_size;
3889 struct GNUNET_PeerIdentity id;
3892 GNUNET_CRYPTO_hash (&va->publicKey,
3893 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3895 if (neighbour == NULL)
3897 /* FIXME: stats... */
3898 GNUNET_break (GNUNET_OK ==
3899 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3902 abort_validation (NULL, NULL, va);
3905 neighbour->publicKey = va->publicKey;
3906 neighbour->public_key_valid = GNUNET_YES;
3907 peer_address = add_peer_address (neighbour,
3908 va->transport_name, NULL,
3909 (const void*) &va[1],
3911 if (peer_address == NULL)
3913 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3914 "Failed to add peer `%4s' for plugin `%s'\n",
3915 GNUNET_i2s (&neighbour->id),
3916 va->transport_name);
3917 GNUNET_break (GNUNET_OK ==
3918 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3921 abort_validation (NULL, NULL, va);
3924 hello_size = GNUNET_HELLO_size(our_hello);
3925 slen = strlen(va->transport_name) + 1;
3926 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3927 message_buf = GNUNET_malloc(tsize);
3928 ping.challenge = htonl(va->challenge);
3929 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3930 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3931 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3932 memcpy(message_buf, our_hello, hello_size);
3933 memcpy(&message_buf[hello_size],
3935 sizeof(struct TransportPingMessage));
3936 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3939 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3944 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3947 : a2s (va->transport_name,
3948 (const void*) &va[1], va->addrlen),
3950 GNUNET_i2s (&neighbour->id),
3951 "HELLO", hello_size,
3952 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3955 GNUNET_STATISTICS_update (stats,
3956 gettext_noop ("# PING messages sent for initial validation"),
3959 transmit_to_peer (NULL, peer_address,
3960 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3961 HELLO_VERIFICATION_TIMEOUT,
3963 GNUNET_YES, neighbour);
3964 GNUNET_free(message_buf);
3969 * Check if the given address is already being validated; if not,
3970 * append the given address to the list of entries that are being be
3971 * validated and initiate validation.
3973 * @param cls closure ('struct CheckHelloValidatedContext *')
3974 * @param tname name of the transport
3975 * @param expiration expiration time
3976 * @param addr the address
3977 * @param addrlen length of the address
3978 * @return GNUNET_OK (always)
3981 run_validation (void *cls,
3983 struct GNUNET_TIME_Absolute expiration,
3987 struct CheckHelloValidatedContext *chvc = cls;
3988 struct GNUNET_PeerIdentity id;
3989 struct TransportPlugin *tp;
3990 struct ValidationEntry *va;
3991 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3992 struct CheckAddressExistsClosure caec;
3993 struct OwnAddressList *oal;
3995 GNUNET_assert (addr != NULL);
3997 GNUNET_STATISTICS_update (stats,
3998 gettext_noop ("# peer addresses scheduled for validation"),
4001 tp = find_transport (tname);
4004 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4005 GNUNET_ERROR_TYPE_BULK,
4007 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4009 GNUNET_STATISTICS_update (stats,
4010 gettext_noop ("# peer addresses not validated (plugin not available)"),
4015 /* check if this is one of our own addresses */
4016 oal = tp->addresses;
4019 if ( (oal->addrlen == addrlen) &&
4020 (0 == memcmp (&oal[1],
4024 /* not plausible, this address is equivalent to our own address! */
4025 GNUNET_STATISTICS_update (stats,
4026 gettext_noop ("# peer addresses not validated (loopback)"),
4033 GNUNET_HELLO_get_key (chvc->hello, &pk);
4034 GNUNET_CRYPTO_hash (&pk,
4036 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4039 if (is_blacklisted(&id, tp))
4042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4043 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4051 caec.addrlen = addrlen;
4052 caec.session = NULL;
4054 caec.exists = GNUNET_NO;
4055 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4056 &check_address_exists,
4058 if (caec.exists == GNUNET_YES)
4060 /* During validation attempts we will likely trigger the other
4061 peer trying to validate our address which in turn will cause
4062 it to send us its HELLO, so we expect to hit this case rather
4063 frequently. Only print something if we are very verbose. */
4064 #if DEBUG_TRANSPORT > 1
4065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4066 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4067 a2s (tname, addr, addrlen),
4071 GNUNET_STATISTICS_update (stats,
4072 gettext_noop ("# peer addresses not validated (in progress)"),
4077 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4080 va->transport_name = GNUNET_strdup (tname);
4081 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4083 va->send_time = GNUNET_TIME_absolute_get();
4084 va->addr = (const void*) &va[1];
4085 memcpy (&va[1], addr, addrlen);
4086 va->addrlen = addrlen;
4087 GNUNET_HELLO_get_key (chvc->hello,
4089 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4090 &timeout_hello_validation,
4092 GNUNET_CONTAINER_multihashmap_put (validation_map,
4095 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4096 setup_peer_check_blacklist (&id, GNUNET_NO,
4097 &transmit_hello_and_ping,
4104 * Check if addresses in validated hello "h" overlap with
4105 * those in "chvc->hello" and validate the rest.
4107 * @param cls closure
4108 * @param peer id of the peer, NULL for last call
4109 * @param h hello message for the peer (can be NULL)
4110 * @param err_msg NULL if successful, otherwise contains error message
4113 check_hello_validated (void *cls,
4114 const struct GNUNET_PeerIdentity *peer,
4115 const struct GNUNET_HELLO_Message *h,
4116 const char *err_msg)
4118 struct CheckHelloValidatedContext *chvc = cls;
4119 struct GNUNET_HELLO_Message *plain_hello;
4120 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4121 struct GNUNET_PeerIdentity target;
4122 struct NeighbourList *n;
4124 if (err_msg != NULL)
4126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4127 _("Error in communication with PEERINFO service\n"));
4133 GNUNET_STATISTICS_update (stats,
4134 gettext_noop ("# outstanding peerinfo iterate requests"),
4138 if (GNUNET_NO == chvc->hello_known)
4140 /* notify PEERINFO about the peer now, so that we at least
4141 have the public key if some other component needs it */
4142 GNUNET_HELLO_get_key (chvc->hello, &pk);
4143 GNUNET_CRYPTO_hash (&pk,
4144 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4145 &target.hashPubKey);
4146 plain_hello = GNUNET_HELLO_create (&pk,
4149 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4150 GNUNET_free (plain_hello);
4151 #if DEBUG_TRANSPORT_HELLO
4152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4153 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4155 GNUNET_i2s (&target));
4157 GNUNET_STATISTICS_update (stats,
4158 gettext_noop ("# new HELLOs requiring full validation"),
4161 GNUNET_HELLO_iterate_addresses (chvc->hello,
4168 GNUNET_STATISTICS_update (stats,
4169 gettext_noop ("# duplicate HELLO (peer known)"),
4174 if (chvc->ve_count == 0)
4176 GNUNET_CONTAINER_DLL_remove (chvc_head,
4185 #if DEBUG_TRANSPORT_HELLO
4186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4187 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4191 chvc->hello_known = GNUNET_YES;
4192 n = find_neighbour (peer);
4195 #if DEBUG_TRANSPORT_HELLO
4196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4197 "Calling hello_iterate_addresses for %s!\n",
4200 GNUNET_HELLO_iterate_addresses (h,
4202 &add_to_foreign_address_list,
4204 try_transmission_to_peer (n);
4208 #if DEBUG_TRANSPORT_HELLO
4209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4210 "No existing neighbor record for %s!\n",
4213 GNUNET_STATISTICS_update (stats,
4214 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4218 GNUNET_STATISTICS_update (stats,
4219 gettext_noop ("# HELLO validations (update case)"),
4222 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4224 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4231 * Process HELLO-message.
4233 * @param plugin transport involved, may be NULL
4234 * @param message the actual message
4235 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4238 process_hello (struct TransportPlugin *plugin,
4239 const struct GNUNET_MessageHeader *message)
4242 struct GNUNET_PeerIdentity target;
4243 const struct GNUNET_HELLO_Message *hello;
4244 struct CheckHelloValidatedContext *chvc;
4245 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4246 #if DEBUG_TRANSPORT_HELLO > 2
4249 hsize = ntohs (message->size);
4250 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4251 (hsize < sizeof (struct GNUNET_MessageHeader)))
4254 return GNUNET_SYSERR;
4256 GNUNET_STATISTICS_update (stats,
4257 gettext_noop ("# HELLOs received for validation"),
4261 /* first, check if load is too high */
4262 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4264 GNUNET_STATISTICS_update (stats,
4265 gettext_noop ("# HELLOs ignored due to high load"),
4268 #if DEBUG_TRANSPORT_HELLO
4269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4270 "Ignoring `%s' for `%4s', load too high.\n",
4272 GNUNET_i2s (&target));
4276 hello = (const struct GNUNET_HELLO_Message *) message;
4277 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4279 #if DEBUG_TRANSPORT_HELLO
4280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4281 "Unable to get public key from `%s' for `%4s'!\n",
4283 GNUNET_i2s (&target));
4285 GNUNET_break_op (0);
4286 return GNUNET_SYSERR;
4289 GNUNET_CRYPTO_hash (&publicKey,
4290 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4291 &target.hashPubKey);
4293 #if DEBUG_TRANSPORT_HELLO
4294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4295 "Received `%s' message for `%4s'\n",
4297 GNUNET_i2s (&target));
4300 if (0 == memcmp (&my_identity,
4302 sizeof (struct GNUNET_PeerIdentity)))
4304 GNUNET_STATISTICS_update (stats,
4305 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4311 while (NULL != chvc)
4313 if (GNUNET_HELLO_equals (hello,
4315 GNUNET_TIME_absolute_get ()).abs_value > 0)
4317 #if DEBUG_TRANSPORT_HELLO > 2
4318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4319 "Received duplicate `%s' message for `%4s'; ignored\n",
4321 GNUNET_i2s (&target));
4323 return GNUNET_OK; /* validation already pending */
4325 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4326 GNUNET_break (0 != memcmp (hello, chvc->hello,
4327 GNUNET_HELLO_size(hello)));
4332 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4333 if ((NULL != temp_neighbor))
4335 fprintf(stderr, "Already know peer, ignoring hello\n");
4340 #if DEBUG_TRANSPORT_HELLO > 2
4343 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4345 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4348 GNUNET_i2s (&target),
4350 GNUNET_HELLO_size(hello));
4354 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4356 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4357 memcpy (&chvc[1], hello, hsize);
4358 GNUNET_CONTAINER_DLL_insert (chvc_head,
4361 /* finally, check if HELLO was previously validated
4362 (continuation will then schedule actual validation) */
4363 GNUNET_STATISTICS_update (stats,
4364 gettext_noop ("# peerinfo process hello iterate requests"),
4367 GNUNET_STATISTICS_update (stats,
4368 gettext_noop ("# outstanding peerinfo iterate requests"),
4371 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4373 HELLO_VERIFICATION_TIMEOUT,
4374 &check_hello_validated, chvc);
4380 * The peer specified by the given neighbour has timed-out or a plugin
4381 * has disconnected. We may either need to do nothing (other plugins
4382 * still up), or trigger a full disconnect and clean up. This
4383 * function updates our state and does the necessary notifications.
4384 * Also notifies our clients that the neighbour is now officially
4387 * @param n the neighbour list entry for the peer
4388 * @param check GNUNET_YES to check if ALL addresses for this peer
4389 * are gone, GNUNET_NO to force a disconnect of the peer
4390 * regardless of whether other addresses exist.
4393 disconnect_neighbour (struct NeighbourList *n, int check)
4395 struct ReadyList *rpos;
4396 struct NeighbourList *npos;
4397 struct NeighbourList *nprev;
4398 struct MessageQueue *mq;
4399 struct ForeignAddressList *peer_addresses;
4400 struct ForeignAddressList *peer_pos;
4402 if (GNUNET_YES == check)
4405 while (NULL != rpos)
4407 peer_addresses = rpos->addresses;
4408 while (peer_addresses != NULL)
4410 if (GNUNET_YES == peer_addresses->connected)
4412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4413 "NOT Disconnecting from `%4s', still have live addresses!\n",
4414 GNUNET_i2s (&n->id));
4415 return; /* still connected */
4417 peer_addresses = peer_addresses->next;
4423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4424 "Disconnecting from `%4s'\n",
4425 GNUNET_i2s (&n->id));
4427 /* remove n from neighbours list */
4430 while ((npos != NULL) && (npos != n))
4435 GNUNET_assert (npos != NULL);
4437 neighbours = n->next;
4439 nprev->next = n->next;
4441 /* notify all clients about disconnect */
4442 if (GNUNET_YES == n->received_pong)
4443 notify_clients_disconnect (&n->id);
4445 /* clean up all plugins, cancel connections and pending transmissions */
4446 while (NULL != (rpos = n->plugins))
4448 n->plugins = rpos->next;
4449 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4450 while (rpos->addresses != NULL)
4452 peer_pos = rpos->addresses;
4453 rpos->addresses = peer_pos->next;
4454 if (peer_pos->connected == GNUNET_YES)
4455 GNUNET_STATISTICS_update (stats,
4456 gettext_noop ("# connected addresses"),
4459 if (GNUNET_YES == peer_pos->validated)
4460 GNUNET_STATISTICS_update (stats,
4461 gettext_noop ("# peer addresses considered valid"),
4464 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4466 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4467 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4469 GNUNET_free(peer_pos);
4474 /* free all messages on the queue */
4475 while (NULL != (mq = n->messages_head))
4477 GNUNET_STATISTICS_update (stats,
4478 gettext_noop ("# bytes in message queue for other peers"),
4479 - (int64_t) mq->message_buf_size,
4481 GNUNET_STATISTICS_update (stats,
4482 gettext_noop ("# bytes discarded due to disconnect"),
4483 mq->message_buf_size,
4485 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4488 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4490 sizeof(struct GNUNET_PeerIdentity)));
4493 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4495 GNUNET_SCHEDULER_cancel (n->timeout_task);
4496 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4498 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4500 GNUNET_SCHEDULER_cancel (n->retry_task);
4501 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4503 if (n->piter != NULL)
4505 GNUNET_PEERINFO_iterate_cancel (n->piter);
4506 GNUNET_STATISTICS_update (stats,
4507 gettext_noop ("# outstanding peerinfo iterate requests"),
4512 /* finally, free n itself */
4513 GNUNET_STATISTICS_update (stats,
4514 gettext_noop ("# active neighbours"),
4517 GNUNET_free_non_null (n->pre_connect_message_buffer);
4523 * We have received a PING message from someone. Need to send a PONG message
4524 * in response to the peer by any means necessary.
4527 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4528 const struct GNUNET_PeerIdentity *peer,
4529 struct Session *session,
4530 const char *sender_address,
4531 uint16_t sender_address_len)
4533 struct TransportPlugin *plugin = cls;
4534 struct SessionHeader *session_header = (struct SessionHeader*) session;
4535 struct TransportPingMessage *ping;
4536 struct TransportPongMessage *pong;
4537 struct NeighbourList *n;
4538 struct ReadyList *rl;
4539 struct ForeignAddressList *fal;
4540 struct OwnAddressList *oal;
4545 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4547 GNUNET_break_op (0);
4548 return GNUNET_SYSERR;
4551 ping = (struct TransportPingMessage *) message;
4552 if (0 != memcmp (&ping->target,
4553 plugin->env.my_identity,
4554 sizeof (struct GNUNET_PeerIdentity)))
4556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4557 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4559 (sender_address != NULL)
4560 ? a2s (plugin->short_name,
4561 (const struct sockaddr *)sender_address,
4564 GNUNET_i2s (&ping->target));
4565 return GNUNET_SYSERR;
4568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4569 "Processing `%s' from `%s'\n",
4571 (sender_address != NULL)
4572 ? a2s (plugin->short_name,
4573 (const struct sockaddr *)sender_address,
4577 GNUNET_STATISTICS_update (stats,
4578 gettext_noop ("# PING messages received"),
4581 addr = (const char*) &ping[1];
4582 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4583 slen = strlen (plugin->short_name) + 1;
4586 /* peer wants to confirm that we have an outbound connection to him */
4587 if (session == NULL)
4589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4590 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4592 return GNUNET_SYSERR;
4594 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4595 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4596 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4597 pong->purpose.size =
4598 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4600 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4601 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4602 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4603 pong->challenge = ping->challenge;
4604 pong->addrlen = htonl(sender_address_len + slen);
4607 sizeof(struct GNUNET_PeerIdentity));
4611 if ((sender_address!=NULL) && (sender_address_len > 0))
4612 memcpy (&((char*)&pong[1])[slen],
4614 sender_address_len);
4615 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4617 /* create / update cached sig */
4619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4620 "Creating PONG signature to indicate active connection.\n");
4622 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4623 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4624 GNUNET_assert (GNUNET_OK ==
4625 GNUNET_CRYPTO_rsa_sign (my_private_key,
4627 &session_header->pong_signature));
4631 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4633 memcpy (&pong->signature,
4634 &session_header->pong_signature,
4635 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4641 /* peer wants to confirm that this is one of our addresses */
4645 plugin->api->check_address (plugin->api->cls,
4649 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4650 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4651 a2s (plugin->short_name,
4656 oal = plugin->addresses;
4659 if ( (oal->addrlen == alen) &&
4666 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4667 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4668 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4669 pong->purpose.size =
4670 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4672 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4673 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4674 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4675 pong->challenge = ping->challenge;
4676 pong->addrlen = htonl(alen + slen);
4679 sizeof(struct GNUNET_PeerIdentity));
4680 memcpy (&pong[1], plugin->short_name, slen);
4681 memcpy (&((char*)&pong[1])[slen], addr, alen);
4682 if ( (oal != NULL) &&
4683 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4685 /* create / update cached sig */
4687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4688 "Creating PONG signature to indicate ownership.\n");
4690 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4691 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4692 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4693 GNUNET_assert (GNUNET_OK ==
4694 GNUNET_CRYPTO_rsa_sign (my_private_key,
4696 &oal->pong_signature));
4697 memcpy (&pong->signature,
4698 &oal->pong_signature,
4699 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4701 else if (oal == NULL)
4703 /* not using cache (typically DV-only) */
4704 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4705 GNUNET_assert (GNUNET_OK ==
4706 GNUNET_CRYPTO_rsa_sign (my_private_key,
4712 /* can used cached version */
4713 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4714 memcpy (&pong->signature,
4715 &oal->pong_signature,
4716 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4719 n = find_neighbour(peer);
4720 GNUNET_assert (n != NULL);
4721 /* first try reliable response transmission */
4725 fal = rl->addresses;
4728 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4731 ntohs (pong->header.size),
4732 TRANSPORT_PONG_PRIORITY,
4733 HELLO_VERIFICATION_TIMEOUT,
4741 GNUNET_STATISTICS_update (stats,
4742 gettext_noop ("# PONGs unicast via reliable transport"),
4752 /* no reliable method found, do multicast */
4753 GNUNET_STATISTICS_update (stats,
4754 gettext_noop ("# PONGs multicast to all available addresses"),
4760 fal = rl->addresses;
4763 transmit_to_peer(NULL, fal,
4764 TRANSPORT_PONG_PRIORITY,
4765 HELLO_VERIFICATION_TIMEOUT,
4767 ntohs(pong->header.size),
4780 * Function called by the plugin for each received message.
4781 * Update data volumes, possibly notify plugins about
4782 * reducing the rate at which they read from the socket
4783 * and generally forward to our receive callback.
4785 * @param cls the "struct TransportPlugin *" we gave to the plugin
4786 * @param peer (claimed) identity of the other peer
4787 * @param message the message, NULL if we only care about
4788 * learning about the delay until we should receive again
4789 * @param ats_data information for automatic transport selection
4790 * @param ats_count number of elements in ats not including 0-terminator
4791 * @param session identifier used for this session (can be NULL)
4792 * @param sender_address binary address of the sender (if observed)
4793 * @param sender_address_len number of bytes in sender_address
4794 * @return how long in ms the plugin should wait until receiving more data
4795 * (plugins that do not support this, can ignore the return value)
4797 static struct GNUNET_TIME_Relative
4798 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4799 const struct GNUNET_MessageHeader *message,
4800 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4802 struct Session *session,
4803 const char *sender_address,
4804 uint16_t sender_address_len)
4806 struct TransportPlugin *plugin = cls;
4807 struct ReadyList *service_context;
4808 struct ForeignAddressList *peer_address;
4810 struct NeighbourList *n;
4811 struct GNUNET_TIME_Relative ret;
4812 if (is_blacklisted (peer, plugin))
4813 return GNUNET_TIME_UNIT_FOREVER_REL;
4817 n = find_neighbour (peer);
4819 n = setup_new_neighbour (peer, GNUNET_YES);
4820 service_context = n->plugins;
4821 while ((service_context != NULL) && (plugin != service_context->plugin))
4822 service_context = service_context->next;
4823 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4824 peer_address = NULL;
4826 for (c=0; c<ats_count; c++)
4828 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4830 distance = ntohl(ats_data[c].value);
4833 /* notify ATS about incoming data */
4834 ats_notify_ats_data(peer, ats_data);
4836 if (message != NULL)
4838 if ( (session != NULL) ||
4839 (sender_address != NULL) )
4840 peer_address = add_peer_address (n,
4844 sender_address_len);
4845 if (peer_address != NULL)
4847 peer_address->distance = distance;
4848 if (GNUNET_YES == peer_address->validated)
4849 mark_address_connected (peer_address);
4850 peer_address->timeout
4852 GNUNET_TIME_relative_to_absolute
4853 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4854 schedule_next_ping (peer_address);
4856 /* update traffic received amount ... */
4857 msize = ntohs (message->size);
4858 GNUNET_STATISTICS_update (stats,
4859 gettext_noop ("# bytes received from other peers"),
4862 n->distance = distance;
4864 GNUNET_TIME_relative_to_absolute
4865 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4866 GNUNET_SCHEDULER_cancel (n->timeout_task);
4868 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4869 &neighbour_timeout_task, n);
4870 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4872 /* dropping message due to frequent inbound volume violations! */
4873 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4874 GNUNET_ERROR_TYPE_BULK,
4876 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4877 n->in_tracker.available_bytes_per_s__,
4878 n->quota_violation_count);
4879 GNUNET_STATISTICS_update (stats,
4880 gettext_noop ("# bandwidth quota violations by other peers"),
4883 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4888 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4889 ntohs (message->type),
4890 ntohs (message->size),
4893 switch (ntohs (message->type))
4895 case GNUNET_MESSAGE_TYPE_HELLO:
4896 GNUNET_STATISTICS_update (stats,
4897 gettext_noop ("# HELLO messages received from other peers"),
4900 process_hello (plugin, message);
4902 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4903 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4905 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4906 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4909 handle_payload_message (message, n);
4913 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4914 if (ret.rel_value > 0)
4916 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4917 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4918 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4919 (unsigned int) n->in_tracker.available_bytes_per_s__,
4920 (unsigned long long) ret.rel_value);
4921 GNUNET_STATISTICS_update (stats,
4922 gettext_noop ("# ms throttling suggested"),
4923 (int64_t) ret.rel_value,
4930 * Handle START-message. This is the first message sent to us
4931 * by any client which causes us to add it to our list.
4933 * @param cls closure (always NULL)
4934 * @param client identification of the client
4935 * @param message the actual message
4938 handle_start (void *cls,
4939 struct GNUNET_SERVER_Client *client,
4940 const struct GNUNET_MessageHeader *message)
4942 const struct StartMessage *start;
4943 struct TransportClient *c;
4944 struct ConnectInfoMessage * cim;
4945 struct NeighbourList *n;
4949 start = (const struct StartMessage*) message;
4951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4952 "Received `%s' request from client\n", "START");
4957 if (c->client == client)
4959 /* client already on our list! */
4961 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4966 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4967 (0 != memcmp (&start->self,
4969 sizeof (struct GNUNET_PeerIdentity))) )
4971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4972 _("Rejecting control connection from peer `%s', which is not me!\n"),
4973 GNUNET_i2s (&start->self));
4974 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4977 c = GNUNET_malloc (sizeof (struct TransportClient));
4981 if (our_hello != NULL)
4984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4985 "Sending our own `%s' to new client\n", "HELLO");
4987 transmit_to_client (c,
4988 (const struct GNUNET_MessageHeader *) our_hello,
4990 /* tell new client about all existing connections */
4992 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4993 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4997 cim = GNUNET_malloc (size);
4998 cim->header.size = htons (size);
4999 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5000 cim->ats_count = htonl(ats_count);
5001 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5002 (&(cim->ats))[2].value = htonl (0);
5006 if (GNUNET_YES == n->received_pong)
5008 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5009 (&(cim->ats))[0].value = htonl (n->distance);
5010 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5011 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5013 transmit_to_client (c, &cim->header, GNUNET_NO);
5019 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5024 * Handle HELLO-message.
5026 * @param cls closure (always NULL)
5027 * @param client identification of the client
5028 * @param message the actual message
5031 handle_hello (void *cls,
5032 struct GNUNET_SERVER_Client *client,
5033 const struct GNUNET_MessageHeader *message)
5037 GNUNET_STATISTICS_update (stats,
5038 gettext_noop ("# HELLOs received from clients"),
5041 ret = process_hello (NULL, message);
5042 GNUNET_SERVER_receive_done (client, ret);
5047 * Closure for 'transmit_client_message'; followed by
5048 * 'msize' bytes of the actual message.
5050 struct TransmitClientMessageContext
5053 * Client on whom's behalf we are sending.
5055 struct GNUNET_SERVER_Client *client;
5058 * Timeout for the transmission.
5060 struct GNUNET_TIME_Absolute timeout;
5068 * Size of the message in bytes.
5075 * Schedule transmission of a message we got from a client to a peer.
5077 * @param cls the 'struct TransmitClientMessageContext*'
5078 * @param n destination, or NULL on error (in that case, drop the message)
5081 transmit_client_message (void *cls,
5082 struct NeighbourList *n)
5084 struct TransmitClientMessageContext *tcmc = cls;
5085 struct TransportClient *tc;
5088 while ((tc != NULL) && (tc->client != tcmc->client))
5093 transmit_to_peer (tc, NULL, tcmc->priority,
5094 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5096 tcmc->msize, GNUNET_NO, n);
5098 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5099 GNUNET_SERVER_client_drop (tcmc->client);
5105 * Handle SEND-message.
5107 * @param cls closure (always NULL)
5108 * @param client identification of the client
5109 * @param message the actual message
5112 handle_send (void *cls,
5113 struct GNUNET_SERVER_Client *client,
5114 const struct GNUNET_MessageHeader *message)
5116 const struct OutboundMessage *obm;
5117 const struct GNUNET_MessageHeader *obmm;
5118 struct TransmitClientMessageContext *tcmc;
5122 size = ntohs (message->size);
5124 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5127 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5130 GNUNET_STATISTICS_update (stats,
5131 gettext_noop ("# payload received for other peers"),
5134 obm = (const struct OutboundMessage *) message;
5135 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5136 msize = size - sizeof (struct OutboundMessage);
5138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5139 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5140 "SEND", GNUNET_i2s (&obm->peer),
5144 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5145 tcmc->client = client;
5146 tcmc->priority = ntohl (obm->priority);
5147 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5148 tcmc->msize = msize;
5149 /* FIXME: this memcpy can be up to 7% of our total runtime */
5150 memcpy (&tcmc[1], obmm, msize);
5151 GNUNET_SERVER_client_keep (client);
5152 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5153 &transmit_client_message,
5159 * Handle request connect message
5161 * @param cls closure (always NULL)
5162 * @param client identification of the client
5163 * @param message the actual message
5166 handle_request_connect (void *cls,
5167 struct GNUNET_SERVER_Client *client,
5168 const struct GNUNET_MessageHeader *message)
5170 const struct TransportRequestConnectMessage *trcm =
5171 (const struct TransportRequestConnectMessage *) message;
5173 GNUNET_STATISTICS_update (stats,
5174 gettext_noop ("# REQUEST CONNECT messages received"),
5177 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5178 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5180 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5184 * Handle SET_QUOTA-message.
5186 * @param cls closure (always NULL)
5187 * @param client identification of the client
5188 * @param message the actual message
5191 handle_set_quota (void *cls,
5192 struct GNUNET_SERVER_Client *client,
5193 const struct GNUNET_MessageHeader *message)
5195 const struct QuotaSetMessage *qsm =
5196 (const struct QuotaSetMessage *) message;
5197 struct NeighbourList *n;
5199 GNUNET_STATISTICS_update (stats,
5200 gettext_noop ("# SET QUOTA messages received"),
5203 n = find_neighbour (&qsm->peer);
5206 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5207 GNUNET_STATISTICS_update (stats,
5208 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5215 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5217 (unsigned int) ntohl (qsm->quota.value__),
5218 (unsigned int) n->in_tracker.available_bytes_per_s__,
5219 GNUNET_i2s (&qsm->peer));
5221 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5223 if (0 == ntohl (qsm->quota.value__))
5225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5226 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5228 disconnect_neighbour (n, GNUNET_NO);
5230 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5235 * Take the given address and append it to the set of results sent back to
5238 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5239 * @param address the resolved name, NULL to indicate the last response
5242 transmit_address_to_client (void *cls, const char *address)
5244 struct GNUNET_SERVER_TransmitContext *tc = cls;
5247 if (NULL == address)
5250 slen = strlen (address) + 1;
5252 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5253 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5254 if (NULL == address)
5255 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5260 * Handle AddressLookup-message.
5262 * @param cls closure (always NULL)
5263 * @param client identification of the client
5264 * @param message the actual message
5267 handle_address_lookup (void *cls,
5268 struct GNUNET_SERVER_Client *client,
5269 const struct GNUNET_MessageHeader *message)
5271 const struct AddressLookupMessage *alum;
5272 struct TransportPlugin *lsPlugin;
5273 const char *nameTransport;
5274 const char *address;
5276 struct GNUNET_SERVER_TransmitContext *tc;
5277 struct GNUNET_TIME_Absolute timeout;
5278 struct GNUNET_TIME_Relative rtimeout;
5281 size = ntohs (message->size);
5282 if (size < sizeof (struct AddressLookupMessage))
5284 GNUNET_break_op (0);
5285 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5288 alum = (const struct AddressLookupMessage *) message;
5289 uint32_t addressLen = ntohl (alum->addrlen);
5290 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5292 GNUNET_break_op (0);
5293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5296 address = (const char *) &alum[1];
5297 nameTransport = (const char *) &address[addressLen];
5299 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5301 GNUNET_break_op (0);
5302 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5305 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5306 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5307 numeric = ntohl (alum->numeric_only);
5308 lsPlugin = find_transport (nameTransport);
5309 if (NULL == lsPlugin)
5311 tc = GNUNET_SERVER_transmit_context_create (client);
5312 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5313 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5314 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5317 tc = GNUNET_SERVER_transmit_context_create (client);
5318 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5320 address, addressLen,
5323 &transmit_address_to_client, tc);
5328 * Setup the environment for this plugin.
5331 create_environment (struct TransportPlugin *plug)
5333 plug->env.cfg = cfg;
5334 plug->env.my_identity = &my_identity;
5335 plug->env.our_hello = &our_hello;
5336 plug->env.cls = plug;
5337 plug->env.receive = &plugin_env_receive;
5338 plug->env.notify_address = &plugin_env_notify_address;
5339 plug->env.session_end = &plugin_env_session_end;
5340 plug->env.max_connections = max_connect_per_transport;
5341 plug->env.stats = stats;
5346 * Start the specified transport (load the plugin).
5349 start_transport (struct GNUNET_SERVER_Handle *server,
5352 struct TransportPlugin *plug;
5355 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5356 _("Loading `%s' transport plugin\n"), name);
5357 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5358 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5359 create_environment (plug);
5360 plug->short_name = GNUNET_strdup (name);
5361 plug->lib_name = libname;
5362 plug->next = plugins;
5364 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5365 if (plug->api == NULL)
5367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5368 _("Failed to load transport plugin for `%s'\n"), name);
5369 GNUNET_free (plug->short_name);
5370 plugins = plug->next;
5371 GNUNET_free (libname);
5378 * Called whenever a client is disconnected. Frees our
5379 * resources associated with that client.
5381 * @param cls closure
5382 * @param client identification of the client
5385 client_disconnect_notification (void *cls,
5386 struct GNUNET_SERVER_Client *client)
5388 struct TransportClient *pos;
5389 struct TransportClient *prev;
5390 struct ClientMessageQueueEntry *mqe;
5391 struct Blacklisters *bl;
5392 struct BlacklistCheck *bc;
5397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5398 "Client disconnected, cleaning up.\n");
5400 /* clean up blacklister */
5404 if (bl->client == client)
5409 if (bc->bl_pos == bl)
5411 bc->bl_pos = bl->next;
5414 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5417 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5418 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5424 GNUNET_CONTAINER_DLL_remove (bl_head,
5427 GNUNET_SERVER_client_drop (bl->client);
5433 /* clean up 'normal' clients */
5436 while ((pos != NULL) && (pos->client != client))
5443 while (NULL != (mqe = pos->message_queue_head))
5445 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5446 pos->message_queue_tail,
5448 pos->message_count--;
5452 clients = pos->next;
5454 prev->next = pos->next;
5455 if (GNUNET_YES == pos->tcs_pending)
5460 if (pos->th != NULL)
5462 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5465 GNUNET_break (0 == pos->message_count);
5471 * Function called when the service shuts down. Unloads our plugins
5472 * and cancels pending validations.
5474 * @param cls closure, unused
5475 * @param tc task context (unused)
5478 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5480 struct TransportPlugin *plug;
5481 struct OwnAddressList *al;
5482 struct CheckHelloValidatedContext *chvc;
5484 while (neighbours != NULL)
5486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5487 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5489 disconnect_neighbour (neighbours, GNUNET_NO);
5492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5493 "Transport service is unloading plugins...\n");
5495 while (NULL != (plug = plugins))
5497 plugins = plug->next;
5498 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5500 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5501 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5503 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5504 GNUNET_free (plug->lib_name);
5505 GNUNET_free (plug->short_name);
5506 while (NULL != (al = plug->addresses))
5508 plug->addresses = al->next;
5513 if (my_private_key != NULL)
5514 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5515 GNUNET_free_non_null (our_hello);
5517 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5520 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5521 validation_map = NULL;
5525 /* free 'chvc' data structure */
5526 while (NULL != (chvc = chvc_head))
5528 chvc_head = chvc->next;
5529 if (chvc->piter != NULL)
5531 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5532 GNUNET_STATISTICS_update (stats,
5533 gettext_noop ("# outstanding peerinfo iterate requests"),
5539 GNUNET_assert (chvc->ve_count == 0);
5546 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5549 if (peerinfo != NULL)
5551 GNUNET_PEERINFO_disconnect (peerinfo);
5554 /* Can we assume those are gone by now, or do we need to clean up
5556 GNUNET_break (bl_head == NULL);
5557 GNUNET_break (bc_head == NULL);
5560 struct ATS_transports
5567 #define FUNCTION ats_create_problem (int peers, int transports, double b_min, double b_max, double r, double R, const struct ATS_peer * pl, const struct ATS_transports * tl, int max_it, int max_dur)
5572 int result = GLP_UNDEF;
5577 int rows = 1 + (3*peers) + (transports);
5583 int ia[1+(rows*cols)], ja[1+(rows*cols)];
5584 double ar[1+(rows*cols)];
5587 /* Setting GLPK options */
5588 glp_smcp * options = GNUNET_malloc( sizeof (glp_smcp));
5589 glp_init_smcp(options);
5591 /* maximum iterations */
5592 options->it_lim = max_it;
5593 /* maximum durations */
5594 options->tm_lim = max_dur;
5597 options->msg_lev = GLP_MSG_ALL;
5599 options->msg_lev = GLP_MSG_OFF;
5601 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating LP problem: %i peers, relativity r %3.2f, b_max %5.2f, b_min %5.2f, \n",peers, r, b_max, b_min);
5602 lp = glp_create_prob();
5603 glp_set_prob_name(lp, "gnunet ats bandwidth distribution");
5604 glp_set_obj_dir(lp, GLP_MAX);
5606 /* Adding transports and objective function coefficients*/
5607 glp_add_cols(lp, cols);
5608 for (c1=1; c1<=cols; c1++)
5610 GNUNET_asprintf(&peer_n,"%s",GNUNET_i2s(&pl[c1-1].peer));
5611 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer[%i] , transport %i, %s: f: %f\n",c1-1 , pl[c1-1].t, peer_n, pl[c1-1].f);
5612 /* add a single transport*/
5613 glp_set_col_name(lp, c1, peer_n);
5614 /* add a lower bound */
5615 glp_set_col_bnds(lp, c1, GLP_LO, 0.0, 0.0);
5616 /* set coefficient function */
5617 value = pl[c1-1].f/b_max;
5619 glp_set_obj_coef(lp, c1, value);
5620 GNUNET_free(peer_n);
5623 /* Adding constraints */
5624 glp_add_rows(lp, rows);
5627 /* constraint 1: Maximum bandwidth for all peers
5630 glp_set_row_bnds(lp, cur_row, GLP_UP, 0.0, b_max);
5631 for (index=1; index<=cols; index++)
5633 ia[index] = 1, ja[index] = index, ar[index] = 1.0;
5636 /* constraint 2: Maximum bandwidth per peer
5637 * V b_i in B: b_i <= b_max
5641 for (c1=0; c1<peers; c1++)
5643 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i \n", cur_row);
5644 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0, b_max);
5646 for (c2 = 1; c2 <= cols; c2++)
5648 ia[index] = cur_row;
5650 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5656 /* constraint 3: Minimum bandwidth
5657 * V b_i in B: b_i >= b_min
5660 for (c1=0; c1<peers; c1++)
5662 glp_set_row_bnds(lp, cur_row , GLP_LO, b_min, 0.0);
5664 for (c2 = 1; c2 <= cols; c2++)
5666 ia[index] = cur_row;
5668 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5674 /* constraint 4: Bandwidth assignment relativity to peer preference
5675 * V b_i in B: b_i >= b_min
5678 for (c1=0; c1<peers; c1++)
5681 value = pl[c1].f * r;
5682 glp_set_row_bnds(lp, cur_row , GLP_LO, value, 0.0);
5683 for (c2 = 1; c2 <= cols; c2++)
5685 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "c1: %i c2 %i index: %i \n",c1 , c2, index);
5686 ia[index] = cur_row;
5688 ar[index] = ((c1+1 == c2) ? (1.0/b_max) : 0.0);
5689 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ia: %i ja %i ar: %f \n",cur_row , c2, ((c1+1 == c2) ? 1.0 : 0.0));
5695 /* constraint 4: transport capacity
5696 * sum of b * c_i < c_max */
5698 for (c1=0; c1<transports; c1++)
5701 value = tl[c1].c_max;
5702 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport %i: c_max %5.2f c_1 %5.2f \n", c1, value, tl[c1].c_1);
5703 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0 , value);
5705 for (c2 = 1; c2 <= cols; c2++)
5707 ia[index] = cur_row;
5709 ar[index] = ((pl[c1-1].t == tl[c1].id) ? (tl[c1].c_1) : 0.0);
5715 glp_load_matrix(lp, rows * cols, ia, ja, ar);
5716 result = glp_simplex(lp, options);
5720 case GLP_EITLIM : /* iteration limit exceeded */
5721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration limit exceeded ");
5723 case GLP_ETMLIM : /* time limit exceeded */
5724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Time limit exceeded ");
5726 case GLP_ENOPFS : /* no primal feasible solution */
5727 case GLP_ENODFS : /* no dual feasible solution */
5728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No feasible solution");
5731 case GLP_EBADB : /* invalid basis */
5734 case GLP_ESING : /* singular matrix */
5736 case GLP_ECOND : /* ill-conditioned matrix */
5738 case GLP_EBOUND : /* invalid bounds */
5740 case GLP_EFAIL : /* solver failed */
5742 case GLP_EOBJLL : /* objective lower limit reached */
5744 case GLP_EOBJUL : /* objective upper limit reached */
5746 case GLP_EROOT : /* root LP optimum not provided */
5748 case GLP_ESTOP : /* search terminated by application */
5750 case GLP_EMIPGAP: /* relative mip gap tolerance reached */
5752 case GLP_ENOFEAS: /* no primal/dual feasible solution */
5754 case GLP_ENOCVG : /* no convergence */
5756 case GLP_EINSTAB: /* numerical instability */
5758 case GLP_EDATA : /* invalid data */
5760 case GLP_ERANGE : /* result out of range */
5763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Optimal solution\n");
5768 char * debug_solution = NULL;
5770 for (c1=1; c1<= peers; c1++ )
5772 old = debug_solution;
5773 GNUNET_asprintf(&debug_solution, "%s %s = %g;", (debug_solution!=NULL) ? debug_solution : "", GNUNET_i2s(&pl[c1-1].peer), glp_get_col_prim(lp, c1));
5774 if (old!=NULL) GNUNET_free(old);
5776 GNUNET_asprintf(&debug_solution, "%s z = %g; \n", debug_solution, glp_get_obj_val(lp));
5777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s \n",debug_solution);
5778 GNUNET_free(debug_solution);
5780 glp_delete_prob(lp);
5781 GNUNET_free(options);
5793 void ats_calculate_bandwidth_distribution ()
5795 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
5796 if (delta.rel_value < ats->min_delta.rel_value)
5799 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
5808 double b_max = 100.0;
5809 double r = 0.85;//1.0;
5815 struct ATS_transports * tl = GNUNET_malloc(transports * sizeof (struct ATS_peer));
5817 struct ATS_peer * pl = GNUNET_malloc(peers * sizeof (struct ATS_peer));
5821 pl[c].peer.hashPubKey.bits[0] = c+1;
5822 pl[c].f = 1 / (double) peers ;
5824 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %s %p \n",c , GNUNET_i2s(&list[c].peer), &list[c].peer);
5828 while (c < transports)
5843 ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur);
5848 ats->last = GNUNET_TIME_absolute_get();
5855 ats_schedule_calculation (void *cls,
5856 const struct GNUNET_SCHEDULER_TaskContext *tc)
5858 struct ATS_info *ats = (struct ATS_info *) cls;
5862 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5863 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
5867 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
5869 ats_calculate_bandwidth_distribution (ats);
5871 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
5872 &ats_schedule_calculation, ats);
5876 int ats_map_remove_peer (void *cls,
5877 const GNUNET_HashCode * key,
5881 struct ATS_peer * p = (struct ATS_peer *) value;
5883 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
5892 struct ATS_info * ats_init ()
5894 struct ATS_info * ats;
5896 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
5898 ats = GNUNET_malloc(sizeof (struct ATS_info));
5899 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
5900 GNUNET_assert(ats->peers!=NULL);
5902 ats->min_delta = ATS_MIN_INTERVAL;
5903 ats->exec_intervall = ATS_EXEC_INTERVAL;
5905 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5907 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5908 &schedule_calculation, NULL);
5910 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5911 &schedule_calculation, NULL);
5913 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
5919 void ats_shutdown ()
5922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
5924 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
5925 GNUNET_SCHEDULER_cancel(ats->ats_task);
5926 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5928 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
5929 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
5934 void ats_notify_peer_connect (
5935 const struct GNUNET_PeerIdentity *peer,
5936 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
5943 while (ntohl(ats_data[c].type)!=0)
5946 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
5950 /* check if peer is already known */
5951 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
5953 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
5954 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
5955 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
5958 ats_calculate_bandwidth_distribution(ats);
5961 void ats_notify_peer_disconnect (
5962 const struct GNUNET_PeerIdentity *peer)
5965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
5968 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
5970 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
5971 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
5974 ats_calculate_bandwidth_distribution (ats);
5978 void ats_notify_ats_data (
5979 const struct GNUNET_PeerIdentity *peer,
5980 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5983 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
5985 ats_calculate_bandwidth_distribution(ats);
5988 struct ForeignAddressList * ats_get_preferred_address (
5989 struct NeighbourList *n)
5992 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
5994 struct ReadyList *next = n->plugins;
5995 while (next != NULL)
5998 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6002 return find_ready_address(n);
6006 * Initiate transport service.
6008 * @param cls closure
6009 * @param server the initialized server
6010 * @param c configuration to use
6014 struct GNUNET_SERVER_Handle *server,
6015 const struct GNUNET_CONFIGURATION_Handle *c)
6017 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6018 {&handle_start, NULL,
6019 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6020 {&handle_hello, NULL,
6021 GNUNET_MESSAGE_TYPE_HELLO, 0},
6022 {&handle_send, NULL,
6023 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6024 {&handle_request_connect, NULL,
6025 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6026 {&handle_set_quota, NULL,
6027 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6028 {&handle_address_lookup, NULL,
6029 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6031 {&handle_blacklist_init, NULL,
6032 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6033 {&handle_blacklist_reply, NULL,
6034 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6040 unsigned long long tneigh;
6044 stats = GNUNET_STATISTICS_create ("transport", cfg);
6045 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6046 /* parse configuration */
6048 GNUNET_CONFIGURATION_get_value_number (c,
6053 GNUNET_CONFIGURATION_get_value_filename (c,
6055 "HOSTKEY", &keyfile)))
6057 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6059 ("Transport service is lacking key configuration settings. Exiting.\n"));
6060 GNUNET_SCHEDULER_shutdown ();
6063 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6066 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6067 validation_map = NULL;
6071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("HAVE\n"));
6073 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("NOT HAVE\n"));
6077 max_connect_per_transport = (uint32_t) tneigh;
6078 peerinfo = GNUNET_PEERINFO_connect (cfg);
6079 if (peerinfo == NULL)
6081 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6082 _("Could not access PEERINFO service. Exiting.\n"));
6083 GNUNET_SCHEDULER_shutdown ();
6086 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6089 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6090 validation_map = NULL;
6091 GNUNET_free (keyfile);
6094 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6095 GNUNET_free (keyfile);
6096 if (my_private_key == NULL)
6098 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6100 ("Transport service could not access hostkey. Exiting.\n"));
6101 GNUNET_SCHEDULER_shutdown ();
6104 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6107 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6108 validation_map = NULL;
6111 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6112 GNUNET_CRYPTO_hash (&my_public_key,
6113 sizeof (my_public_key), &my_identity.hashPubKey);
6114 /* setup notification */
6115 GNUNET_SERVER_disconnect_notify (server,
6116 &client_disconnect_notification, NULL);
6117 /* load plugins... */
6120 GNUNET_CONFIGURATION_get_value_string (c,
6121 "TRANSPORT", "PLUGINS", &plugs))
6123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6124 _("Starting transport plugins `%s'\n"), plugs);
6125 pos = strtok (plugs, " ");
6128 start_transport (server, pos);
6130 pos = strtok (NULL, " ");
6132 GNUNET_free (plugs);
6134 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6135 &shutdown_task, NULL);
6140 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6142 /* If we have a blacklist file, read from it */
6143 read_blacklist_file(cfg);
6144 /* process client requests */
6145 GNUNET_SERVER_add_handlers (server, handlers);
6150 * The main function for the transport service.
6152 * @param argc number of arguments from the command line
6153 * @param argv command line arguments
6154 * @return 0 ok, 1 on error
6157 main (int argc, char *const *argv)
6159 a2s (NULL, NULL, 0); /* make compiler happy */
6160 return (GNUNET_OK ==
6161 GNUNET_SERVICE_run (argc,
6164 GNUNET_SERVICE_OPTION_NONE,
6165 &run, NULL)) ? 0 : 1;
6168 /* end of gnunet-service-transport.c */