2 This file is part of GNUnet.
3 (C) 2009 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 2, 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
27 * - This code uses 'GNUNET_a2s' for debug printing in many places,
28 * which is technically wrong since it assumes we have IP+Port
29 * (v4/v6) addresses. Once we add transports like http or smtp
30 * this will have to be changed!
31 * - Already wrong with dv.
34 #include "gnunet_client_lib.h"
35 #include "gnunet_container_lib.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_getopt_lib.h"
38 #include "gnunet_hello_lib.h"
39 #include "gnunet_os_lib.h"
40 #include "gnunet_peerinfo_service.h"
41 #include "gnunet_plugin_lib.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_service_lib.h"
44 #include "gnunet_signatures.h"
45 #include "plugin_transport.h"
46 #include "transport.h"
48 #define DEBUG_BLACKLIST GNUNET_NO
50 #define DEBUG_PING_PONG GNUNET_NO
53 * Should we do some additional checks (to validate behavior
56 #define EXTRA_CHECKS GNUNET_YES
59 * How many messages can we have pending for a given client process
60 * before we start to drop incoming messages? We typically should
61 * have only one client and so this would be the primary buffer for
62 * messages, so the number should be chosen rather generously.
64 * The expectation here is that most of the time the queue is large
65 * enough so that a drop is virtually never required.
67 #define MAX_PENDING 128
70 * How often should we try to reconnect to a peer using a particular
71 * transport plugin before giving up? Note that the plugin may be
72 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
74 #define MAX_CONNECT_RETRY 3
77 * Limit on the number of ready-to-run tasks when validating
78 * HELLOs. If more tasks are ready to run, we will drop
79 * HELLOs instead of validating them.
81 #define MAX_HELLO_LOAD 4
84 * How often must a peer violate bandwidth quotas before we start
85 * to simply drop its messages?
87 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
90 * How long until a HELLO verification attempt should time out?
91 * Must be rather small, otherwise a partially successful HELLO
92 * validation (some addresses working) might not be available
93 * before a client's request for a connection fails for good.
94 * Besides, if a single request to an address takes a long time,
95 * then the peer is unlikely worthwhile anyway.
97 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
100 * Priority to use for PONG messages.
102 #define TRANSPORT_PONG_PRIORITY 4
105 * How often do we re-add (cheaper) plugins to our list of plugins
106 * to try for a given connected peer?
108 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
111 * After how long do we expire an address in a HELLO that we just
112 * validated? This value is also used for our own addresses when we
115 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
119 * How long before an existing address expires should we again try to
120 * validate it? Must be (significantly) smaller than
121 * HELLO_ADDRESS_EXPIRATION.
123 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
126 * Maximum frequency for re-evaluating latencies for all transport addresses.
128 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
131 * Maximum frequency for re-evaluating latencies for connected addresses.
133 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
137 * List of addresses of other peers
139 struct ForeignAddressList
142 * This is a linked list.
144 struct ForeignAddressList *next;
147 * Which ready list does this entry belong to.
149 struct ReadyList *ready_list;
152 * How long until we auto-expire this address (unless it is
153 * re-confirmed by the transport)?
155 struct GNUNET_TIME_Absolute expires;
158 * Task used to re-validate addresses, updates latencies and
161 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
174 * Session (or NULL if no valid session currently exists or if the
175 * plugin does not use sessions).
177 struct Session *session;
180 * What was the last latency observed for this address, plugin and peer?
182 struct GNUNET_TIME_Relative latency;
185 * If we did not successfully transmit a message to the given peer
186 * via this connection during the specified time, we should consider
187 * the connection to be dead. This is used in the case that a TCP
188 * transport simply stalls writing to the stream but does not
189 * formerly get a signal that the other peer died.
191 struct GNUNET_TIME_Absolute timeout;
194 * How often have we tried to connect using this plugin? Used to
195 * discriminate against addresses that do not work well.
196 * FIXME: not yet used, but should be!
198 unsigned int connect_attempts;
201 * DV distance to this peer (1 if no DV is used).
202 * FIXME: need to set this from transport plugins!
207 * Have we ever estimated the latency of this address? Used to
208 * ensure that the first time we add an address, we immediately
214 * Are we currently connected via this address? The first time we
215 * successfully transmit or receive data to a peer via a particular
216 * address, we set this to GNUNET_YES. If we later get an error
217 * (disconnect notification, transmission failure, timeout), we set
218 * it back to GNUNET_NO.
223 * Is this plugin currently busy transmitting to the specific target?
224 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
225 * messages do not count as 'in transmit'.
230 * Has this address been validated yet?
238 * Entry in linked list of network addresses for ourselves.
240 struct OwnAddressList
243 * This is a linked list.
245 struct OwnAddressList *next;
248 * The address, actually a pointer to the end
249 * of this struct. Do not free!
254 * How long until we auto-expire this address (unless it is
255 * re-confirmed by the transport)?
257 struct GNUNET_TIME_Absolute expires;
268 * Entry in linked list of all of our plugins.
270 struct TransportPlugin
274 * This is a linked list.
276 struct TransportPlugin *next;
279 * API of the transport as returned by the plugin's
280 * initialization function.
282 struct GNUNET_TRANSPORT_PluginFunctions *api;
285 * Short name for the plugin (i.e. "tcp").
290 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
295 * List of our known addresses for this transport.
297 struct OwnAddressList *addresses;
300 * Environment this transport service is using
303 struct GNUNET_TRANSPORT_PluginEnvironment env;
306 * ID of task that is used to clean up expired addresses.
308 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
311 * Set to GNUNET_YES if we need to scrap the existing list of
312 * "addresses" and start fresh when we receive the next address
313 * update from a transport. Set to GNUNET_NO if we should just add
314 * the new address to the list and wait for the commit call.
319 * Hashmap of blacklisted peers for this particular transport.
321 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
324 struct NeighbourList;
327 * For each neighbour we keep a list of messages
328 * that we still want to transmit to the neighbour.
334 * This is a doubly linked list.
336 struct MessageQueue *next;
339 * This is a doubly linked list.
341 struct MessageQueue *prev;
344 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
345 * stuck together in memory. Allocated at the end of this struct.
347 const char *message_buf;
350 * Size of the message buf
352 size_t message_buf_size;
355 * Client responsible for queueing the message;
356 * used to check that a client has no two messages
357 * pending for the same target. Can be NULL.
359 struct TransportClient *client;
362 * Using which specific address should we send this message?
364 struct ForeignAddressList *specific_address;
367 * Peer ID of the Neighbour this entry belongs to.
369 struct GNUNET_PeerIdentity neighbour_id;
372 * Plugin that we used for the transmission.
373 * NULL until we scheduled a transmission.
375 struct TransportPlugin *plugin;
378 * At what time should we fail?
380 struct GNUNET_TIME_Absolute timeout;
383 * Internal message of the transport system that should not be
384 * included in the usual SEND-SEND_OK transmission confirmation
385 * traffic management scheme. Typically, "internal_msg" will
386 * be set whenever "client" is NULL (but it is not strictly
392 * How important is the message?
394 unsigned int priority;
400 * For a given Neighbour, which plugins are available
401 * to talk to this peer and what are their costs?
406 * This is a linked list.
408 struct ReadyList *next;
411 * Which of our transport plugins does this entry
414 struct TransportPlugin *plugin;
417 * Transport addresses, latency, and readiness for
418 * this particular plugin.
420 struct ForeignAddressList *addresses;
423 * To which neighbour does this ready list belong to?
425 struct NeighbourList *neighbour;
431 * Entry in linked list of all of our current neighbours.
437 * This is a linked list.
439 struct NeighbourList *next;
442 * Which of our transports is connected to this peer
443 * and what is their status?
445 struct ReadyList *plugins;
448 * Head of list of messages we would like to send to this peer;
449 * must contain at most one message per client.
451 struct MessageQueue *messages_head;
454 * Tail of list of messages we would like to send to this peer; must
455 * contain at most one message per client.
457 struct MessageQueue *messages_tail;
460 * Buffer for at most one payload message used when we receive
461 * payload data before our PING-PONG has succeeded. We then
462 * store such messages in this intermediary buffer until the
463 * connection is fully up.
465 struct GNUNET_MessageHeader *pre_connect_message_buffer;
468 * Context for peerinfo iteration.
469 * NULL after we are done processing peerinfo's information.
471 struct GNUNET_PEERINFO_IteratorContext *piter;
474 * Public key for this peer. Valid only if the respective flag is set below.
476 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
479 * Identity of this neighbour.
481 struct GNUNET_PeerIdentity id;
484 * ID of task scheduled to run when this peer is about to
485 * time out (will free resources associated with the peer).
487 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
490 * ID of task scheduled to run when we should retry transmitting
491 * the head of the message queue. Actually triggered when the
492 * transmission is timing out (we trigger instantly when we have
493 * a chance of success).
495 GNUNET_SCHEDULER_TaskIdentifier retry_task;
498 * How long until we should consider this peer dead
499 * (if we don't receive another message in the
502 struct GNUNET_TIME_Absolute peer_timeout;
505 * Tracker for inbound bandwidth.
507 struct GNUNET_BANDWIDTH_Tracker in_tracker;
510 * The latency we have seen for this particular address for
511 * this particular peer. This latency may have been calculated
512 * over multiple transports. This value reflects how long it took
513 * us to receive a response when SENDING via this particular
514 * transport/neighbour/address combination!
516 * FIXME: we need to periodically send PINGs to update this
517 * latency (at least more often than the current "huge" (11h?)
520 struct GNUNET_TIME_Relative latency;
523 * How often has the other peer (recently) violated the
524 * inbound traffic limit? Incremented by 10 per violation,
525 * decremented by 1 per non-violation (for each
528 unsigned int quota_violation_count;
531 * DV distance to this peer (1 if no DV is used).
536 * Have we seen an PONG from this neighbour in the past (and
537 * not had a disconnect since)?
542 * Do we have a valid public key for this neighbour?
544 int public_key_valid;
549 * Message used to ask a peer to validate receipt (to check an address
552 struct TransportPingMessage
556 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
558 struct GNUNET_MessageHeader header;
561 * Random challenge number (in network byte order).
563 uint32_t challenge GNUNET_PACKED;
566 * Who is the intended recipient?
568 struct GNUNET_PeerIdentity target;
574 * Message used to validate a HELLO. The challenge is included in the
575 * confirmation to make matching of replies to requests possible. The
576 * signature signs the original challenge number, our public key, the
577 * sender's address (so that the sender can check that the address we
578 * saw is plausible for him and possibly detect a MiM attack) and a
579 * timestamp (to limit replay).<p>
581 * This message is followed by the address of the
582 * client that we are observing (which is part of what
585 struct TransportPongMessage
589 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
591 struct GNUNET_MessageHeader header;
594 * For padding, always zero.
596 uint32_t reserved GNUNET_PACKED;
601 struct GNUNET_CRYPTO_RsaSignature signature;
604 * What are we signing and why?
606 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
609 * Random challenge number (in network byte order).
611 uint32_t challenge GNUNET_PACKED;
614 * Who signed this message?
616 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
619 * Size of address appended to this message
627 * Linked list of messages to be transmitted to the client. Each
628 * entry is followed by the actual message.
630 struct ClientMessageQueueEntry
633 * This is a doubly-linked list.
635 struct ClientMessageQueueEntry *next;
638 * This is a doubly-linked list.
640 struct ClientMessageQueueEntry *prev;
645 * Client connected to the transport service.
647 struct TransportClient
651 * This is a linked list.
653 struct TransportClient *next;
656 * Handle to the client.
658 struct GNUNET_SERVER_Client *client;
661 * Linked list of messages yet to be transmitted to
664 struct ClientMessageQueueEntry *message_queue_head;
667 * Tail of linked list of messages yet to be transmitted to the
670 struct ClientMessageQueueEntry *message_queue_tail;
673 * Current transmit request handle.
675 struct GNUNET_CONNECTION_TransmitHandle *th;
678 * Is a call to "transmit_send_continuation" pending? If so, we
679 * must not free this struct (even if the corresponding client
680 * disconnects) and instead only remove it from the linked list and
681 * set the "client" field to NULL.
686 * Length of the list of messages pending for this client.
688 unsigned int message_count;
694 * Entry in map of all HELLOs awaiting validation.
696 struct ValidationEntry
700 * The address, actually a pointer to the end
701 * of this struct. Do not free!
706 * Name of the transport.
708 char *transport_name;
711 * The public key of the peer.
713 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
716 * ID of task that will clean up this entry if we don't succeed
717 * with the validation first.
719 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
722 * At what time did we send this validation?
724 struct GNUNET_TIME_Absolute send_time;
727 * Session being validated (or NULL for none).
729 struct Session *session;
737 * Challenge number we used.
745 * Context of currently active requests to peerinfo
746 * for validation of HELLOs.
748 struct CheckHelloValidatedContext
752 * This is a doubly-linked list.
754 struct CheckHelloValidatedContext *next;
757 * This is a doubly-linked list.
759 struct CheckHelloValidatedContext *prev;
762 * Hello that we are validating.
764 const struct GNUNET_HELLO_Message *hello;
767 * Context for peerinfo iteration.
768 * NULL after we are done processing peerinfo's information.
770 struct GNUNET_PEERINFO_IteratorContext *piter;
773 * Was a HELLO known for this peer to peerinfo?
784 static struct GNUNET_HELLO_Message *our_hello;
787 * "version" of "our_hello". Used to see if a given neighbour has
788 * already been sent the latest version of our HELLO message.
790 static unsigned int our_hello_version;
795 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
800 static struct GNUNET_PeerIdentity my_identity;
805 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
810 struct GNUNET_SCHEDULER_Handle *sched;
815 const struct GNUNET_CONFIGURATION_Handle *cfg;
818 * Linked list of all clients to this service.
820 static struct TransportClient *clients;
823 * All loaded plugins.
825 static struct TransportPlugin *plugins;
830 static struct GNUNET_SERVER_Handle *server;
833 * All known neighbours and their HELLOs.
835 static struct NeighbourList *neighbours;
838 * Number of neighbours we'd like to have.
840 static uint32_t max_connect_per_transport;
843 * Head of linked list.
845 static struct CheckHelloValidatedContext *chvc_head;
848 * Tail of linked list.
850 static struct CheckHelloValidatedContext *chvc_tail;
853 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
854 * of the given peer that we are currently validating).
856 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
859 * Handle for reporting statistics.
861 static struct GNUNET_STATISTICS_Handle *stats;
865 * The peer specified by the given neighbour has timed-out or a plugin
866 * has disconnected. We may either need to do nothing (other plugins
867 * still up), or trigger a full disconnect and clean up. This
868 * function updates our state and do the necessary notifications.
869 * Also notifies our clients that the neighbour is now officially
872 * @param n the neighbour list entry for the peer
873 * @param check should we just check if all plugins
874 * disconnected or must we ask all plugins to
877 static void disconnect_neighbour (struct NeighbourList *n, int check);
880 * Check the ready list for the given neighbour and if a plugin is
881 * ready for transmission (and if we have a message), do so!
883 * @param neighbour target peer for which to transmit
885 static void try_transmission_to_peer (struct NeighbourList *neighbour);
889 * Find an entry in the neighbour list for a particular peer.
891 * @return NULL if not found.
893 static struct NeighbourList *
894 find_neighbour (const struct GNUNET_PeerIdentity *key)
896 struct NeighbourList *head = neighbours;
898 while ((head != NULL) &&
899 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
906 * Find an entry in the transport list for a particular transport.
908 * @return NULL if not found.
910 static struct TransportPlugin *
911 find_transport (const char *short_name)
913 struct TransportPlugin *head = plugins;
914 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
920 * Is a particular peer blacklisted for a particular transport?
922 * @param peer the peer to check for
923 * @param plugin the plugin used to connect to the peer
925 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
928 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
931 if (plugin->blacklist != NULL)
933 if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
936 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
937 _("Peer `%s:%s' is blacklisted!\n"),
938 plugin->short_name, GNUNET_i2s (peer));
948 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
950 struct TransportPlugin *plugin;
952 plugin = find_transport(transport_name);
954 if (plugin == NULL) /* Nothing to do */
957 if (plugin->blacklist == NULL)
959 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(100); /* FIXME: estimated number of peers or what? */
962 GNUNET_assert(plugin->blacklist != NULL);
964 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
968 * Read the blacklist file, containing transport:peer entries.
969 * Provided the transport is loaded, set up hashmap with these
970 * entries to blacklist peers by transport.
974 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
981 struct GNUNET_PeerIdentity pid;
983 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
984 unsigned int entries_found;
985 char *transport_name;
988 GNUNET_CONFIGURATION_get_value_filename (cfg,
993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
994 _("Option `%s' in section `%s' not specified!\n"),
999 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1000 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1001 | GNUNET_DISK_PERM_USER_WRITE);
1002 if (0 != STAT (fn, &frstat))
1004 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1005 _("Could not read blacklist file `%s'\n"), fn);
1009 if (frstat.st_size == 0)
1011 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1012 _("Blacklist file `%s' is empty.\n"),
1017 data = GNUNET_malloc_large (frstat.st_size);
1018 if (frstat.st_size !=
1019 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1021 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1022 _("Failed to read blacklist from `%s'\n"), fn);
1029 while ((pos < frstat.st_size) && isspace (data[pos]))
1031 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1032 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1035 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace (data[colon_pos]))
1038 if (colon_pos >= frstat.st_size)
1040 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1041 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1042 (unsigned long long) colon_pos);
1048 if (isspace(data[colon_pos]))
1050 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1051 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1052 (unsigned long long) colon_pos);
1054 while ((pos < frstat.st_size) && isspace (data[pos]))
1058 tsize = colon_pos - pos;
1059 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size))
1061 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1062 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1063 (unsigned long long) colon_pos);
1069 transport_name = GNUNET_malloc(tsize);
1070 memcpy(transport_name, &data[pos], tsize);
1071 pos = colon_pos + 1;
1074 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075 _("Read transport name %s in blacklist file.\n"),
1078 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1079 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1081 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1082 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1083 (unsigned long long) pos);
1085 while ((pos < frstat.st_size) && (!isspace (data[pos])))
1087 GNUNET_free_non_null(transport_name);
1090 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1091 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1093 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1094 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1095 (unsigned long long) pos,
1100 if (0 != memcmp (&pid,
1102 sizeof (struct GNUNET_PeerIdentity)))
1105 add_peer_to_blacklist (&pid,
1107 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1108 _("Found blacklisted peer `%s:%s' in configuration\n"),
1109 transport_name, GNUNET_i2s (&pid));
1113 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1114 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1118 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1119 GNUNET_free_non_null(transport_name);
1120 while ((pos < frstat.st_size) && isspace (data[pos]))
1129 * Function called to notify a client about the socket being ready to
1130 * queue more data. "buf" will be NULL and "size" zero if the socket
1131 * was closed for writing in the meantime.
1133 * @param cls closure
1134 * @param size number of bytes available in buf
1135 * @param buf where the callee should write the message
1136 * @return number of bytes written to buf
1139 transmit_to_client_callback (void *cls, size_t size, void *buf)
1141 struct TransportClient *client = cls;
1142 struct ClientMessageQueueEntry *q;
1145 const struct GNUNET_MessageHeader *msg;
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 "Transmission to client failed, closing connection.\n");
1153 /* fatal error with client, free message queue! */
1154 while (NULL != (q = client->message_queue_head))
1156 GNUNET_STATISTICS_update (stats,
1157 gettext_noop ("# bytes discarded (could not transmit to client)"),
1158 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1160 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1161 client->message_queue_tail,
1165 client->message_count = 0;
1170 while (NULL != (q = client->message_queue_head))
1172 msg = (const struct GNUNET_MessageHeader *) &q[1];
1173 msize = ntohs (msg->size);
1174 if (msize + tsize > size)
1177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178 "Transmitting message of type %u to client.\n",
1181 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1182 client->message_queue_tail,
1184 memcpy (&cbuf[tsize], msg, msize);
1187 client->message_count--;
1191 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1192 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1194 GNUNET_TIME_UNIT_FOREVER_REL,
1195 &transmit_to_client_callback,
1197 GNUNET_assert (client->th != NULL);
1204 * Mark the given FAL entry as 'connected' (and hence preferred for
1205 * sending); also mark all others for the same peer as 'not connected'
1206 * (since only one can be preferred).
1208 * @param fal address to set to 'connected'
1211 mark_address_connected (struct ForeignAddressList *fal)
1213 struct ForeignAddressList *pos;
1216 GNUNET_assert (GNUNET_YES == fal->validated);
1217 if (fal->connected == GNUNET_YES)
1218 return; /* nothing to do */
1220 pos = fal->ready_list->addresses;
1223 if (GNUNET_YES == pos->connected)
1225 GNUNET_break (cnt == GNUNET_YES);
1227 pos->connected = GNUNET_NO;
1231 fal->connected = GNUNET_YES;
1232 if (GNUNET_YES == cnt)
1234 GNUNET_STATISTICS_update (stats,
1235 gettext_noop ("# connected addresses"),
1243 * Send the specified message to the specified client. Since multiple
1244 * messages may be pending for the same client at a time, this code
1245 * makes sure that no message is lost.
1247 * @param client client to transmit the message to
1248 * @param msg the message to send
1249 * @param may_drop can this message be dropped if the
1250 * message queue for this client is getting far too large?
1253 transmit_to_client (struct TransportClient *client,
1254 const struct GNUNET_MessageHeader *msg, int may_drop)
1256 struct ClientMessageQueueEntry *q;
1259 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1261 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1263 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1264 client->message_count, MAX_PENDING);
1265 /* TODO: call to statistics... */
1268 msize = ntohs (msg->size);
1269 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1270 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1271 memcpy (&q[1], msg, msize);
1272 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1273 client->message_queue_tail,
1274 client->message_queue_tail,
1276 client->message_count++;
1277 if (client->th == NULL)
1279 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1281 GNUNET_TIME_UNIT_FOREVER_REL,
1282 &transmit_to_client_callback,
1284 GNUNET_assert (client->th != NULL);
1290 * Transmit a 'SEND_OK' notification to the given client for the
1293 * @param client who to notify
1294 * @param n neighbour to notify about
1295 * @param result status code for the transmission request
1298 transmit_send_ok (struct TransportClient *client,
1299 struct NeighbourList *n,
1302 struct SendOkMessage send_ok_msg;
1304 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1305 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1306 send_ok_msg.success = htonl (result);
1307 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1308 send_ok_msg.peer = n->id;
1309 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1314 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1315 * upon "completion" of a send request. This tells the API
1316 * that it is now legal to send another message to the given
1319 * @param cls closure, identifies the entry on the
1320 * message queue that was transmitted and the
1321 * client responsible for queueing the message
1322 * @param target the peer receiving the message
1323 * @param result GNUNET_OK on success, if the transmission
1324 * failed, we should not tell the client to transmit
1328 transmit_send_continuation (void *cls,
1329 const struct GNUNET_PeerIdentity *target,
1332 struct MessageQueue *mq = cls;
1333 struct NeighbourList *n;
1335 GNUNET_STATISTICS_update (stats,
1336 gettext_noop ("# bytes pending with plugins"),
1337 - (int64_t) mq->message_buf_size,
1339 if (result == GNUNET_OK)
1341 GNUNET_STATISTICS_update (stats,
1342 gettext_noop ("# bytes successfully transmitted by plugins"),
1343 mq->message_buf_size,
1348 GNUNET_STATISTICS_update (stats,
1349 gettext_noop ("# bytes with transmission failure by plugins"),
1350 mq->message_buf_size,
1353 n = find_neighbour(&mq->neighbour_id);
1354 GNUNET_assert (n != NULL);
1355 if (mq->specific_address != NULL)
1357 if (result == GNUNET_OK)
1359 mq->specific_address->timeout =
1360 GNUNET_TIME_relative_to_absolute
1361 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1362 if (mq->specific_address->validated == GNUNET_YES)
1363 mark_address_connected (mq->specific_address);
1367 if (mq->specific_address->connected != GNUNET_NO)
1369 GNUNET_STATISTICS_update (stats,
1370 gettext_noop ("# connected addresses"),
1373 mq->specific_address->connected = GNUNET_NO;
1376 if (! mq->internal_msg)
1377 mq->specific_address->in_transmit = GNUNET_NO;
1379 if (mq->client != NULL)
1380 transmit_send_ok (mq->client, n, result);
1382 try_transmission_to_peer (n);
1387 * Find an address in any of the available transports for
1388 * the given neighbour that would be good for message
1389 * transmission. This is essentially the transport selection
1392 * @param neighbour for whom to select an address
1393 * @return selected address, NULL if we have none
1395 struct ForeignAddressList *
1396 find_ready_address(struct NeighbourList *neighbour)
1398 struct ReadyList *head = neighbour->plugins;
1399 struct ForeignAddressList *addresses;
1400 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1401 struct ForeignAddressList *best_address;
1403 best_address = NULL;
1404 while (head != NULL)
1406 addresses = head->addresses;
1407 while (addresses != NULL)
1409 if ( (addresses->timeout.value < now.value) &&
1410 (addresses->connected == GNUNET_YES) )
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "Marking long-time inactive connection to `%4s' as down.\n",
1415 GNUNET_i2s (&neighbour->id));
1417 GNUNET_STATISTICS_update (stats,
1418 gettext_noop ("# connected addresses"),
1421 addresses->connected = GNUNET_NO;
1423 addresses = addresses->next;
1426 addresses = head->addresses;
1427 while (addresses != NULL)
1429 #if DEBUG_TRANSPORT > 1
1430 if (addresses->addr != NULL)
1431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1433 GNUNET_a2s (addresses->addr,
1434 addresses->addrlen),
1435 GNUNET_i2s (&neighbour->id),
1436 addresses->connected,
1437 addresses->in_transmit,
1438 addresses->validated,
1439 addresses->connect_attempts,
1440 (unsigned long long) addresses->timeout.value,
1441 (unsigned int) addresses->distance);
1443 if ( ( (best_address == NULL) ||
1444 (addresses->connected == GNUNET_YES) ||
1445 (best_address->connected == GNUNET_NO) ) &&
1446 (addresses->in_transmit == GNUNET_NO) &&
1447 ( (best_address == NULL) ||
1448 (addresses->latency.value < best_address->latency.value)) )
1449 best_address = addresses;
1450 /* FIXME: also give lower-latency addresses that are not
1451 connected a chance some times... */
1452 addresses = addresses->next;
1456 if (best_address != NULL)
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 "Best address found has latency of %llu ms.\n",
1461 best_address->latency.value);
1466 GNUNET_STATISTICS_update (stats,
1467 gettext_noop ("# transmission attempts failed (no address)"),
1471 return best_address;
1477 * We should re-try transmitting to the given peer,
1478 * hopefully we've learned something in the meantime.
1481 retry_transmission_task (void *cls,
1482 const struct GNUNET_SCHEDULER_TaskContext *tc)
1484 struct NeighbourList *n = cls;
1486 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1487 try_transmission_to_peer (n);
1492 * Check the ready list for the given neighbour and if a plugin is
1493 * ready for transmission (and if we have a message), do so!
1495 * @param neighbour target peer for which to transmit
1498 try_transmission_to_peer (struct NeighbourList *neighbour)
1500 struct ReadyList *rl;
1501 struct MessageQueue *mq;
1502 struct GNUNET_TIME_Relative timeout;
1506 if (neighbour->messages_head == NULL)
1509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1510 "Transmission queue for `%4s' is empty\n",
1511 GNUNET_i2s (&neighbour->id));
1513 return; /* nothing to do */
1516 mq = neighbour->messages_head;
1517 force_address = GNUNET_YES;
1518 if (mq->specific_address == NULL)
1520 mq->specific_address = find_ready_address(neighbour);
1521 GNUNET_STATISTICS_update (stats,
1522 gettext_noop ("# transport selected peer address freely"),
1525 force_address = GNUNET_NO;
1527 if (mq->specific_address == NULL)
1529 GNUNET_STATISTICS_update (stats,
1530 gettext_noop ("# transport failed to selected peer address"),
1533 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1534 if (timeout.value == 0)
1537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1538 "No destination address available to transmit message of size %u to peer `%4s'\n",
1539 mq->message_buf_size,
1540 GNUNET_i2s (&mq->neighbour_id));
1542 GNUNET_STATISTICS_update (stats,
1543 gettext_noop ("# bytes in message queue for other peers"),
1544 - (int64_t) mq->message_buf_size,
1546 GNUNET_STATISTICS_update (stats,
1547 gettext_noop ("# bytes discarded (no destination address available)"),
1548 mq->message_buf_size,
1550 if (mq->client != NULL)
1551 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1552 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1553 neighbour->messages_tail,
1556 return; /* nobody ready */
1558 GNUNET_STATISTICS_update (stats,
1559 gettext_noop ("# message delivery deferred (no address)"),
1562 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1563 GNUNET_SCHEDULER_cancel (sched,
1564 neighbour->retry_task);
1565 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1567 &retry_transmission_task,
1570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1571 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1572 mq->message_buf_size,
1573 GNUNET_i2s (&mq->neighbour_id),
1576 /* FIXME: might want to trigger peerinfo lookup here
1577 (unless that's already pending...) */
1580 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1581 neighbour->messages_tail,
1583 if (mq->specific_address->connected == GNUNET_NO)
1584 mq->specific_address->connect_attempts++;
1585 rl = mq->specific_address->ready_list;
1586 mq->plugin = rl->plugin;
1587 if (!mq->internal_msg)
1588 mq->specific_address->in_transmit = GNUNET_YES;
1590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1592 mq->message_buf_size,
1593 GNUNET_i2s (&neighbour->id),
1594 (mq->specific_address->addr != NULL)
1595 ? GNUNET_a2s (mq->specific_address->addr,
1596 mq->specific_address->addrlen)
1598 rl->plugin->short_name);
1600 GNUNET_STATISTICS_update (stats,
1601 gettext_noop ("# bytes in message queue for other peers"),
1602 - (int64_t) mq->message_buf_size,
1604 GNUNET_STATISTICS_update (stats,
1605 gettext_noop ("# bytes pending with plugins"),
1606 mq->message_buf_size,
1608 ret = rl->plugin->api->send (rl->plugin->api->cls,
1611 mq->message_buf_size,
1613 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1614 mq->specific_address->session,
1615 mq->specific_address->addr,
1616 mq->specific_address->addrlen,
1618 &transmit_send_continuation, mq);
1621 /* failure, but 'send' would not call continuation in this case,
1622 so we need to do it here! */
1623 transmit_send_continuation (mq,
1631 * Send the specified message to the specified peer.
1633 * @param client source of the transmission request (can be NULL)
1634 * @param peer_address ForeignAddressList where we should send this message
1635 * @param priority how important is the message
1636 * @param timeout how long do we have to transmit?
1637 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1638 * @param message_buf_size total size of all messages in message_buf
1639 * @param is_internal is this an internal message; these are pre-pended and
1640 * also do not count for plugins being "ready" to transmit
1641 * @param neighbour handle to the neighbour for transmission
1644 transmit_to_peer (struct TransportClient *client,
1645 struct ForeignAddressList *peer_address,
1646 unsigned int priority,
1647 struct GNUNET_TIME_Relative timeout,
1648 const char *message_buf,
1649 size_t message_buf_size,
1650 int is_internal, struct NeighbourList *neighbour)
1652 struct MessageQueue *mq;
1657 /* check for duplicate submission */
1658 mq = neighbour->messages_head;
1661 if (mq->client == client)
1663 /* client transmitted to same peer twice
1664 before getting SEND_OK! */
1672 GNUNET_STATISTICS_update (stats,
1673 gettext_noop ("# bytes in message queue for other peers"),
1676 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1677 mq->specific_address = peer_address;
1678 mq->client = client;
1679 memcpy (&mq[1], message_buf, message_buf_size);
1680 mq->message_buf = (const char*) &mq[1];
1681 mq->message_buf_size = message_buf_size;
1682 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1683 mq->internal_msg = is_internal;
1684 mq->priority = priority;
1685 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1687 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1688 neighbour->messages_tail,
1691 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1692 neighbour->messages_tail,
1693 neighbour->messages_tail,
1695 try_transmission_to_peer (neighbour);
1702 struct GeneratorContext
1704 struct TransportPlugin *plug_pos;
1705 struct OwnAddressList *addr_pos;
1706 struct GNUNET_TIME_Absolute expiration;
1714 address_generator (void *cls, size_t max, void *buf)
1716 struct GeneratorContext *gc = cls;
1719 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1721 gc->plug_pos = gc->plug_pos->next;
1722 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1724 if (NULL == gc->plug_pos)
1729 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1732 gc->addr_pos->addrlen, buf, max);
1733 gc->addr_pos = gc->addr_pos->next;
1739 * Construct our HELLO message from all of the addresses of
1740 * all of the transports.
1745 struct GNUNET_HELLO_Message *hello;
1746 struct TransportClient *cpos;
1747 struct NeighbourList *npos;
1748 struct GeneratorContext gc;
1750 gc.plug_pos = plugins;
1751 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1752 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1753 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1756 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1758 GNUNET_STATISTICS_update (stats,
1759 gettext_noop ("# refreshed my HELLO"),
1763 while (cpos != NULL)
1765 transmit_to_client (cpos,
1766 (const struct GNUNET_MessageHeader *) hello,
1771 GNUNET_free_non_null (our_hello);
1773 our_hello_version++;
1774 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1776 while (npos != NULL)
1779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1780 "Transmitting updated `%s' to neighbour `%4s'\n",
1781 "HELLO", GNUNET_i2s (&npos->id));
1783 GNUNET_STATISTICS_update (stats,
1784 gettext_noop ("# transmitted my HELLO to other peers"),
1787 transmit_to_peer (NULL, NULL, 0,
1788 HELLO_ADDRESS_EXPIRATION,
1789 (const char *) our_hello,
1790 GNUNET_HELLO_size(our_hello),
1798 * Task used to clean up expired addresses for a plugin.
1800 * @param cls closure
1804 expire_address_task (void *cls,
1805 const struct GNUNET_SCHEDULER_TaskContext *tc);
1809 * Update the list of addresses for this plugin,
1810 * expiring those that are past their expiration date.
1812 * @param plugin addresses of which plugin should be recomputed?
1813 * @param fresh set to GNUNET_YES if a new address was added
1814 * and we need to regenerate the HELLO even if nobody
1818 update_addresses (struct TransportPlugin *plugin, int fresh)
1820 static struct GNUNET_TIME_Absolute last_update;
1821 struct GNUNET_TIME_Relative min_remaining;
1822 struct GNUNET_TIME_Relative remaining;
1823 struct GNUNET_TIME_Absolute now;
1824 struct OwnAddressList *pos;
1825 struct OwnAddressList *prev;
1826 struct OwnAddressList *next;
1829 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1830 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1831 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1832 now = GNUNET_TIME_absolute_get ();
1833 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1834 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1836 pos = plugin->addresses;
1840 if (pos->expires.value < now.value)
1842 expired = GNUNET_YES;
1844 plugin->addresses = pos->next;
1846 prev->next = pos->next;
1851 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1852 if (remaining.value < min_remaining.value)
1853 min_remaining = remaining;
1859 if (expired || fresh)
1864 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1865 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1867 plugin->address_update_task
1868 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1870 &expire_address_task, plugin);
1875 * Task used to clean up expired addresses for a plugin.
1877 * @param cls closure
1881 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1883 struct TransportPlugin *plugin = cls;
1885 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1886 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1887 update_addresses (plugin, GNUNET_NO);
1892 * Iterator over hash map entries that NULLs the session of validation
1893 * entries that match the given session.
1895 * @param cls closure (the 'struct Session*' to match against)
1896 * @param key current key code (peer ID, not used)
1897 * @param value value in the hash map ('struct ValidationEntry*')
1898 * @return GNUNET_YES (we should continue to iterate)
1901 remove_session_validations (void *cls,
1902 const GNUNET_HashCode * key,
1905 struct Session *session = cls;
1906 struct ValidationEntry *ve = value;
1908 if (session == ve->session)
1915 * Function that will be called whenever the plugin internally
1916 * cleans up a session pointer and hence the service needs to
1917 * discard all of those sessions as well. Plugins that do not
1918 * use sessions can simply omit calling this function and always
1919 * use NULL wherever a session pointer is needed.
1921 * @param cls closure
1922 * @param peer which peer was the session for
1923 * @param session which session is being destoyed
1926 plugin_env_session_end (void *cls,
1927 const struct GNUNET_PeerIdentity *peer,
1928 struct Session *session)
1930 struct TransportPlugin *p = cls;
1931 struct NeighbourList *nl;
1932 struct ReadyList *rl;
1933 struct ForeignAddressList *pos;
1934 struct ForeignAddressList *prev;
1936 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1937 &remove_session_validations,
1939 nl = find_neighbour (peer);
1945 if (rl->plugin == p)
1952 pos = rl->addresses;
1953 while ( (pos != NULL) &&
1954 (pos->session != session) )
1961 pos->session = NULL;
1962 if (pos->addrlen != 0)
1965 rl->addresses = pos->next;
1967 prev->next = pos->next;
1968 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
1970 GNUNET_SCHEDULER_cancel (sched,
1971 pos->revalidate_task);
1972 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
1975 if (nl->received_pong == GNUNET_NO)
1976 return; /* nothing to do */
1977 /* check if we have any validated addresses left */
1978 pos = rl->addresses;
1985 /* no valid addresses left, signal disconnect! */
1986 disconnect_neighbour (nl, GNUNET_NO);
1991 * Function that must be called by each plugin to notify the
1992 * transport service about the addresses under which the transport
1993 * provided by the plugin can be reached.
1995 * @param cls closure
1996 * @param name name of the transport that generated the address
1997 * @param addr one of the addresses of the host, NULL for the last address
1998 * the specific address format depends on the transport
1999 * @param addrlen length of the address
2000 * @param expires when should this address automatically expire?
2003 plugin_env_notify_address (void *cls,
2007 struct GNUNET_TIME_Relative expires)
2009 struct TransportPlugin *p = cls;
2010 struct OwnAddressList *al;
2011 struct GNUNET_TIME_Absolute abex;
2013 GNUNET_assert (addr != NULL);
2014 abex = GNUNET_TIME_relative_to_absolute (expires);
2015 GNUNET_assert (p == find_transport (name));
2019 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2021 if (al->expires.value < abex.value)
2028 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2030 al->next = p->addresses;
2033 al->addrlen = addrlen;
2034 memcpy (&al[1], addr, addrlen);
2035 update_addresses (p, GNUNET_YES);
2040 * Notify all of our clients about a peer connecting.
2043 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2044 struct GNUNET_TIME_Relative latency,
2047 struct ConnectInfoMessage cim;
2048 struct TransportClient *cpos;
2051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052 "Notifying clients about connection from `%s'\n",
2055 GNUNET_STATISTICS_update (stats,
2056 gettext_noop ("# peers connected"),
2059 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2060 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2061 cim.distance = htonl (distance);
2062 cim.latency = GNUNET_TIME_relative_hton (latency);
2063 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
2065 while (cpos != NULL)
2067 transmit_to_client (cpos, &cim.header, GNUNET_NO);
2074 * Notify all of our clients about a peer disconnecting.
2077 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2079 struct DisconnectInfoMessage dim;
2080 struct TransportClient *cpos;
2083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084 "Notifying clients about lost connection to `%s'\n",
2087 GNUNET_STATISTICS_update (stats,
2088 gettext_noop ("# peers connected"),
2091 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2092 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2093 dim.reserved = htonl (0);
2094 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2096 while (cpos != NULL)
2098 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2105 * Find a ForeignAddressList entry for the given neighbour
2106 * that matches the given address and transport.
2108 * @param neighbour which peer we care about
2109 * @param tname name of the transport plugin
2110 * @param session session to look for, NULL for 'any'; otherwise
2111 * can be used for the service to "learn" this session ID
2113 * @param addr binary address
2114 * @param addrlen length of addr
2115 * @return NULL if no such entry exists
2117 static struct ForeignAddressList *
2118 find_peer_address(struct NeighbourList *neighbour,
2120 struct Session *session,
2124 struct ReadyList *head;
2125 struct ForeignAddressList *pos;
2127 head = neighbour->plugins;
2128 while (head != NULL)
2130 if (0 == strcmp (tname, head->plugin->short_name))
2136 pos = head->addresses;
2137 while ( (pos != NULL) &&
2138 ( (pos->addrlen != addrlen) ||
2139 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2141 if ( (session != NULL) &&
2142 (pos->session == session) )
2146 if ( (session != NULL) && (pos != NULL) )
2147 pos->session = session; /* learn it! */
2153 * Get the peer address struct for the given neighbour and
2154 * address. If it doesn't yet exist, create it.
2156 * @param neighbour which peer we care about
2157 * @param tname name of the transport plugin
2158 * @param session session of the plugin, or NULL for none
2159 * @param addr binary address
2160 * @param addrlen length of addr
2161 * @return NULL if we do not have a transport plugin for 'tname'
2163 static struct ForeignAddressList *
2164 add_peer_address (struct NeighbourList *neighbour,
2166 struct Session *session,
2170 struct ReadyList *head;
2171 struct ForeignAddressList *ret;
2173 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2176 head = neighbour->plugins;
2178 while (head != NULL)
2180 if (0 == strcmp (tname, head->plugin->short_name))
2186 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2187 ret->session = session;
2190 ret->addr = (const char*) &ret[1];
2191 memcpy (&ret[1], addr, addrlen);
2197 ret->addrlen = addrlen;
2198 ret->expires = GNUNET_TIME_relative_to_absolute
2199 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2200 ret->latency = GNUNET_TIME_relative_get_forever();
2202 ret->timeout = GNUNET_TIME_relative_to_absolute
2203 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2204 ret->ready_list = head;
2205 ret->next = head->addresses;
2206 head->addresses = ret;
2212 * Closure for 'add_validated_address'.
2214 struct AddValidatedAddressContext
2217 * Entry that has been validated.
2219 const struct ValidationEntry *ve;
2222 * Flag set after we have added the address so
2223 * that we terminate the iteration next time.
2230 * Callback function used to fill a buffer of max bytes with a list of
2231 * addresses in the format used by HELLOs. Should use
2232 * "GNUNET_HELLO_add_address" as a helper function.
2234 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2235 * @param max maximum number of bytes that can be written to buf
2236 * @param buf where to write the address information
2237 * @return number of bytes written, 0 to signal the
2238 * end of the iteration.
2241 add_validated_address (void *cls,
2242 size_t max, void *buf)
2244 struct AddValidatedAddressContext *avac = cls;
2245 const struct ValidationEntry *ve = avac->ve;
2247 if (GNUNET_YES == avac->done)
2249 avac->done = GNUNET_YES;
2250 return GNUNET_HELLO_add_address (ve->transport_name,
2251 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2261 * Closure for 'check_address_exists'.
2263 struct CheckAddressExistsClosure
2266 * Address to check for.
2271 * Name of the transport.
2278 struct Session *session;
2286 * Set to GNUNET_YES if the address exists.
2293 * Iterator over hash map entries. Checks if the given
2294 * validation entry is for the same address as what is given
2297 * @param cls the 'struct CheckAddressExistsClosure*'
2298 * @param key current key code (ignored)
2299 * @param value value in the hash map ('struct ValidationEntry')
2300 * @return GNUNET_YES if we should continue to
2301 * iterate (mismatch), GNUNET_NO if not (entry matched)
2304 check_address_exists (void *cls,
2305 const GNUNET_HashCode * key,
2308 struct CheckAddressExistsClosure *caec = cls;
2309 struct ValidationEntry *ve = value;
2311 if ( (0 == strcmp (caec->tname,
2312 ve->transport_name)) &&
2313 (caec->addrlen == ve->addrlen) &&
2314 (0 == memcmp (caec->addr,
2318 caec->exists = GNUNET_YES;
2321 if ( (ve->session != NULL) &&
2322 (caec->session == ve->session) )
2324 caec->exists = GNUNET_YES;
2332 * HELLO validation cleanup task (validation failed).
2334 * @param cls the 'struct ValidationEntry' that failed
2335 * @param tc scheduler context (unused)
2338 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2340 struct ValidationEntry *va = cls;
2341 struct GNUNET_PeerIdentity pid;
2343 GNUNET_STATISTICS_update (stats,
2344 gettext_noop ("# address validation timeouts"),
2347 GNUNET_CRYPTO_hash (&va->publicKey,
2349 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2351 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2354 GNUNET_free (va->transport_name);
2360 neighbour_timeout_task (void *cls,
2361 const struct GNUNET_SCHEDULER_TaskContext *tc)
2363 struct NeighbourList *n = cls;
2366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2367 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2369 GNUNET_STATISTICS_update (stats,
2370 gettext_noop ("# disconnects due to timeout"),
2373 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2374 disconnect_neighbour (n, GNUNET_NO);
2379 * Schedule the job that will cause us to send a PING to the
2380 * foreign address to evaluate its validity and latency.
2382 * @param fal address to PING
2385 schedule_next_ping (struct ForeignAddressList *fal);
2389 * Add the given address to the list of foreign addresses
2390 * available for the given peer (check for duplicates).
2392 * @param cls the respective 'struct NeighbourList' to update
2393 * @param tname name of the transport
2394 * @param expiration expiration time
2395 * @param addr the address
2396 * @param addrlen length of the address
2397 * @return GNUNET_OK (always)
2400 add_to_foreign_address_list (void *cls,
2402 struct GNUNET_TIME_Absolute expiration,
2403 const void *addr, size_t addrlen)
2405 struct NeighbourList *n = cls;
2406 struct ForeignAddressList *fal;
2409 GNUNET_STATISTICS_update (stats,
2410 gettext_noop ("# valid peer addresses returned by peerinfo"),
2414 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2419 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2420 GNUNET_a2s (addr, addrlen),
2422 GNUNET_i2s (&n->id),
2425 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2428 GNUNET_STATISTICS_update (stats,
2429 gettext_noop ("# previously validated addresses lacking transport"),
2435 fal->expires = GNUNET_TIME_absolute_max (expiration,
2437 schedule_next_ping (fal);
2443 fal->expires = GNUNET_TIME_absolute_max (expiration,
2448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2449 "Failed to add new address for `%4s'\n",
2450 GNUNET_i2s (&n->id));
2453 if (fal->validated == GNUNET_NO)
2455 fal->validated = GNUNET_YES;
2456 GNUNET_STATISTICS_update (stats,
2457 gettext_noop ("# peer addresses considered valid"),
2461 if (try == GNUNET_YES)
2463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464 "Have new addresses, will try to trigger transmissions.\n");
2465 try_transmission_to_peer (n);
2472 * Add addresses in validated HELLO "h" to the set of addresses
2473 * we have for this peer.
2475 * @param cls closure ('struct NeighbourList*')
2476 * @param peer id of the peer, NULL for last call
2477 * @param h hello message for the peer (can be NULL)
2478 * @param trust amount of trust we have in the peer (not used)
2481 add_hello_for_peer (void *cls,
2482 const struct GNUNET_PeerIdentity *peer,
2483 const struct GNUNET_HELLO_Message *h,
2486 struct NeighbourList *n = cls;
2494 return; /* no HELLO available */
2496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2497 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2501 if (GNUNET_YES != n->public_key_valid)
2503 GNUNET_HELLO_get_key (h, &n->publicKey);
2504 n->public_key_valid = GNUNET_YES;
2506 GNUNET_HELLO_iterate_addresses (h,
2508 &add_to_foreign_address_list,
2514 * Create a fresh entry in our neighbour list for the given peer.
2515 * Will try to transmit our current HELLO to the new neighbour.
2517 * @param peer the peer for which we create the entry
2518 * @return the new neighbour list entry
2520 static struct NeighbourList *
2521 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2523 struct NeighbourList *n;
2524 struct TransportPlugin *tp;
2525 struct ReadyList *rl;
2527 GNUNET_assert (our_hello != NULL);
2528 GNUNET_STATISTICS_update (stats,
2529 gettext_noop ("# active neighbours"),
2532 n = GNUNET_malloc (sizeof (struct NeighbourList));
2533 n->next = neighbours;
2537 GNUNET_TIME_relative_to_absolute
2538 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2539 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2540 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2541 MAX_BANDWIDTH_CARRY_S);
2545 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2547 rl = GNUNET_malloc (sizeof (struct ReadyList));
2549 rl->next = n->plugins;
2552 rl->addresses = NULL;
2556 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2558 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2559 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2560 &neighbour_timeout_task, n);
2561 n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2562 0, GNUNET_TIME_UNIT_FOREVER_REL,
2563 &add_hello_for_peer, n);
2564 transmit_to_peer (NULL, NULL, 0,
2565 HELLO_ADDRESS_EXPIRATION,
2566 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2573 * Send periodic PING messages to a give foreign address.
2575 * @param cls our 'struct PeriodicValidationContext*'
2576 * @param tc task context
2579 send_periodic_ping (void *cls,
2580 const struct GNUNET_SCHEDULER_TaskContext *tc)
2582 struct ForeignAddressList *peer_address = cls;
2583 struct TransportPlugin *tp;
2584 struct ValidationEntry *va;
2585 struct NeighbourList *neighbour;
2586 struct TransportPingMessage ping;
2587 struct CheckAddressExistsClosure caec;
2589 uint16_t hello_size;
2592 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2593 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2595 tp = peer_address->ready_list->plugin;
2596 neighbour = peer_address->ready_list->neighbour;
2597 if (GNUNET_YES != neighbour->public_key_valid)
2599 /* no public key yet, try again later */
2600 schedule_next_ping (peer_address);
2603 caec.addr = peer_address->addr;
2604 caec.addrlen = peer_address->addrlen;
2605 caec.tname = tp->short_name;
2606 caec.session = peer_address->session;
2607 caec.exists = GNUNET_NO;
2608 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2609 &check_address_exists,
2611 if (caec.exists == GNUNET_YES)
2613 /* During validation attempts we will likely trigger the other
2614 peer trying to validate our address which in turn will cause
2615 it to send us its HELLO, so we expect to hit this case rather
2616 frequently. Only print something if we are very verbose. */
2617 #if DEBUG_TRANSPORT > 1
2618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2619 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2620 (peer_address->addr != NULL)
2621 ? GNUNET_a2s (peer_address->addr,
2622 peer_address->addrlen)
2625 GNUNET_i2s (&neighbour->id));
2627 schedule_next_ping (peer_address);
2630 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2631 va->transport_name = GNUNET_strdup (tp->short_name);
2632 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2634 va->send_time = GNUNET_TIME_absolute_get();
2635 va->session = peer_address->session;
2636 if (peer_address->addr != NULL)
2638 va->addr = (const void*) &va[1];
2639 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2640 va->addrlen = peer_address->addrlen;
2642 memcpy(&va->publicKey,
2643 &neighbour->publicKey,
2644 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2646 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2647 HELLO_VERIFICATION_TIMEOUT,
2648 &timeout_hello_validation,
2650 GNUNET_CONTAINER_multihashmap_put (validation_map,
2651 &neighbour->id.hashPubKey,
2653 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2654 hello_size = GNUNET_HELLO_size(our_hello);
2655 tsize = sizeof(struct TransportPingMessage) + hello_size;
2656 message_buf = GNUNET_malloc(tsize);
2657 ping.challenge = htonl(va->challenge);
2658 ping.header.size = htons(sizeof(struct TransportPingMessage));
2659 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2660 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2661 memcpy(message_buf, our_hello, hello_size);
2662 memcpy(&message_buf[hello_size],
2664 sizeof(struct TransportPingMessage));
2665 #if DEBUG_TRANSPORT_REVALIDATION
2666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2667 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2668 (peer_address->addr != NULL)
2669 ? GNUNET_a2s (peer_address->addr,
2670 peer_address->addrlen)
2673 GNUNET_i2s (&neighbour->id),
2674 "HELLO", hello_size,
2675 "PING", sizeof (struct TransportPingMessage));
2677 GNUNET_STATISTICS_update (stats,
2678 gettext_noop ("# PING messages sent for re-validation"),
2681 transmit_to_peer (NULL, peer_address,
2682 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2683 HELLO_VERIFICATION_TIMEOUT,
2685 GNUNET_YES, neighbour);
2686 GNUNET_free(message_buf);
2687 schedule_next_ping (peer_address);
2692 * Schedule the job that will cause us to send a PING to the
2693 * foreign address to evaluate its validity and latency.
2695 * @param fal address to PING
2698 schedule_next_ping (struct ForeignAddressList *fal)
2700 struct GNUNET_TIME_Relative delay;
2702 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2704 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2705 delay.value /= 2; /* do before expiration */
2706 delay = GNUNET_TIME_relative_min (delay,
2707 LATENCY_EVALUATION_MAX_DELAY);
2708 if (GNUNET_YES != fal->estimated)
2710 delay = GNUNET_TIME_UNIT_ZERO;
2711 fal->estimated = GNUNET_YES;
2713 if (GNUNET_YES == fal->connected)
2715 delay = GNUNET_TIME_relative_min (delay,
2716 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2718 /* FIXME: also adjust delay based on how close the last
2719 observed latency is to the latency of the best alternative */
2720 /* bound how fast we can go */
2721 delay = GNUNET_TIME_relative_max (delay,
2722 GNUNET_TIME_UNIT_SECONDS);
2723 /* randomize a bit (to avoid doing all at the same time) */
2724 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2725 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
2727 &send_periodic_ping,
2735 * Function that will be called if we receive some payload
2736 * from another peer.
2738 * @param message the payload
2739 * @param n peer who claimed to be the sender
2742 handle_payload_message (const struct GNUNET_MessageHeader *message,
2743 struct NeighbourList *n)
2745 struct InboundMessage *im;
2746 struct TransportClient *cpos;
2749 msize = ntohs (message->size);
2750 if (n->received_pong == GNUNET_NO)
2752 GNUNET_free_non_null (n->pre_connect_message_buffer);
2753 n->pre_connect_message_buffer = GNUNET_malloc (msize);
2754 memcpy (n->pre_connect_message_buffer, message, msize);
2758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2759 "Received message of type %u from `%4s', sending to all clients.\n",
2760 ntohs (message->type),
2761 GNUNET_i2s (&n->id));
2763 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2766 n->quota_violation_count++;
2768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2769 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
2770 n->in_tracker.available_bytes_per_s__,
2771 n->quota_violation_count);
2773 /* Discount 32k per violation */
2774 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2779 if (n->quota_violation_count > 0)
2781 /* try to add 32k back */
2782 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2784 n->quota_violation_count--;
2787 GNUNET_STATISTICS_update (stats,
2788 gettext_noop ("# payload received from other peers"),
2791 /* transmit message to all clients */
2792 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2793 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2794 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2795 im->latency = GNUNET_TIME_relative_hton (n->latency);
2797 memcpy (&im[1], message, msize);
2799 while (cpos != NULL)
2801 transmit_to_client (cpos, &im->header, GNUNET_YES);
2809 * Iterator over hash map entries. Checks if the given validation
2810 * entry is for the same challenge as what is given in the PONG.
2812 * @param cls the 'struct TransportPongMessage*'
2813 * @param key peer identity
2814 * @param value value in the hash map ('struct ValidationEntry')
2815 * @return GNUNET_YES if we should continue to
2816 * iterate (mismatch), GNUNET_NO if not (entry matched)
2819 check_pending_validation (void *cls,
2820 const GNUNET_HashCode * key,
2823 const struct TransportPongMessage *pong = cls;
2824 struct ValidationEntry *ve = value;
2825 struct AddValidatedAddressContext avac;
2826 unsigned int challenge = ntohl(pong->challenge);
2827 struct GNUNET_HELLO_Message *hello;
2828 struct GNUNET_PeerIdentity target;
2829 struct NeighbourList *n;
2830 struct ForeignAddressList *fal;
2831 struct GNUNET_MessageHeader *prem;
2833 if (ve->challenge != challenge)
2836 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
2841 GNUNET_break_op (0);
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2850 ? GNUNET_a2s ((const struct sockaddr *) ve->addr,
2853 ve->transport_name);
2855 GNUNET_STATISTICS_update (stats,
2856 gettext_noop ("# address validation successes"),
2859 /* create the updated HELLO */
2860 GNUNET_CRYPTO_hash (&ve->publicKey,
2861 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2862 &target.hashPubKey);
2863 if (ve->addr != NULL)
2865 avac.done = GNUNET_NO;
2867 hello = GNUNET_HELLO_create (&ve->publicKey,
2868 &add_validated_address,
2870 GNUNET_PEERINFO_add_peer (cfg, sched,
2873 GNUNET_free (hello);
2875 n = find_neighbour (&target);
2878 n->publicKey = ve->publicKey;
2879 n->public_key_valid = GNUNET_YES;
2880 fal = add_peer_address (n,
2885 GNUNET_assert (fal != NULL);
2886 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2887 fal->validated = GNUNET_YES;
2888 mark_address_connected (fal);
2889 GNUNET_STATISTICS_update (stats,
2890 gettext_noop ("# peer addresses considered valid"),
2893 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2894 schedule_next_ping (fal);
2895 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2896 n->latency = fal->latency;
2898 n->latency.value = (fal->latency.value + n->latency.value) / 2;
2899 n->distance = fal->distance;
2900 if (GNUNET_NO == n->received_pong)
2902 n->received_pong = GNUNET_YES;
2903 notify_clients_connect (&target, n->latency, n->distance);
2904 if (NULL != (prem = n->pre_connect_message_buffer))
2906 n->pre_connect_message_buffer = NULL;
2907 handle_payload_message (prem, n);
2911 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2913 GNUNET_SCHEDULER_cancel (sched,
2915 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2916 try_transmission_to_peer (n);
2920 /* clean up validation entry */
2921 GNUNET_assert (GNUNET_YES ==
2922 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2925 GNUNET_SCHEDULER_cancel (sched,
2927 GNUNET_free (ve->transport_name);
2934 * Function that will be called if we receive a validation
2935 * of an address challenge that we transmitted to another
2936 * peer. Note that the validation should only be considered
2937 * acceptable if the challenge matches AND if the sender
2938 * address is at least a plausible address for this peer
2939 * (otherwise we may be seeing a MiM attack).
2941 * @param cls closure
2942 * @param message the pong message
2943 * @param peer who responded to our challenge
2944 * @param sender_address string describing our sender address (as observed
2945 * by the other peer in binary format)
2946 * @param sender_address_len number of bytes in 'sender_address'
2949 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2950 const struct GNUNET_PeerIdentity *peer,
2951 const char *sender_address,
2952 size_t sender_address_len)
2954 #if DEBUG_TRANSPORT > 1
2955 /* we get tons of these that just get discarded, only log
2956 if we are quite verbose */
2957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2958 "Receiving `%s' message from `%4s'.\n", "PONG",
2961 GNUNET_STATISTICS_update (stats,
2962 gettext_noop ("# PONG messages received"),
2965 if (GNUNET_SYSERR !=
2966 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2968 &check_pending_validation,
2971 /* This is *expected* to happen a lot since we send
2972 PONGs to *all* known addresses of the sender of
2973 the PING, so most likely we get multiple PONGs
2974 per PING, and all but the first PONG will end up
2975 here. So really we should not print anything here
2976 unless we want to be very, very verbose... */
2977 #if DEBUG_TRANSPORT > 2
2978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2979 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2988 /* FIXME: add given address to potential pool of our addresses
2990 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2991 _("Another peer saw us using the address `%s' via `%s'.\n"),
2992 GNUNET_a2s ((const struct sockaddr *) &pong[1],
2993 ntohs(pong->addrlen)),
2994 va->transport_name);
3000 * Check if the given address is already being validated; if not,
3001 * append the given address to the list of entries that are being be
3002 * validated and initiate validation.
3004 * @param cls closure ('struct CheckHelloValidatedContext *')
3005 * @param tname name of the transport
3006 * @param expiration expiration time
3007 * @param addr the address
3008 * @param addrlen length of the address
3009 * @return GNUNET_OK (always)
3012 run_validation (void *cls,
3014 struct GNUNET_TIME_Absolute expiration,
3015 const void *addr, size_t addrlen)
3017 struct CheckHelloValidatedContext *chvc = cls;
3018 struct GNUNET_PeerIdentity id;
3019 struct TransportPlugin *tp;
3020 struct ValidationEntry *va;
3021 struct NeighbourList *neighbour;
3022 struct ForeignAddressList *peer_address;
3023 struct TransportPingMessage ping;
3024 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3025 struct CheckAddressExistsClosure caec;
3027 uint16_t hello_size;
3030 GNUNET_assert (addr != NULL);
3031 GNUNET_STATISTICS_update (stats,
3032 gettext_noop ("# peer addresses scheduled for validation"),
3035 tp = find_transport (tname);
3038 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3039 GNUNET_ERROR_TYPE_BULK,
3041 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3043 GNUNET_STATISTICS_update (stats,
3044 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
3049 GNUNET_HELLO_get_key (chvc->hello, &pk);
3050 GNUNET_CRYPTO_hash (&pk,
3052 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3055 if (is_blacklisted(&id, tp))
3058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3059 _("Attempted to validate blacklisted peer `%s' using `%s'!\n"), GNUNET_i2s(&id), tname);
3065 caec.addrlen = addrlen;
3066 caec.session = NULL;
3068 caec.exists = GNUNET_NO;
3069 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3070 &check_address_exists,
3072 if (caec.exists == GNUNET_YES)
3074 /* During validation attempts we will likely trigger the other
3075 peer trying to validate our address which in turn will cause
3076 it to send us its HELLO, so we expect to hit this case rather
3077 frequently. Only print something if we are very verbose. */
3078 #if DEBUG_TRANSPORT > 1
3079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3080 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3081 GNUNET_a2s (addr, addrlen),
3085 GNUNET_STATISTICS_update (stats,
3086 gettext_noop ("# peer addresses not validated (in progress)"),
3091 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
3092 va->transport_name = GNUNET_strdup (tname);
3093 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3095 va->send_time = GNUNET_TIME_absolute_get();
3096 va->addr = (const void*) &va[1];
3097 memcpy (&va[1], addr, addrlen);
3098 va->addrlen = addrlen;
3099 GNUNET_HELLO_get_key (chvc->hello,
3101 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3102 HELLO_VERIFICATION_TIMEOUT,
3103 &timeout_hello_validation,
3105 GNUNET_CONTAINER_multihashmap_put (validation_map,
3108 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3109 neighbour = find_neighbour(&id);
3110 if (neighbour == NULL)
3111 neighbour = setup_new_neighbour(&id);
3112 neighbour->publicKey = va->publicKey;
3113 neighbour->public_key_valid = GNUNET_YES;
3114 peer_address = add_peer_address (neighbour, tname, NULL, addr, addrlen);
3115 if (peer_address == NULL)
3117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3118 "Attempted to add peer `%4s' for plugin `%s'\n",
3119 GNUNET_i2s (&id), tname);
3121 GNUNET_assert(peer_address != NULL);
3122 hello_size = GNUNET_HELLO_size(our_hello);
3123 tsize = sizeof(struct TransportPingMessage) + hello_size;
3124 message_buf = GNUNET_malloc(tsize);
3125 ping.challenge = htonl(va->challenge);
3126 ping.header.size = htons(sizeof(struct TransportPingMessage));
3127 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3128 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
3129 memcpy(message_buf, our_hello, hello_size);
3130 memcpy(&message_buf[hello_size],
3132 sizeof(struct TransportPingMessage));
3134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3135 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3136 GNUNET_a2s (addr, addrlen),
3139 "HELLO", hello_size,
3140 "PING", sizeof (struct TransportPingMessage));
3142 GNUNET_STATISTICS_update (stats,
3143 gettext_noop ("# PING messages sent for initial validation"),
3146 transmit_to_peer (NULL, peer_address,
3147 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3148 HELLO_VERIFICATION_TIMEOUT,
3150 GNUNET_YES, neighbour);
3151 GNUNET_free(message_buf);
3157 * Check if addresses in validated hello "h" overlap with
3158 * those in "chvc->hello" and validate the rest.
3160 * @param cls closure
3161 * @param peer id of the peer, NULL for last call
3162 * @param h hello message for the peer (can be NULL)
3163 * @param trust amount of trust we have in the peer (not used)
3166 check_hello_validated (void *cls,
3167 const struct GNUNET_PeerIdentity *peer,
3168 const struct GNUNET_HELLO_Message *h,
3171 struct CheckHelloValidatedContext *chvc = cls;
3172 struct GNUNET_HELLO_Message *plain_hello;
3173 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3174 struct GNUNET_PeerIdentity target;
3175 struct NeighbourList *n;
3180 GNUNET_CONTAINER_DLL_remove (chvc_head,
3183 if (GNUNET_NO == chvc->hello_known)
3185 /* notify PEERINFO about the peer now, so that we at least
3186 have the public key if some other component needs it */
3187 GNUNET_HELLO_get_key (chvc->hello, &pk);
3188 GNUNET_CRYPTO_hash (&pk,
3189 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3190 &target.hashPubKey);
3191 plain_hello = GNUNET_HELLO_create (&pk,
3194 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
3195 GNUNET_free (plain_hello);
3197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3198 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
3200 GNUNET_i2s (&target));
3202 GNUNET_STATISTICS_update (stats,
3203 gettext_noop ("# new HELLOs requiring full validation"),
3206 GNUNET_HELLO_iterate_addresses (chvc->hello,
3213 GNUNET_STATISTICS_update (stats,
3214 gettext_noop ("# duplicate HELLO (peer known)"),
3224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3225 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
3229 chvc->hello_known = GNUNET_YES;
3230 n = find_neighbour (peer);
3233 GNUNET_HELLO_iterate_addresses (h,
3235 &add_to_foreign_address_list,
3237 try_transmission_to_peer (n);
3241 GNUNET_STATISTICS_update (stats,
3242 gettext_noop ("# no existing neighbour record (validating HELLO)"),
3246 GNUNET_STATISTICS_update (stats,
3247 gettext_noop ("# HELLO validations (update case)"),
3250 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
3252 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
3258 * Process HELLO-message.
3260 * @param plugin transport involved, may be NULL
3261 * @param message the actual message
3262 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
3265 process_hello (struct TransportPlugin *plugin,
3266 const struct GNUNET_MessageHeader *message)
3269 struct GNUNET_PeerIdentity target;
3270 const struct GNUNET_HELLO_Message *hello;
3271 struct CheckHelloValidatedContext *chvc;
3272 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
3274 hsize = ntohs (message->size);
3275 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
3276 (hsize < sizeof (struct GNUNET_MessageHeader)))
3279 return GNUNET_SYSERR;
3281 GNUNET_STATISTICS_update (stats,
3282 gettext_noop ("# HELLOs received for validation"),
3285 /* first, check if load is too high */
3286 if (GNUNET_SCHEDULER_get_load (sched,
3287 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
3289 GNUNET_STATISTICS_update (stats,
3290 gettext_noop ("# HELLOs ignored due to high load"),
3295 hello = (const struct GNUNET_HELLO_Message *) message;
3296 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3298 GNUNET_break_op (0);
3299 return GNUNET_SYSERR;
3301 GNUNET_CRYPTO_hash (&publicKey,
3302 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3303 &target.hashPubKey);
3304 if (0 == memcmp (&my_identity,
3306 sizeof (struct GNUNET_PeerIdentity)))
3308 GNUNET_STATISTICS_update (stats,
3309 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3314 #if DEBUG_TRANSPORT > 1
3315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3316 "Processing `%s' message for `%4s' of size %u\n",
3318 GNUNET_i2s (&target),
3319 GNUNET_HELLO_size(hello));
3321 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3322 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3323 memcpy (&chvc[1], hello, hsize);
3324 GNUNET_CONTAINER_DLL_insert (chvc_head,
3327 /* finally, check if HELLO was previously validated
3328 (continuation will then schedule actual validation) */
3329 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
3333 HELLO_VERIFICATION_TIMEOUT,
3334 &check_hello_validated, chvc);
3340 * The peer specified by the given neighbour has timed-out or a plugin
3341 * has disconnected. We may either need to do nothing (other plugins
3342 * still up), or trigger a full disconnect and clean up. This
3343 * function updates our state and does the necessary notifications.
3344 * Also notifies our clients that the neighbour is now officially
3347 * @param n the neighbour list entry for the peer
3348 * @param check should we just check if all plugins
3349 * disconnected or must we ask all plugins to
3353 disconnect_neighbour (struct NeighbourList *n, int check)
3355 struct ReadyList *rpos;
3356 struct NeighbourList *npos;
3357 struct NeighbourList *nprev;
3358 struct MessageQueue *mq;
3359 struct ForeignAddressList *peer_addresses;
3360 struct ForeignAddressList *peer_pos;
3362 if (GNUNET_YES == check)
3365 while (NULL != rpos)
3367 peer_addresses = rpos->addresses;
3368 while (peer_addresses != NULL)
3370 if (GNUNET_YES == peer_addresses->connected)
3371 return; /* still connected */
3372 peer_addresses = peer_addresses->next;
3378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3379 "Disconnecting from `%4s'\n",
3380 GNUNET_i2s (&n->id));
3382 /* remove n from neighbours list */
3385 while ((npos != NULL) && (npos != n))
3390 GNUNET_assert (npos != NULL);
3392 neighbours = n->next;
3394 nprev->next = n->next;
3396 /* notify all clients about disconnect */
3397 if (GNUNET_YES == n->received_pong)
3398 notify_clients_disconnect (&n->id);
3400 /* clean up all plugins, cancel connections and pending transmissions */
3401 while (NULL != (rpos = n->plugins))
3403 n->plugins = rpos->next;
3404 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3405 while (rpos->addresses != NULL)
3407 peer_pos = rpos->addresses;
3408 rpos->addresses = peer_pos->next;
3409 if (peer_pos->connected == GNUNET_YES)
3410 GNUNET_STATISTICS_update (stats,
3411 gettext_noop ("# connected addresses"),
3414 if (GNUNET_YES == peer_pos->validated)
3415 GNUNET_STATISTICS_update (stats,
3416 gettext_noop ("# peer addresses considered valid"),
3419 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3421 GNUNET_SCHEDULER_cancel (sched,
3422 peer_pos->revalidate_task);
3423 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3425 GNUNET_free(peer_pos);
3430 /* free all messages on the queue */
3431 while (NULL != (mq = n->messages_head))
3433 GNUNET_STATISTICS_update (stats,
3434 gettext_noop ("# bytes in message queue for other peers"),
3435 - (int64_t) mq->message_buf_size,
3437 GNUNET_STATISTICS_update (stats,
3438 gettext_noop ("# bytes discarded due to disconnect"),
3439 mq->message_buf_size,
3441 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3444 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3446 sizeof(struct GNUNET_PeerIdentity)));
3449 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3451 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3452 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3454 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3456 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3457 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3459 if (n->piter != NULL)
3461 GNUNET_PEERINFO_iterate_cancel (n->piter);
3464 /* finally, free n itself */
3465 GNUNET_STATISTICS_update (stats,
3466 gettext_noop ("# active neighbours"),
3469 GNUNET_free_non_null (n->pre_connect_message_buffer);
3475 * We have received a PING message from someone. Need to send a PONG message
3476 * in response to the peer by any means necessary.
3479 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3480 const struct GNUNET_PeerIdentity *peer,
3481 const char *sender_address,
3482 size_t sender_address_len)
3484 struct TransportPlugin *plugin = cls;
3485 struct TransportPingMessage *ping;
3486 struct TransportPongMessage *pong;
3487 struct NeighbourList *n;
3488 struct ReadyList *rl;
3489 struct ForeignAddressList *fal;
3491 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3493 GNUNET_break_op (0);
3494 return GNUNET_SYSERR;
3497 ping = (struct TransportPingMessage *) message;
3498 if (0 != memcmp (&ping->target,
3499 plugin->env.my_identity,
3500 sizeof (struct GNUNET_PeerIdentity)))
3502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3503 _("Received `%s' message not destined for me!\n"),
3505 return GNUNET_SYSERR;
3508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3509 "Processing `%s' from `%s'\n",
3511 (sender_address != NULL)
3512 ? GNUNET_a2s ((const struct sockaddr *)sender_address,
3516 GNUNET_STATISTICS_update (stats,
3517 gettext_noop ("# PING messages received"),
3520 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3521 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3522 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3523 pong->purpose.size =
3524 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3526 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3527 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3528 pong->challenge = ping->challenge;
3529 pong->addrlen = htons(sender_address_len);
3530 memcpy(&pong->signer,
3532 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3533 if (sender_address != NULL)
3534 memcpy (&pong[1], sender_address, sender_address_len);
3535 GNUNET_assert (GNUNET_OK ==
3536 GNUNET_CRYPTO_rsa_sign (my_private_key,
3537 &pong->purpose, &pong->signature));
3538 n = find_neighbour(peer);
3539 GNUNET_assert (n != NULL);
3540 /* first try reliable response transmission */
3544 fal = rl->addresses;
3547 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3550 ntohs (pong->header.size),
3551 TRANSPORT_PONG_PRIORITY,
3552 HELLO_VERIFICATION_TIMEOUT,
3560 GNUNET_STATISTICS_update (stats,
3561 gettext_noop ("# PONGs unicast via reliable transport"),
3571 /* no reliable method found, do multicast */
3572 GNUNET_STATISTICS_update (stats,
3573 gettext_noop ("# PONGs multicast to all available addresses"),
3579 fal = rl->addresses;
3582 transmit_to_peer(NULL, fal,
3583 TRANSPORT_PONG_PRIORITY,
3584 HELLO_VERIFICATION_TIMEOUT,
3586 ntohs(pong->header.size),
3599 * Function called by the plugin for each received message.
3600 * Update data volumes, possibly notify plugins about
3601 * reducing the rate at which they read from the socket
3602 * and generally forward to our receive callback.
3604 * @param cls the "struct TransportPlugin *" we gave to the plugin
3605 * @param peer (claimed) identity of the other peer
3606 * @param message the message, NULL if we only care about
3607 * learning about the delay until we should receive again
3608 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3609 * @param session identifier used for this session (can be NULL)
3610 * @param sender_address binary address of the sender (if observed)
3611 * @param sender_address_len number of bytes in sender_address
3612 * @return how long the plugin should wait until receiving more data
3613 * (plugins that do not support this, can ignore the return value)
3615 static struct GNUNET_TIME_Relative
3616 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3617 const struct GNUNET_MessageHeader *message,
3618 unsigned int distance,
3619 struct Session *session,
3620 const char *sender_address,
3621 size_t sender_address_len)
3623 struct TransportPlugin *plugin = cls;
3624 struct ReadyList *service_context;
3625 struct ForeignAddressList *peer_address;
3627 struct NeighbourList *n;
3628 struct GNUNET_TIME_Relative ret;
3630 if (is_blacklisted(peer, plugin))
3631 return GNUNET_TIME_UNIT_FOREVER_REL;
3633 n = find_neighbour (peer);
3635 n = setup_new_neighbour (peer);
3636 service_context = n->plugins;
3637 while ((service_context != NULL) && (plugin != service_context->plugin))
3638 service_context = service_context->next;
3639 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3640 peer_address = NULL;
3641 if (message != NULL)
3643 if ( (session != NULL) ||
3644 (sender_address != NULL) )
3645 peer_address = add_peer_address (n,
3649 sender_address_len);
3650 if (peer_address != NULL)
3652 peer_address->distance = distance;
3653 if (GNUNET_YES == peer_address->validated)
3654 mark_address_connected (peer_address);
3655 peer_address->timeout
3657 GNUNET_TIME_relative_to_absolute
3658 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3659 schedule_next_ping (peer_address);
3661 /* update traffic received amount ... */
3662 msize = ntohs (message->size);
3663 GNUNET_STATISTICS_update (stats,
3664 gettext_noop ("# bytes received from other peers"),
3667 n->distance = distance;
3669 GNUNET_TIME_relative_to_absolute
3670 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3671 GNUNET_SCHEDULER_cancel (sched,
3674 GNUNET_SCHEDULER_add_delayed (sched,
3675 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3676 &neighbour_timeout_task, n);
3677 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3679 /* dropping message due to frequent inbound volume violations! */
3680 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3681 GNUNET_ERROR_TYPE_BULK,
3683 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
3684 n->in_tracker.available_bytes_per_s__,
3685 n->quota_violation_count);
3686 GNUNET_STATISTICS_update (stats,
3687 gettext_noop ("# bandwidth quota violations by other peers"),
3690 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
3693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3694 "Received message of type %u from `%4s', sending to all clients.\n",
3695 ntohs (message->type), GNUNET_i2s (peer));
3697 switch (ntohs (message->type))
3699 case GNUNET_MESSAGE_TYPE_HELLO:
3700 GNUNET_STATISTICS_update (stats,
3701 gettext_noop ("# HELLO messages received from other peers"),
3704 process_hello (plugin, message);
3706 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3707 handle_ping (plugin, message, peer, sender_address, sender_address_len);
3709 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3710 handle_pong (plugin, message, peer, sender_address, sender_address_len);
3713 handle_payload_message (message, n);
3717 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3720 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3721 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3722 (unsigned long long) n->in_tracker.consumption_since_last_update__,
3723 (unsigned int) n->in_tracker.available_bytes_per_s__,
3724 (unsigned long long) ret.value);
3725 GNUNET_STATISTICS_update (stats,
3726 gettext_noop ("# ms throttling suggested"),
3727 (int64_t) ret.value,
3734 * Handle START-message. This is the first message sent to us
3735 * by any client which causes us to add it to our list.
3737 * @param cls closure (always NULL)
3738 * @param client identification of the client
3739 * @param message the actual message
3742 handle_start (void *cls,
3743 struct GNUNET_SERVER_Client *client,
3744 const struct GNUNET_MessageHeader *message)
3746 struct TransportClient *c;
3747 struct ConnectInfoMessage cim;
3748 struct NeighbourList *n;
3751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3752 "Received `%s' request from client\n", "START");
3757 if (c->client == client)
3759 /* client already on our list! */
3761 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3766 c = GNUNET_malloc (sizeof (struct TransportClient));
3770 if (our_hello != NULL)
3773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3774 "Sending our own `%s' to new client\n", "HELLO");
3776 transmit_to_client (c,
3777 (const struct GNUNET_MessageHeader *) our_hello,
3779 /* tell new client about all existing connections */
3780 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3781 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3785 if (GNUNET_YES == n->received_pong)
3788 cim.latency = GNUNET_TIME_relative_hton (n->latency);
3789 cim.distance = htonl (n->distance);
3790 transmit_to_client (c, &cim.header, GNUNET_NO);
3795 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3800 * Handle HELLO-message.
3802 * @param cls closure (always NULL)
3803 * @param client identification of the client
3804 * @param message the actual message
3807 handle_hello (void *cls,
3808 struct GNUNET_SERVER_Client *client,
3809 const struct GNUNET_MessageHeader *message)
3813 GNUNET_STATISTICS_update (stats,
3814 gettext_noop ("# HELLOs received from clients"),
3817 ret = process_hello (NULL, message);
3818 GNUNET_SERVER_receive_done (client, ret);
3823 * Handle SEND-message.
3825 * @param cls closure (always NULL)
3826 * @param client identification of the client
3827 * @param message the actual message
3830 handle_send (void *cls,
3831 struct GNUNET_SERVER_Client *client,
3832 const struct GNUNET_MessageHeader *message)
3834 struct TransportClient *tc;
3835 struct NeighbourList *n;
3836 const struct OutboundMessage *obm;
3837 const struct GNUNET_MessageHeader *obmm;
3841 size = ntohs (message->size);
3843 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3846 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3849 GNUNET_STATISTICS_update (stats,
3850 gettext_noop ("# payload received for other peers"),
3853 obm = (const struct OutboundMessage *) message;
3855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3856 "Received `%s' request from client with target `%4s'\n",
3857 "SEND", GNUNET_i2s (&obm->peer));
3859 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3860 msize = ntohs (obmm->size);
3861 if (size != msize + sizeof (struct OutboundMessage))
3864 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3867 n = find_neighbour (&obm->peer);
3869 n = setup_new_neighbour (&obm->peer);
3871 while ((tc != NULL) && (tc->client != client))
3875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3876 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3878 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3880 transmit_to_peer (tc, NULL, ntohl (obm->priority),
3881 GNUNET_TIME_relative_ntoh (obm->timeout),
3883 ntohs (obmm->size), GNUNET_NO, n);
3884 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3889 * Handle SET_QUOTA-message.
3891 * @param cls closure (always NULL)
3892 * @param client identification of the client
3893 * @param message the actual message
3896 handle_set_quota (void *cls,
3897 struct GNUNET_SERVER_Client *client,
3898 const struct GNUNET_MessageHeader *message)
3900 const struct QuotaSetMessage *qsm =
3901 (const struct QuotaSetMessage *) message;
3902 struct NeighbourList *n;
3904 GNUNET_STATISTICS_update (stats,
3905 gettext_noop ("# SET QUOTA messages received"),
3908 n = find_neighbour (&qsm->peer);
3911 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3912 GNUNET_STATISTICS_update (stats,
3913 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3920 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3922 (unsigned int) ntohl (qsm->quota.value__),
3923 (unsigned int) n->in_tracker.available_bytes_per_s__,
3924 GNUNET_i2s (&qsm->peer));
3926 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3928 if (0 == ntohl (qsm->quota.value__))
3929 disconnect_neighbour (n, GNUNET_NO);
3930 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3935 * Take the given address and append it to the set of results send back to
3938 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3939 * @param address the resolved name, NULL to indicate the last response
3942 transmit_address_to_client (void *cls, const char *address)
3944 struct GNUNET_SERVER_TransmitContext *tc = cls;
3947 if (NULL == address)
3950 slen = strlen (address) + 1;
3951 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3952 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3953 if (NULL == address)
3954 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3959 * Handle AddressLookup-message.
3961 * @param cls closure (always NULL)
3962 * @param client identification of the client
3963 * @param message the actual message
3966 handle_address_lookup (void *cls,
3967 struct GNUNET_SERVER_Client *client,
3968 const struct GNUNET_MessageHeader *message)
3970 const struct AddressLookupMessage *alum;
3971 struct TransportPlugin *lsPlugin;
3972 const char *nameTransport;
3973 const char *address;
3975 struct GNUNET_SERVER_TransmitContext *tc;
3976 struct GNUNET_TIME_Absolute timeout;
3977 struct GNUNET_TIME_Relative rtimeout;
3980 size = ntohs (message->size);
3981 if (size < sizeof (struct AddressLookupMessage))
3983 GNUNET_break_op (0);
3984 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3987 alum = (const struct AddressLookupMessage *) message;
3988 uint32_t addressLen = ntohl (alum->addrlen);
3989 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3991 GNUNET_break_op (0);
3992 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3995 address = (const char *) &alum[1];
3996 nameTransport = (const char *) &address[addressLen];
3998 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
4000 GNUNET_break_op (0);
4001 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4004 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4005 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4006 numeric = ntohl (alum->numeric_only);
4007 lsPlugin = find_transport (nameTransport);
4008 if (NULL == lsPlugin)
4010 tc = GNUNET_SERVER_transmit_context_create (client);
4011 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4012 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4013 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4016 tc = GNUNET_SERVER_transmit_context_create (client);
4017 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4019 address, addressLen,
4022 &transmit_address_to_client, tc);
4026 * List of handlers for the messages understood by this
4029 static struct GNUNET_SERVER_MessageHandler handlers[] = {
4030 {&handle_start, NULL,
4031 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4032 {&handle_hello, NULL,
4033 GNUNET_MESSAGE_TYPE_HELLO, 0},
4034 {&handle_send, NULL,
4035 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4036 {&handle_set_quota, NULL,
4037 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4038 {&handle_address_lookup, NULL,
4039 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4046 * Setup the environment for this plugin.
4049 create_environment (struct TransportPlugin *plug)
4051 plug->env.cfg = cfg;
4052 plug->env.sched = sched;
4053 plug->env.my_identity = &my_identity;
4054 plug->env.cls = plug;
4055 plug->env.receive = &plugin_env_receive;
4056 plug->env.notify_address = &plugin_env_notify_address;
4057 plug->env.session_end = &plugin_env_session_end;
4058 plug->env.max_connections = max_connect_per_transport;
4059 plug->env.stats = stats;
4064 * Start the specified transport (load the plugin).
4067 start_transport (struct GNUNET_SERVER_Handle *server,
4070 struct TransportPlugin *plug;
4073 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4074 _("Loading `%s' transport plugin\n"), name);
4075 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4076 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4077 create_environment (plug);
4078 plug->short_name = GNUNET_strdup (name);
4079 plug->lib_name = libname;
4080 plug->next = plugins;
4082 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4083 if (plug->api == NULL)
4085 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4086 _("Failed to load transport plugin for `%s'\n"), name);
4087 GNUNET_free (plug->short_name);
4088 plugins = plug->next;
4089 GNUNET_free (libname);
4096 * Called whenever a client is disconnected. Frees our
4097 * resources associated with that client.
4099 * @param cls closure
4100 * @param client identification of the client
4103 client_disconnect_notification (void *cls,
4104 struct GNUNET_SERVER_Client *client)
4106 struct TransportClient *pos;
4107 struct TransportClient *prev;
4108 struct ClientMessageQueueEntry *mqe;
4113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4114 "Client disconnected, cleaning up.\n");
4118 while ((pos != NULL) && (pos->client != client))
4125 while (NULL != (mqe = pos->message_queue_head))
4127 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4128 pos->message_queue_tail,
4130 pos->message_count--;
4134 clients = pos->next;
4136 prev->next = pos->next;
4137 if (GNUNET_YES == pos->tcs_pending)
4142 if (pos->th != NULL)
4144 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4147 GNUNET_break (0 == pos->message_count);
4153 * Iterator to free entries in the validation_map.
4155 * @param cls closure (unused)
4156 * @param key current key code
4157 * @param value value in the hash map (validation to abort)
4158 * @return GNUNET_YES (always)
4161 abort_validation (void *cls,
4162 const GNUNET_HashCode * key,
4165 struct ValidationEntry *va = value;
4167 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
4168 GNUNET_free (va->transport_name);
4175 * Function called when the service shuts down. Unloads our plugins
4176 * and cancels pending validations.
4178 * @param cls closure, unused
4179 * @param tc task context (unused)
4182 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4184 struct TransportPlugin *plug;
4185 struct OwnAddressList *al;
4186 struct CheckHelloValidatedContext *chvc;
4188 while (neighbours != NULL)
4189 disconnect_neighbour (neighbours, GNUNET_NO);
4191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4192 "Transport service is unloading plugins...\n");
4194 while (NULL != (plug = plugins))
4196 plugins = plug->next;
4197 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4199 GNUNET_SCHEDULER_cancel (plug->env.sched,
4200 plug->address_update_task);
4201 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4203 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4204 GNUNET_free (plug->lib_name);
4205 GNUNET_free (plug->short_name);
4206 while (NULL != (al = plug->addresses))
4208 plug->addresses = al->next;
4213 if (my_private_key != NULL)
4214 GNUNET_CRYPTO_rsa_key_free (my_private_key);
4215 GNUNET_free_non_null (our_hello);
4217 /* free 'chvc' data structure */
4218 while (NULL != (chvc = chvc_head))
4220 chvc_head = chvc->next;
4221 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
4226 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4229 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4230 validation_map = NULL;
4233 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4240 * Initiate transport service.
4242 * @param cls closure
4243 * @param s scheduler to use
4244 * @param serv the initialized server
4245 * @param c configuration to use
4249 struct GNUNET_SCHEDULER_Handle *s,
4250 struct GNUNET_SERVER_Handle *serv,
4251 const struct GNUNET_CONFIGURATION_Handle *c)
4256 unsigned long long tneigh;
4261 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4262 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4263 /* parse configuration */
4265 GNUNET_CONFIGURATION_get_value_number (c,
4270 GNUNET_CONFIGURATION_get_value_filename (c,
4272 "HOSTKEY", &keyfile)))
4274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4276 ("Transport service is lacking key configuration settings. Exiting.\n"));
4277 GNUNET_SCHEDULER_shutdown (s);
4280 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4283 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4284 validation_map = NULL;
4287 max_connect_per_transport = (uint32_t) tneigh;
4288 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4289 GNUNET_free (keyfile);
4290 if (my_private_key == NULL)
4292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4294 ("Transport service could not access hostkey. Exiting.\n"));
4295 GNUNET_SCHEDULER_shutdown (s);
4298 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4301 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4302 validation_map = NULL;
4305 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4306 GNUNET_CRYPTO_hash (&my_public_key,
4307 sizeof (my_public_key), &my_identity.hashPubKey);
4308 /* setup notification */
4310 GNUNET_SERVER_disconnect_notify (server,
4311 &client_disconnect_notification, NULL);
4312 /* load plugins... */
4315 GNUNET_CONFIGURATION_get_value_string (c,
4316 "TRANSPORT", "PLUGINS", &plugs))
4318 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4319 _("Starting transport plugins `%s'\n"), plugs);
4320 pos = strtok (plugs, " ");
4323 start_transport (server, pos);
4325 pos = strtok (NULL, " ");
4327 GNUNET_free (plugs);
4329 GNUNET_SCHEDULER_add_delayed (sched,
4330 GNUNET_TIME_UNIT_FOREVER_REL,
4331 &shutdown_task, NULL);
4336 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4338 /* If we have a blacklist file, read from it */
4339 read_blacklist_file(cfg);
4340 /* process client requests */
4341 GNUNET_SERVER_add_handlers (server, handlers);
4346 * The main function for the transport service.
4348 * @param argc number of arguments from the command line
4349 * @param argv command line arguments
4350 * @return 0 ok, 1 on error
4353 main (int argc, char *const *argv)
4355 return (GNUNET_OK ==
4356 GNUNET_SERVICE_run (argc,
4359 GNUNET_SERVICE_OPTION_NONE,
4360 &run, NULL)) ? 0 : 1;
4363 /* end of gnunet-service-transport.c */