2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 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
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "plugin_transport.h"
40 #include "transport.h"
42 #define DEBUG_BLACKLIST GNUNET_NO
44 #define DEBUG_PING_PONG GNUNET_NO
46 #define SIGN_USELESS GNUNET_NO
49 * Should we do some additional checks (to validate behavior
52 #define EXTRA_CHECKS GNUNET_YES
55 * How many messages can we have pending for a given client process
56 * before we start to drop incoming messages? We typically should
57 * have only one client and so this would be the primary buffer for
58 * messages, so the number should be chosen rather generously.
60 * The expectation here is that most of the time the queue is large
61 * enough so that a drop is virtually never required.
63 #define MAX_PENDING 128
66 * Size of the per-transport blacklist hash maps.
68 #define TRANSPORT_BLACKLIST_HT_SIZE 16
71 * How often should we try to reconnect to a peer using a particular
72 * transport plugin before giving up? Note that the plugin may be
73 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
75 #define MAX_CONNECT_RETRY 3
78 * Limit on the number of ready-to-run tasks when validating
79 * HELLOs. If more tasks are ready to run, we will drop
80 * HELLOs instead of validating them.
82 #define MAX_HELLO_LOAD 4
85 * How often must a peer violate bandwidth quotas before we start
86 * to simply drop its messages?
88 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
91 * How long until a HELLO verification attempt should time out?
92 * Must be rather small, otherwise a partially successful HELLO
93 * validation (some addresses working) might not be available
94 * before a client's request for a connection fails for good.
95 * Besides, if a single request to an address takes a long time,
96 * then the peer is unlikely worthwhile anyway.
98 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
101 * Priority to use for PONG messages.
103 #define TRANSPORT_PONG_PRIORITY 4
106 * How often do we re-add (cheaper) plugins to our list of plugins
107 * to try for a given connected peer?
109 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
112 * After how long do we expire an address in a HELLO that we just
113 * validated? This value is also used for our own addresses when we
116 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
120 * How long before an existing address expires should we again try to
121 * validate it? Must be (significantly) smaller than
122 * HELLO_ADDRESS_EXPIRATION.
124 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
127 * Maximum frequency for re-evaluating latencies for all transport addresses.
129 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
132 * Maximum frequency for re-evaluating latencies for connected addresses.
134 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
138 * List of addresses of other peers
140 struct ForeignAddressList
143 * This is a linked list.
145 struct ForeignAddressList *next;
148 * Which ready list does this entry belong to.
150 struct ReadyList *ready_list;
153 * How long until we auto-expire this address (unless it is
154 * re-confirmed by the transport)?
156 struct GNUNET_TIME_Absolute expires;
159 * Task used to re-validate addresses, updates latencies and
162 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
170 * Session (or NULL if no valid session currently exists or if the
171 * plugin does not use sessions).
173 struct Session *session;
176 * What was the last latency observed for this address, plugin and peer?
178 struct GNUNET_TIME_Relative latency;
181 * If we did not successfully transmit a message to the given peer
182 * via this connection during the specified time, we should consider
183 * the connection to be dead. This is used in the case that a TCP
184 * transport simply stalls writing to the stream but does not
185 * formerly get a signal that the other peer died.
187 struct GNUNET_TIME_Absolute timeout;
190 * How often have we tried to connect using this plugin? Used to
191 * discriminate against addresses that do not work well.
192 * FIXME: not yet used, but should be!
194 unsigned int connect_attempts;
197 * DV distance to this peer (1 if no DV is used).
198 * FIXME: need to set this from transport plugins!
208 * Have we ever estimated the latency of this address? Used to
209 * ensure that the first time we add an address, we immediately
215 * Are we currently connected via this address? The first time we
216 * successfully transmit or receive data to a peer via a particular
217 * address, we set this to GNUNET_YES. If we later get an error
218 * (disconnect notification, transmission failure, timeout), we set
219 * it back to GNUNET_NO.
224 * Is this plugin currently busy transmitting to the specific target?
225 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
226 * messages do not count as 'in transmit'.
231 * Has this address been validated yet?
239 * Entry in linked list of network addresses for ourselves.
241 struct OwnAddressList
244 * This is a linked list.
246 struct OwnAddressList *next;
249 * The address, actually a pointer to the end
250 * of this struct. Do not free!
255 * How long until we auto-expire this address (unless it is
256 * re-confirmed by the transport)?
258 struct GNUNET_TIME_Absolute expires;
269 * Entry in linked list of all of our plugins.
271 struct TransportPlugin
275 * This is a linked list.
277 struct TransportPlugin *next;
280 * API of the transport as returned by the plugin's
281 * initialization function.
283 struct GNUNET_TRANSPORT_PluginFunctions *api;
286 * Short name for the plugin (i.e. "tcp").
291 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
296 * List of our known addresses for this transport.
298 struct OwnAddressList *addresses;
301 * Environment this transport service is using
304 struct GNUNET_TRANSPORT_PluginEnvironment env;
307 * ID of task that is used to clean up expired addresses.
309 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
312 * Set to GNUNET_YES if we need to scrap the existing list of
313 * "addresses" and start fresh when we receive the next address
314 * update from a transport. Set to GNUNET_NO if we should just add
315 * the new address to the list and wait for the commit call.
320 * Hashmap of blacklisted peers for this particular transport.
322 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
325 struct NeighbourList;
328 * For each neighbour we keep a list of messages
329 * that we still want to transmit to the neighbour.
335 * This is a doubly linked list.
337 struct MessageQueue *next;
340 * This is a doubly linked list.
342 struct MessageQueue *prev;
345 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
346 * stuck together in memory. Allocated at the end of this struct.
348 const char *message_buf;
351 * Size of the message buf
353 size_t message_buf_size;
356 * Client responsible for queueing the message;
357 * used to check that a client has no two messages
358 * pending for the same target. Can be NULL.
360 struct TransportClient *client;
363 * Using which specific address should we send this message?
365 struct ForeignAddressList *specific_address;
368 * Peer ID of the Neighbour this entry belongs to.
370 struct GNUNET_PeerIdentity neighbour_id;
373 * Plugin that we used for the transmission.
374 * NULL until we scheduled a transmission.
376 struct TransportPlugin *plugin;
379 * At what time should we fail?
381 struct GNUNET_TIME_Absolute timeout;
384 * Internal message of the transport system that should not be
385 * included in the usual SEND-SEND_OK transmission confirmation
386 * traffic management scheme. Typically, "internal_msg" will
387 * be set whenever "client" is NULL (but it is not strictly
393 * How important is the message?
395 unsigned int priority;
401 * For a given Neighbour, which plugins are available
402 * to talk to this peer and what are their costs?
407 * This is a linked list.
409 struct ReadyList *next;
412 * Which of our transport plugins does this entry
415 struct TransportPlugin *plugin;
418 * Transport addresses, latency, and readiness for
419 * this particular plugin.
421 struct ForeignAddressList *addresses;
424 * To which neighbour does this ready list belong to?
426 struct NeighbourList *neighbour;
432 * Entry in linked list of all of our current neighbours.
438 * This is a linked list.
440 struct NeighbourList *next;
443 * Which of our transports is connected to this peer
444 * and what is their status?
446 struct ReadyList *plugins;
449 * Head of list of messages we would like to send to this peer;
450 * must contain at most one message per client.
452 struct MessageQueue *messages_head;
455 * Tail of list of messages we would like to send to this peer; must
456 * contain at most one message per client.
458 struct MessageQueue *messages_tail;
461 * Buffer for at most one payload message used when we receive
462 * payload data before our PING-PONG has succeeded. We then
463 * store such messages in this intermediary buffer until the
464 * connection is fully up.
466 struct GNUNET_MessageHeader *pre_connect_message_buffer;
469 * Context for peerinfo iteration.
470 * NULL after we are done processing peerinfo's information.
472 struct GNUNET_PEERINFO_IteratorContext *piter;
475 * Public key for this peer. Valid only if the respective flag is set below.
477 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
480 * Identity of this neighbour.
482 struct GNUNET_PeerIdentity id;
485 * ID of task scheduled to run when this peer is about to
486 * time out (will free resources associated with the peer).
488 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
491 * ID of task scheduled to run when we should retry transmitting
492 * the head of the message queue. Actually triggered when the
493 * transmission is timing out (we trigger instantly when we have
494 * a chance of success).
496 GNUNET_SCHEDULER_TaskIdentifier retry_task;
499 * How long until we should consider this peer dead
500 * (if we don't receive another message in the
503 struct GNUNET_TIME_Absolute peer_timeout;
506 * Tracker for inbound bandwidth.
508 struct GNUNET_BANDWIDTH_Tracker in_tracker;
511 * The latency we have seen for this particular address for
512 * this particular peer. This latency may have been calculated
513 * over multiple transports. This value reflects how long it took
514 * us to receive a response when SENDING via this particular
515 * transport/neighbour/address combination!
517 * FIXME: we need to periodically send PINGs to update this
518 * latency (at least more often than the current "huge" (11h?)
521 struct GNUNET_TIME_Relative latency;
524 * How often has the other peer (recently) violated the
525 * inbound traffic limit? Incremented by 10 per violation,
526 * decremented by 1 per non-violation (for each
529 unsigned int quota_violation_count;
532 * DV distance to this peer (1 if no DV is used).
537 * Have we seen an PONG from this neighbour in the past (and
538 * not had a disconnect since)?
543 * Do we have a valid public key for this neighbour?
545 int public_key_valid;
550 * Message used to ask a peer to validate receipt (to check an address
553 struct TransportPingMessage
557 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
559 struct GNUNET_MessageHeader header;
562 * Random challenge number (in network byte order).
564 uint32_t challenge GNUNET_PACKED;
567 * Who is the intended recipient?
569 struct GNUNET_PeerIdentity target;
575 * Message used to validate a HELLO. The challenge is included in the
576 * confirmation to make matching of replies to requests possible. The
577 * signature signs the original challenge number, our public key, the
578 * sender's address (so that the sender can check that the address we
579 * saw is plausible for him and possibly detect a MiM attack) and a
580 * timestamp (to limit replay).<p>
582 * This message is followed by the address of the
583 * client that we are observing (which is part of what
586 struct TransportPongMessage
590 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
592 struct GNUNET_MessageHeader header;
595 * For padding, always zero.
597 uint32_t reserved GNUNET_PACKED;
602 struct GNUNET_CRYPTO_RsaSignature signature;
605 * What are we signing and why?
607 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
610 * Random challenge number (in network byte order).
612 uint32_t challenge GNUNET_PACKED;
615 * Who signed this message?
617 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
620 * Size of address appended to this message
628 * Linked list of messages to be transmitted to the client. Each
629 * entry is followed by the actual message.
631 struct ClientMessageQueueEntry
634 * This is a doubly-linked list.
636 struct ClientMessageQueueEntry *next;
639 * This is a doubly-linked list.
641 struct ClientMessageQueueEntry *prev;
646 * Client connected to the transport service.
648 struct TransportClient
652 * This is a linked list.
654 struct TransportClient *next;
657 * Handle to the client.
659 struct GNUNET_SERVER_Client *client;
662 * Linked list of messages yet to be transmitted to
665 struct ClientMessageQueueEntry *message_queue_head;
668 * Tail of linked list of messages yet to be transmitted to the
671 struct ClientMessageQueueEntry *message_queue_tail;
674 * Current transmit request handle.
676 struct GNUNET_CONNECTION_TransmitHandle *th;
679 * Is a call to "transmit_send_continuation" pending? If so, we
680 * must not free this struct (even if the corresponding client
681 * disconnects) and instead only remove it from the linked list and
682 * set the "client" field to NULL.
687 * Length of the list of messages pending for this client.
689 unsigned int message_count;
695 * Entry in map of all HELLOs awaiting validation.
697 struct ValidationEntry
701 * The address, actually a pointer to the end
702 * of this struct. Do not free!
707 * Name of the transport.
709 char *transport_name;
712 * The public key of the peer.
714 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
717 * ID of task that will clean up this entry if we don't succeed
718 * with the validation first.
720 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
723 * At what time did we send this validation?
725 struct GNUNET_TIME_Absolute send_time;
728 * Session being validated (or NULL for none).
730 struct Session *session;
733 * Challenge number we used.
746 * Context of currently active requests to peerinfo
747 * for validation of HELLOs.
749 struct CheckHelloValidatedContext
753 * This is a doubly-linked list.
755 struct CheckHelloValidatedContext *next;
758 * This is a doubly-linked list.
760 struct CheckHelloValidatedContext *prev;
763 * Hello that we are validating.
765 const struct GNUNET_HELLO_Message *hello;
768 * Context for peerinfo iteration.
769 * NULL after we are done processing peerinfo's information.
771 struct GNUNET_PEERINFO_IteratorContext *piter;
774 * Was a HELLO known for this peer to peerinfo?
785 static struct GNUNET_HELLO_Message *our_hello;
788 * "version" of "our_hello". Used to see if a given neighbour has
789 * already been sent the latest version of our HELLO message.
791 static unsigned int our_hello_version;
796 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
801 static struct GNUNET_PeerIdentity my_identity;
806 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
811 struct GNUNET_SCHEDULER_Handle *sched;
816 const struct GNUNET_CONFIGURATION_Handle *cfg;
819 * Linked list of all clients to this service.
821 static struct TransportClient *clients;
824 * All loaded plugins.
826 static struct TransportPlugin *plugins;
831 static struct GNUNET_SERVER_Handle *server;
834 * Handle to peerinfo service.
836 static struct GNUNET_PEERINFO_Handle *peerinfo;
839 * All known neighbours and their HELLOs.
841 static struct NeighbourList *neighbours;
844 * Number of neighbours we'd like to have.
846 static uint32_t max_connect_per_transport;
849 * Head of linked list.
851 static struct CheckHelloValidatedContext *chvc_head;
854 * Tail of linked list.
856 static struct CheckHelloValidatedContext *chvc_tail;
859 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
860 * of the given peer that we are currently validating).
862 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
865 * Handle for reporting statistics.
867 static struct GNUNET_STATISTICS_Handle *stats;
871 * The peer specified by the given neighbour has timed-out or a plugin
872 * has disconnected. We may either need to do nothing (other plugins
873 * still up), or trigger a full disconnect and clean up. This
874 * function updates our state and do the necessary notifications.
875 * Also notifies our clients that the neighbour is now officially
878 * @param n the neighbour list entry for the peer
879 * @param check should we just check if all plugins
880 * disconnected or must we ask all plugins to
883 static void disconnect_neighbour (struct NeighbourList *n, int check);
886 * Check the ready list for the given neighbour and if a plugin is
887 * ready for transmission (and if we have a message), do so!
889 * @param neighbour target peer for which to transmit
891 static void try_transmission_to_peer (struct NeighbourList *neighbour);
895 * Find an entry in the neighbour list for a particular peer.
897 * @return NULL if not found.
899 static struct NeighbourList *
900 find_neighbour (const struct GNUNET_PeerIdentity *key)
902 struct NeighbourList *head = neighbours;
904 while ((head != NULL) &&
905 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
912 * Find an entry in the transport list for a particular transport.
914 * @return NULL if not found.
916 static struct TransportPlugin *
917 find_transport (const char *short_name)
919 struct TransportPlugin *head = plugins;
920 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
926 * Is a particular peer blacklisted for a particular transport?
928 * @param peer the peer to check for
929 * @param plugin the plugin used to connect to the peer
931 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
934 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
937 if (plugin->blacklist != NULL)
939 if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
943 _("Peer `%s:%s' is blacklisted!\n"),
944 plugin->short_name, GNUNET_i2s (peer));
955 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
957 struct TransportPlugin *plugin;
959 plugin = find_transport(transport_name);
960 if (plugin == NULL) /* Nothing to do */
962 if (plugin->blacklist == NULL)
963 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
964 GNUNET_assert(plugin->blacklist != NULL);
965 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
967 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
972 * Read the blacklist file, containing transport:peer entries.
973 * Provided the transport is loaded, set up hashmap with these
974 * entries to blacklist peers by transport.
978 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
985 struct GNUNET_PeerIdentity pid;
987 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
988 unsigned int entries_found;
989 char *transport_name;
992 GNUNET_CONFIGURATION_get_value_filename (cfg,
998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999 _("Option `%s' in section `%s' not specified!\n"),
1005 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1006 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1007 | GNUNET_DISK_PERM_USER_WRITE);
1008 if (0 != STAT (fn, &frstat))
1010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1011 _("Could not read blacklist file `%s'\n"), fn);
1015 if (frstat.st_size == 0)
1017 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1018 _("Blacklist file `%s' is empty.\n"),
1023 /* FIXME: use mmap */
1024 data = GNUNET_malloc_large (frstat.st_size);
1025 if (frstat.st_size !=
1026 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1028 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1029 _("Failed to read blacklist from `%s'\n"), fn);
1036 while ((pos < frstat.st_size) && isspace (data[pos]))
1038 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1039 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1042 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace (data[colon_pos]))
1045 if (colon_pos >= frstat.st_size)
1047 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1048 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1049 (unsigned long long) colon_pos);
1055 if (isspace(data[colon_pos]))
1057 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1058 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1059 (unsigned long long) colon_pos);
1061 while ((pos < frstat.st_size) && isspace (data[pos]))
1065 tsize = colon_pos - pos;
1066 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size))
1068 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1069 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1070 (unsigned long long) colon_pos);
1076 transport_name = GNUNET_malloc(tsize);
1077 memcpy(transport_name, &data[pos], tsize);
1078 pos = colon_pos + 1;
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 _("Read transport name %s in blacklist file.\n"),
1085 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1086 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1088 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1089 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1090 (unsigned long long) pos);
1092 while ((pos < frstat.st_size) && (!isspace (data[pos])))
1094 GNUNET_free_non_null(transport_name);
1097 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1098 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1100 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1101 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1102 (unsigned long long) pos,
1107 if (0 != memcmp (&pid,
1109 sizeof (struct GNUNET_PeerIdentity)))
1112 add_peer_to_blacklist (&pid,
1114 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1115 _("Found blacklisted peer `%s:%s' in configuration\n"),
1116 transport_name, GNUNET_i2s (&pid));
1120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1121 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1125 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1126 GNUNET_free_non_null(transport_name);
1127 while ((pos < frstat.st_size) && isspace (data[pos]))
1136 * Function called to notify a client about the socket being ready to
1137 * queue more data. "buf" will be NULL and "size" zero if the socket
1138 * was closed for writing in the meantime.
1140 * @param cls closure
1141 * @param size number of bytes available in buf
1142 * @param buf where the callee should write the message
1143 * @return number of bytes written to buf
1146 transmit_to_client_callback (void *cls, size_t size, void *buf)
1148 struct TransportClient *client = cls;
1149 struct ClientMessageQueueEntry *q;
1152 const struct GNUNET_MessageHeader *msg;
1158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1159 "Transmission to client failed, closing connection.\n");
1160 /* fatal error with client, free message queue! */
1161 while (NULL != (q = client->message_queue_head))
1163 GNUNET_STATISTICS_update (stats,
1164 gettext_noop ("# bytes discarded (could not transmit to client)"),
1165 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1167 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1168 client->message_queue_tail,
1172 client->message_count = 0;
1177 while (NULL != (q = client->message_queue_head))
1179 msg = (const struct GNUNET_MessageHeader *) &q[1];
1180 msize = ntohs (msg->size);
1181 if (msize + tsize > size)
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185 "Transmitting message of type %u to client.\n",
1188 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1189 client->message_queue_tail,
1191 memcpy (&cbuf[tsize], msg, msize);
1194 client->message_count--;
1198 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1199 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1201 GNUNET_TIME_UNIT_FOREVER_REL,
1202 &transmit_to_client_callback,
1204 GNUNET_assert (client->th != NULL);
1211 * Mark the given FAL entry as 'connected' (and hence preferred for
1212 * sending); also mark all others for the same peer as 'not connected'
1213 * (since only one can be preferred).
1215 * @param fal address to set to 'connected'
1218 mark_address_connected (struct ForeignAddressList *fal)
1220 struct ForeignAddressList *pos;
1223 GNUNET_assert (GNUNET_YES == fal->validated);
1224 if (fal->connected == GNUNET_YES)
1225 return; /* nothing to do */
1227 pos = fal->ready_list->addresses;
1230 if (GNUNET_YES == pos->connected)
1232 GNUNET_break (cnt == GNUNET_YES);
1234 pos->connected = GNUNET_NO;
1238 fal->connected = GNUNET_YES;
1239 if (GNUNET_YES == cnt)
1241 GNUNET_STATISTICS_update (stats,
1242 gettext_noop ("# connected addresses"),
1250 * Send the specified message to the specified client. Since multiple
1251 * messages may be pending for the same client at a time, this code
1252 * makes sure that no message is lost.
1254 * @param client client to transmit the message to
1255 * @param msg the message to send
1256 * @param may_drop can this message be dropped if the
1257 * message queue for this client is getting far too large?
1260 transmit_to_client (struct TransportClient *client,
1261 const struct GNUNET_MessageHeader *msg, int may_drop)
1263 struct ClientMessageQueueEntry *q;
1266 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1268 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1270 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1271 client->message_count, MAX_PENDING);
1272 /* TODO: call to statistics... */
1275 msize = ntohs (msg->size);
1276 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1277 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1278 memcpy (&q[1], msg, msize);
1279 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1280 client->message_queue_tail,
1281 client->message_queue_tail,
1283 client->message_count++;
1284 if (client->th == NULL)
1286 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1288 GNUNET_TIME_UNIT_FOREVER_REL,
1289 &transmit_to_client_callback,
1291 GNUNET_assert (client->th != NULL);
1297 * Transmit a 'SEND_OK' notification to the given client for the
1300 * @param client who to notify
1301 * @param n neighbour to notify about
1302 * @param result status code for the transmission request
1305 transmit_send_ok (struct TransportClient *client,
1306 struct NeighbourList *n,
1309 struct SendOkMessage send_ok_msg;
1311 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1312 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1313 send_ok_msg.success = htonl (result);
1314 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1315 send_ok_msg.peer = n->id;
1316 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1321 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1322 * upon "completion" of a send request. This tells the API
1323 * that it is now legal to send another message to the given
1326 * @param cls closure, identifies the entry on the
1327 * message queue that was transmitted and the
1328 * client responsible for queueing the message
1329 * @param target the peer receiving the message
1330 * @param result GNUNET_OK on success, if the transmission
1331 * failed, we should not tell the client to transmit
1335 transmit_send_continuation (void *cls,
1336 const struct GNUNET_PeerIdentity *target,
1339 struct MessageQueue *mq = cls;
1340 struct NeighbourList *n;
1342 GNUNET_STATISTICS_update (stats,
1343 gettext_noop ("# bytes pending with plugins"),
1344 - (int64_t) mq->message_buf_size,
1346 if (result == GNUNET_OK)
1348 GNUNET_STATISTICS_update (stats,
1349 gettext_noop ("# bytes successfully transmitted by plugins"),
1350 mq->message_buf_size,
1355 GNUNET_STATISTICS_update (stats,
1356 gettext_noop ("# bytes with transmission failure by plugins"),
1357 mq->message_buf_size,
1360 n = find_neighbour(&mq->neighbour_id);
1361 GNUNET_assert (n != NULL);
1362 if (mq->specific_address != NULL)
1364 if (result == GNUNET_OK)
1366 mq->specific_address->timeout =
1367 GNUNET_TIME_relative_to_absolute
1368 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1369 if (mq->specific_address->validated == GNUNET_YES)
1370 mark_address_connected (mq->specific_address);
1374 if (mq->specific_address->connected != GNUNET_NO)
1376 GNUNET_STATISTICS_update (stats,
1377 gettext_noop ("# connected addresses"),
1380 mq->specific_address->connected = GNUNET_NO;
1383 if (! mq->internal_msg)
1384 mq->specific_address->in_transmit = GNUNET_NO;
1386 if (mq->client != NULL)
1387 transmit_send_ok (mq->client, n, result);
1389 try_transmission_to_peer (n);
1394 * Convert an address to a string.
1396 * @param plugin name of the plugin responsible for the address
1397 * @param addr binary address
1398 * @param addr_len number of bytes in addr
1399 * @return NULL on error, otherwise address string
1402 a2s (const char *plugin,
1406 struct TransportPlugin *p;
1410 p = find_transport (plugin);
1413 return p->api->address_to_string (p->api->cls,
1420 * Find an address in any of the available transports for
1421 * the given neighbour that would be good for message
1422 * transmission. This is essentially the transport selection
1425 * @param neighbour for whom to select an address
1426 * @return selected address, NULL if we have none
1428 struct ForeignAddressList *
1429 find_ready_address(struct NeighbourList *neighbour)
1431 struct ReadyList *head = neighbour->plugins;
1432 struct ForeignAddressList *addresses;
1433 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1434 struct ForeignAddressList *best_address;
1436 best_address = NULL;
1437 while (head != NULL)
1439 addresses = head->addresses;
1440 while (addresses != NULL)
1442 if ( (addresses->timeout.value < now.value) &&
1443 (addresses->connected == GNUNET_YES) )
1446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447 "Marking long-time inactive connection to `%4s' as down.\n",
1448 GNUNET_i2s (&neighbour->id));
1450 GNUNET_STATISTICS_update (stats,
1451 gettext_noop ("# connected addresses"),
1454 addresses->connected = GNUNET_NO;
1456 addresses = addresses->next;
1459 addresses = head->addresses;
1460 while (addresses != NULL)
1462 #if DEBUG_TRANSPORT > 1
1463 if (addresses->addr != NULL)
1464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1465 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1466 a2s (head->plugin->short_name,
1468 addresses->addrlen),
1469 GNUNET_i2s (&neighbour->id),
1470 addresses->connected,
1471 addresses->in_transmit,
1472 addresses->validated,
1473 addresses->connect_attempts,
1474 (unsigned long long) addresses->timeout.value,
1475 (unsigned int) addresses->distance);
1477 if ( ( (best_address == NULL) ||
1478 (addresses->connected == GNUNET_YES) ||
1479 (best_address->connected == GNUNET_NO) ) &&
1480 (addresses->in_transmit == GNUNET_NO) &&
1481 ( (best_address == NULL) ||
1482 (addresses->latency.value < best_address->latency.value)) )
1483 best_address = addresses;
1484 /* FIXME: also give lower-latency addresses that are not
1485 connected a chance some times... */
1486 addresses = addresses->next;
1490 if (best_address != NULL)
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494 "Best address found has latency of %llu ms.\n",
1495 best_address->latency.value);
1500 GNUNET_STATISTICS_update (stats,
1501 gettext_noop ("# transmission attempts failed (no address)"),
1505 return best_address;
1511 * We should re-try transmitting to the given peer,
1512 * hopefully we've learned something in the meantime.
1515 retry_transmission_task (void *cls,
1516 const struct GNUNET_SCHEDULER_TaskContext *tc)
1518 struct NeighbourList *n = cls;
1520 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1521 try_transmission_to_peer (n);
1526 * Check the ready list for the given neighbour and if a plugin is
1527 * ready for transmission (and if we have a message), do so!
1529 * @param neighbour target peer for which to transmit
1532 try_transmission_to_peer (struct NeighbourList *neighbour)
1534 struct ReadyList *rl;
1535 struct MessageQueue *mq;
1536 struct GNUNET_TIME_Relative timeout;
1540 if (neighbour->messages_head == NULL)
1543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1544 "Transmission queue for `%4s' is empty\n",
1545 GNUNET_i2s (&neighbour->id));
1547 return; /* nothing to do */
1550 mq = neighbour->messages_head;
1551 force_address = GNUNET_YES;
1552 if (mq->specific_address == NULL)
1554 mq->specific_address = find_ready_address(neighbour);
1555 GNUNET_STATISTICS_update (stats,
1556 gettext_noop ("# transport selected peer address freely"),
1559 force_address = GNUNET_NO;
1561 if (mq->specific_address == NULL)
1563 GNUNET_STATISTICS_update (stats,
1564 gettext_noop ("# transport failed to selected peer address"),
1567 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1568 if (timeout.value == 0)
1571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1572 "No destination address available to transmit message of size %u to peer `%4s'\n",
1573 mq->message_buf_size,
1574 GNUNET_i2s (&mq->neighbour_id));
1576 GNUNET_STATISTICS_update (stats,
1577 gettext_noop ("# bytes in message queue for other peers"),
1578 - (int64_t) mq->message_buf_size,
1580 GNUNET_STATISTICS_update (stats,
1581 gettext_noop ("# bytes discarded (no destination address available)"),
1582 mq->message_buf_size,
1584 if (mq->client != NULL)
1585 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1586 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1587 neighbour->messages_tail,
1590 return; /* nobody ready */
1592 GNUNET_STATISTICS_update (stats,
1593 gettext_noop ("# message delivery deferred (no address)"),
1596 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1597 GNUNET_SCHEDULER_cancel (sched,
1598 neighbour->retry_task);
1599 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1601 &retry_transmission_task,
1604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1605 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1606 mq->message_buf_size,
1607 GNUNET_i2s (&mq->neighbour_id),
1610 /* FIXME: might want to trigger peerinfo lookup here
1611 (unless that's already pending...) */
1614 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1615 neighbour->messages_tail,
1617 if (mq->specific_address->connected == GNUNET_NO)
1618 mq->specific_address->connect_attempts++;
1619 rl = mq->specific_address->ready_list;
1620 mq->plugin = rl->plugin;
1621 if (!mq->internal_msg)
1622 mq->specific_address->in_transmit = GNUNET_YES;
1624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1625 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1626 mq->message_buf_size,
1627 GNUNET_i2s (&neighbour->id),
1628 (mq->specific_address->addr != NULL)
1629 ? a2s (mq->plugin->short_name,
1630 mq->specific_address->addr,
1631 mq->specific_address->addrlen)
1633 rl->plugin->short_name);
1635 GNUNET_STATISTICS_update (stats,
1636 gettext_noop ("# bytes in message queue for other peers"),
1637 - (int64_t) mq->message_buf_size,
1639 GNUNET_STATISTICS_update (stats,
1640 gettext_noop ("# bytes pending with plugins"),
1641 mq->message_buf_size,
1643 ret = rl->plugin->api->send (rl->plugin->api->cls,
1646 mq->message_buf_size,
1648 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1649 mq->specific_address->session,
1650 mq->specific_address->addr,
1651 mq->specific_address->addrlen,
1653 &transmit_send_continuation, mq);
1656 /* failure, but 'send' would not call continuation in this case,
1657 so we need to do it here! */
1658 transmit_send_continuation (mq,
1666 * Send the specified message to the specified peer.
1668 * @param client source of the transmission request (can be NULL)
1669 * @param peer_address ForeignAddressList where we should send this message
1670 * @param priority how important is the message
1671 * @param timeout how long do we have to transmit?
1672 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1673 * @param message_buf_size total size of all messages in message_buf
1674 * @param is_internal is this an internal message; these are pre-pended and
1675 * also do not count for plugins being "ready" to transmit
1676 * @param neighbour handle to the neighbour for transmission
1679 transmit_to_peer (struct TransportClient *client,
1680 struct ForeignAddressList *peer_address,
1681 unsigned int priority,
1682 struct GNUNET_TIME_Relative timeout,
1683 const char *message_buf,
1684 size_t message_buf_size,
1685 int is_internal, struct NeighbourList *neighbour)
1687 struct MessageQueue *mq;
1692 /* check for duplicate submission */
1693 mq = neighbour->messages_head;
1696 if (mq->client == client)
1698 /* client transmitted to same peer twice
1699 before getting SEND_OK! */
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# bytes in message queue for other peers"),
1711 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1712 mq->specific_address = peer_address;
1713 mq->client = client;
1714 memcpy (&mq[1], message_buf, message_buf_size);
1715 mq->message_buf = (const char*) &mq[1];
1716 mq->message_buf_size = message_buf_size;
1717 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1718 mq->internal_msg = is_internal;
1719 mq->priority = priority;
1720 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1722 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1723 neighbour->messages_tail,
1726 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1727 neighbour->messages_tail,
1728 neighbour->messages_tail,
1730 try_transmission_to_peer (neighbour);
1737 struct GeneratorContext
1739 struct TransportPlugin *plug_pos;
1740 struct OwnAddressList *addr_pos;
1741 struct GNUNET_TIME_Absolute expiration;
1749 address_generator (void *cls, size_t max, void *buf)
1751 struct GeneratorContext *gc = cls;
1754 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1756 gc->plug_pos = gc->plug_pos->next;
1757 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1759 if (NULL == gc->plug_pos)
1764 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1767 gc->addr_pos->addrlen, buf, max);
1768 gc->addr_pos = gc->addr_pos->next;
1774 * Construct our HELLO message from all of the addresses of
1775 * all of the transports.
1780 struct GNUNET_HELLO_Message *hello;
1781 struct TransportClient *cpos;
1782 struct NeighbourList *npos;
1783 struct GeneratorContext gc;
1785 gc.plug_pos = plugins;
1786 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1787 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1788 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1791 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1793 GNUNET_STATISTICS_update (stats,
1794 gettext_noop ("# refreshed my HELLO"),
1798 while (cpos != NULL)
1800 transmit_to_client (cpos,
1801 (const struct GNUNET_MessageHeader *) hello,
1806 GNUNET_free_non_null (our_hello);
1808 our_hello_version++;
1809 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1811 while (npos != NULL)
1814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1815 "Transmitting updated `%s' to neighbour `%4s'\n",
1816 "HELLO", GNUNET_i2s (&npos->id));
1818 GNUNET_STATISTICS_update (stats,
1819 gettext_noop ("# transmitted my HELLO to other peers"),
1822 transmit_to_peer (NULL, NULL, 0,
1823 HELLO_ADDRESS_EXPIRATION,
1824 (const char *) our_hello,
1825 GNUNET_HELLO_size(our_hello),
1833 * Task used to clean up expired addresses for a plugin.
1835 * @param cls closure
1839 expire_address_task (void *cls,
1840 const struct GNUNET_SCHEDULER_TaskContext *tc);
1844 * Update the list of addresses for this plugin,
1845 * expiring those that are past their expiration date.
1847 * @param plugin addresses of which plugin should be recomputed?
1848 * @param fresh set to GNUNET_YES if a new address was added
1849 * and we need to regenerate the HELLO even if nobody
1853 update_addresses (struct TransportPlugin *plugin, int fresh)
1855 static struct GNUNET_TIME_Absolute last_update;
1856 struct GNUNET_TIME_Relative min_remaining;
1857 struct GNUNET_TIME_Relative remaining;
1858 struct GNUNET_TIME_Absolute now;
1859 struct OwnAddressList *pos;
1860 struct OwnAddressList *prev;
1861 struct OwnAddressList *next;
1864 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1865 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1866 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1867 now = GNUNET_TIME_absolute_get ();
1868 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1869 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1871 pos = plugin->addresses;
1875 if (pos->expires.value < now.value)
1877 expired = GNUNET_YES;
1879 plugin->addresses = pos->next;
1881 prev->next = pos->next;
1886 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1887 if (remaining.value < min_remaining.value)
1888 min_remaining = remaining;
1894 if (expired || fresh)
1899 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1900 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1902 plugin->address_update_task
1903 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1905 &expire_address_task, plugin);
1910 * Task used to clean up expired addresses for a plugin.
1912 * @param cls closure
1916 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1918 struct TransportPlugin *plugin = cls;
1920 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1921 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1922 update_addresses (plugin, GNUNET_NO);
1927 * Iterator over hash map entries that NULLs the session of validation
1928 * entries that match the given session.
1930 * @param cls closure (the 'struct Session*' to match against)
1931 * @param key current key code (peer ID, not used)
1932 * @param value value in the hash map ('struct ValidationEntry*')
1933 * @return GNUNET_YES (we should continue to iterate)
1936 remove_session_validations (void *cls,
1937 const GNUNET_HashCode * key,
1940 struct Session *session = cls;
1941 struct ValidationEntry *ve = value;
1943 if (session == ve->session)
1950 * Function that will be called whenever the plugin internally
1951 * cleans up a session pointer and hence the service needs to
1952 * discard all of those sessions as well. Plugins that do not
1953 * use sessions can simply omit calling this function and always
1954 * use NULL wherever a session pointer is needed.
1956 * @param cls closure
1957 * @param peer which peer was the session for
1958 * @param session which session is being destoyed
1961 plugin_env_session_end (void *cls,
1962 const struct GNUNET_PeerIdentity *peer,
1963 struct Session *session)
1965 struct TransportPlugin *p = cls;
1966 struct NeighbourList *nl;
1967 struct ReadyList *rl;
1968 struct ForeignAddressList *pos;
1969 struct ForeignAddressList *prev;
1971 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1972 &remove_session_validations,
1974 nl = find_neighbour (peer);
1980 if (rl->plugin == p)
1987 pos = rl->addresses;
1988 while ( (pos != NULL) &&
1989 (pos->session != session) )
1996 pos->session = NULL;
1997 if (pos->addrlen != 0)
2000 rl->addresses = pos->next;
2002 prev->next = pos->next;
2003 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2005 GNUNET_SCHEDULER_cancel (sched,
2006 pos->revalidate_task);
2007 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2010 if (nl->received_pong == GNUNET_NO)
2011 return; /* nothing to do */
2012 /* check if we have any validated addresses left */
2013 pos = rl->addresses;
2020 /* no valid addresses left, signal disconnect! */
2021 disconnect_neighbour (nl, GNUNET_NO);
2026 * Function that must be called by each plugin to notify the
2027 * transport service about the addresses under which the transport
2028 * provided by the plugin can be reached.
2030 * @param cls closure
2031 * @param name name of the transport that generated the address
2032 * @param addr one of the addresses of the host, NULL for the last address
2033 * the specific address format depends on the transport
2034 * @param addrlen length of the address
2035 * @param expires when should this address automatically expire?
2038 plugin_env_notify_address (void *cls,
2042 struct GNUNET_TIME_Relative expires)
2044 struct TransportPlugin *p = cls;
2045 struct OwnAddressList *al;
2046 struct GNUNET_TIME_Absolute abex;
2048 GNUNET_assert (addr != NULL);
2049 abex = GNUNET_TIME_relative_to_absolute (expires);
2050 GNUNET_assert (p == find_transport (name));
2054 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2056 if (al->expires.value < abex.value)
2063 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2065 al->next = p->addresses;
2068 al->addrlen = addrlen;
2069 memcpy (&al[1], addr, addrlen);
2070 update_addresses (p, GNUNET_YES);
2075 * Notify all of our clients about a peer connecting.
2078 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2079 struct GNUNET_TIME_Relative latency,
2082 struct ConnectInfoMessage cim;
2083 struct TransportClient *cpos;
2086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2087 "Notifying clients about connection from `%s'\n",
2090 GNUNET_STATISTICS_update (stats,
2091 gettext_noop ("# peers connected"),
2094 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2095 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2096 cim.distance = htonl (distance);
2097 cim.latency = GNUNET_TIME_relative_hton (latency);
2098 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
2100 while (cpos != NULL)
2102 transmit_to_client (cpos, &cim.header, GNUNET_NO);
2109 * Notify all of our clients about a peer disconnecting.
2112 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2114 struct DisconnectInfoMessage dim;
2115 struct TransportClient *cpos;
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2119 "Notifying clients about lost connection to `%s'\n",
2122 GNUNET_STATISTICS_update (stats,
2123 gettext_noop ("# peers connected"),
2126 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2127 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2128 dim.reserved = htonl (0);
2129 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2131 while (cpos != NULL)
2133 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2140 * Find a ForeignAddressList entry for the given neighbour
2141 * that matches the given address and transport.
2143 * @param neighbour which peer we care about
2144 * @param tname name of the transport plugin
2145 * @param session session to look for, NULL for 'any'; otherwise
2146 * can be used for the service to "learn" this session ID
2148 * @param addr binary address
2149 * @param addrlen length of addr
2150 * @return NULL if no such entry exists
2152 static struct ForeignAddressList *
2153 find_peer_address(struct NeighbourList *neighbour,
2155 struct Session *session,
2159 struct ReadyList *head;
2160 struct ForeignAddressList *pos;
2162 head = neighbour->plugins;
2163 while (head != NULL)
2165 if (0 == strcmp (tname, head->plugin->short_name))
2171 pos = head->addresses;
2172 while ( (pos != NULL) &&
2173 ( (pos->addrlen != addrlen) ||
2174 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2176 if ( (session != NULL) &&
2177 (pos->session == session) )
2181 if ( (session != NULL) && (pos != NULL) )
2182 pos->session = session; /* learn it! */
2188 * Get the peer address struct for the given neighbour and
2189 * address. If it doesn't yet exist, create it.
2191 * @param neighbour which peer we care about
2192 * @param tname name of the transport plugin
2193 * @param session session of the plugin, or NULL for none
2194 * @param addr binary address
2195 * @param addrlen length of addr
2196 * @return NULL if we do not have a transport plugin for 'tname'
2198 static struct ForeignAddressList *
2199 add_peer_address (struct NeighbourList *neighbour,
2201 struct Session *session,
2205 struct ReadyList *head;
2206 struct ForeignAddressList *ret;
2208 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2211 head = neighbour->plugins;
2213 while (head != NULL)
2215 if (0 == strcmp (tname, head->plugin->short_name))
2221 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2222 ret->session = session;
2225 ret->addr = (const char*) &ret[1];
2226 memcpy (&ret[1], addr, addrlen);
2232 ret->addrlen = addrlen;
2233 ret->expires = GNUNET_TIME_relative_to_absolute
2234 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2235 ret->latency = GNUNET_TIME_relative_get_forever();
2237 ret->timeout = GNUNET_TIME_relative_to_absolute
2238 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2239 ret->ready_list = head;
2240 ret->next = head->addresses;
2241 head->addresses = ret;
2247 * Closure for 'add_validated_address'.
2249 struct AddValidatedAddressContext
2252 * Entry that has been validated.
2254 const struct ValidationEntry *ve;
2257 * Flag set after we have added the address so
2258 * that we terminate the iteration next time.
2265 * Callback function used to fill a buffer of max bytes with a list of
2266 * addresses in the format used by HELLOs. Should use
2267 * "GNUNET_HELLO_add_address" as a helper function.
2269 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2270 * @param max maximum number of bytes that can be written to buf
2271 * @param buf where to write the address information
2272 * @return number of bytes written, 0 to signal the
2273 * end of the iteration.
2276 add_validated_address (void *cls,
2277 size_t max, void *buf)
2279 struct AddValidatedAddressContext *avac = cls;
2280 const struct ValidationEntry *ve = avac->ve;
2282 if (GNUNET_YES == avac->done)
2284 avac->done = GNUNET_YES;
2285 return GNUNET_HELLO_add_address (ve->transport_name,
2286 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2296 * Closure for 'check_address_exists'.
2298 struct CheckAddressExistsClosure
2301 * Address to check for.
2306 * Name of the transport.
2313 struct Session *session;
2316 * Set to GNUNET_YES if the address exists.
2329 * Iterator over hash map entries. Checks if the given
2330 * validation entry is for the same address as what is given
2333 * @param cls the 'struct CheckAddressExistsClosure*'
2334 * @param key current key code (ignored)
2335 * @param value value in the hash map ('struct ValidationEntry')
2336 * @return GNUNET_YES if we should continue to
2337 * iterate (mismatch), GNUNET_NO if not (entry matched)
2340 check_address_exists (void *cls,
2341 const GNUNET_HashCode * key,
2344 struct CheckAddressExistsClosure *caec = cls;
2345 struct ValidationEntry *ve = value;
2347 if ( (0 == strcmp (caec->tname,
2348 ve->transport_name)) &&
2349 (caec->addrlen == ve->addrlen) &&
2350 (0 == memcmp (caec->addr,
2354 caec->exists = GNUNET_YES;
2357 if ( (ve->session != NULL) &&
2358 (caec->session == ve->session) )
2360 caec->exists = GNUNET_YES;
2368 * HELLO validation cleanup task (validation failed).
2370 * @param cls the 'struct ValidationEntry' that failed
2371 * @param tc scheduler context (unused)
2374 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2376 struct ValidationEntry *va = cls;
2377 struct GNUNET_PeerIdentity pid;
2379 GNUNET_STATISTICS_update (stats,
2380 gettext_noop ("# address validation timeouts"),
2383 GNUNET_CRYPTO_hash (&va->publicKey,
2385 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2387 GNUNET_break (GNUNET_OK ==
2388 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2391 GNUNET_free (va->transport_name);
2397 neighbour_timeout_task (void *cls,
2398 const struct GNUNET_SCHEDULER_TaskContext *tc)
2400 struct NeighbourList *n = cls;
2403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2404 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2406 GNUNET_STATISTICS_update (stats,
2407 gettext_noop ("# disconnects due to timeout"),
2410 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2411 disconnect_neighbour (n, GNUNET_NO);
2416 * Schedule the job that will cause us to send a PING to the
2417 * foreign address to evaluate its validity and latency.
2419 * @param fal address to PING
2422 schedule_next_ping (struct ForeignAddressList *fal);
2426 * Add the given address to the list of foreign addresses
2427 * available for the given peer (check for duplicates).
2429 * @param cls the respective 'struct NeighbourList' to update
2430 * @param tname name of the transport
2431 * @param expiration expiration time
2432 * @param addr the address
2433 * @param addrlen length of the address
2434 * @return GNUNET_OK (always)
2437 add_to_foreign_address_list (void *cls,
2439 struct GNUNET_TIME_Absolute expiration,
2443 struct NeighbourList *n = cls;
2444 struct ForeignAddressList *fal;
2447 GNUNET_STATISTICS_update (stats,
2448 gettext_noop ("# valid peer addresses returned by peerinfo"),
2452 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2457 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2458 a2s (tname, addr, addrlen),
2460 GNUNET_i2s (&n->id),
2463 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2466 GNUNET_STATISTICS_update (stats,
2467 gettext_noop ("# previously validated addresses lacking transport"),
2473 fal->expires = GNUNET_TIME_absolute_max (expiration,
2475 schedule_next_ping (fal);
2481 fal->expires = GNUNET_TIME_absolute_max (expiration,
2486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2487 "Failed to add new address for `%4s'\n",
2488 GNUNET_i2s (&n->id));
2491 if (fal->validated == GNUNET_NO)
2493 fal->validated = GNUNET_YES;
2494 GNUNET_STATISTICS_update (stats,
2495 gettext_noop ("# peer addresses considered valid"),
2499 if (try == GNUNET_YES)
2501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2502 "Have new addresses, will try to trigger transmissions.\n");
2503 try_transmission_to_peer (n);
2510 * Add addresses in validated HELLO "h" to the set of addresses
2511 * we have for this peer.
2513 * @param cls closure ('struct NeighbourList*')
2514 * @param peer id of the peer, NULL for last call
2515 * @param h hello message for the peer (can be NULL)
2516 * @param trust amount of trust we have in the peer (not used)
2519 add_hello_for_peer (void *cls,
2520 const struct GNUNET_PeerIdentity *peer,
2521 const struct GNUNET_HELLO_Message *h,
2524 struct NeighbourList *n = cls;
2532 return; /* no HELLO available */
2534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2535 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2539 if (GNUNET_YES != n->public_key_valid)
2541 GNUNET_HELLO_get_key (h, &n->publicKey);
2542 n->public_key_valid = GNUNET_YES;
2544 GNUNET_HELLO_iterate_addresses (h,
2546 &add_to_foreign_address_list,
2552 * Create a fresh entry in our neighbour list for the given peer.
2553 * Will try to transmit our current HELLO to the new neighbour.
2554 * Do not call this function directly, use 'setup_peer_check_blacklist.
2556 * @param peer the peer for which we create the entry
2557 * @param do_hello should we schedule transmitting a HELLO
2558 * @return the new neighbour list entry
2560 static struct NeighbourList *
2561 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2564 struct NeighbourList *n;
2565 struct TransportPlugin *tp;
2566 struct ReadyList *rl;
2568 GNUNET_assert (our_hello != NULL);
2569 GNUNET_STATISTICS_update (stats,
2570 gettext_noop ("# active neighbours"),
2573 n = GNUNET_malloc (sizeof (struct NeighbourList));
2574 n->next = neighbours;
2578 GNUNET_TIME_relative_to_absolute
2579 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2580 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2581 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2582 MAX_BANDWIDTH_CARRY_S);
2586 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2588 rl = GNUNET_malloc (sizeof (struct ReadyList));
2590 rl->next = n->plugins;
2593 rl->addresses = NULL;
2597 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2599 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2600 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2601 &neighbour_timeout_task, n);
2604 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2605 0, GNUNET_TIME_UNIT_FOREVER_REL,
2606 &add_hello_for_peer, n);
2607 transmit_to_peer (NULL, NULL, 0,
2608 HELLO_ADDRESS_EXPIRATION,
2609 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2617 * Function called after we have checked if communicating
2618 * with a given peer is acceptable.
2620 * @param cls closure
2621 * @param n NULL if communication is not acceptable
2623 typedef void (*SetupContinuation)(void *cls,
2624 struct NeighbourList *n);
2628 * Information kept for each client registered to perform
2634 * This is a linked list.
2636 struct Blacklisters *next;
2639 * This is a linked list.
2641 struct Blacklisters *prev;
2644 * Client responsible for this entry.
2646 struct GNUNET_SERVER_Client *client;
2649 * Blacklist check that we're currently performing.
2651 struct BlacklistCheck *bc;
2657 * Head of DLL of blacklisting clients.
2659 static struct Blacklisters *bl_head;
2662 * Tail of DLL of blacklisting clients.
2664 static struct Blacklisters *bl_tail;
2668 * Context we use when performing a blacklist check.
2670 struct BlacklistCheck
2674 * This is a linked list.
2676 struct BlacklistCheck *next;
2679 * This is a linked list.
2681 struct BlacklistCheck *prev;
2684 * Peer being checked.
2686 struct GNUNET_PeerIdentity peer;
2689 * Option for setup neighbour afterwards.
2694 * Continuation to call with the result.
2696 SetupContinuation cont;
2704 * Current transmission request handle for this client, or NULL if no
2705 * request is pending.
2707 struct GNUNET_CONNECTION_TransmitHandle *th;
2710 * Our current position in the blacklisters list.
2712 struct Blacklisters *bl_pos;
2715 * Current task performing the check.
2717 GNUNET_SCHEDULER_TaskIdentifier task;
2722 * Head of DLL of active blacklisting queries.
2724 static struct BlacklistCheck *bc_head;
2727 * Tail of DLL of active blacklisting queries.
2729 static struct BlacklistCheck *bc_tail;
2733 * Perform next action in the blacklist check.
2735 * @param cls the 'struct BlacklistCheck*'
2739 do_blacklist_check (void *cls,
2740 const struct GNUNET_SCHEDULER_TaskContext *tc);
2744 * Transmit blacklist query to the client.
2746 * @param cls the 'struct BlacklistCheck'
2747 * @param size number of bytes allowed
2748 * @param buf where to copy the message
2749 * @return number of bytes copied to buf
2752 transmit_blacklist_message (void *cls,
2756 struct BlacklistCheck *bc = cls;
2757 struct Blacklisters *bl;
2758 struct BlacklistMessage bm;
2763 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
2764 bc->task = GNUNET_SCHEDULER_add_now (sched,
2765 &do_blacklist_check,
2770 bm.header.size = htons (sizeof (struct BlacklistMessage));
2771 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2772 bm.is_allowed = htonl (0);
2774 memcpy (buf, &bm, sizeof (bm));
2775 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
2781 * Perform next action in the blacklist check.
2783 * @param cls the 'struct BlacklistCheck*'
2787 do_blacklist_check (void *cls,
2788 const struct GNUNET_SCHEDULER_TaskContext *tc)
2790 struct BlacklistCheck *bc = cls;
2791 struct Blacklisters *bl;
2793 bc->task = GNUNET_SCHEDULER_NO_TASK;
2797 bc->cont (bc->cont_cls,
2798 setup_new_neighbour (&bc->peer, bc->do_hello));
2805 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
2806 sizeof (struct BlacklistMessage),
2807 GNUNET_TIME_UNIT_FOREVER_REL,
2808 &transmit_blacklist_message,
2815 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
2816 * does not yet exist, check the blacklist. If the blacklist says creating
2817 * one is acceptable, create one and call the continuation; otherwise
2818 * call the continuation with NULL.
2820 * @param peer peer to setup or look up a struct NeighbourList for
2821 * @param do_hello should we also schedule sending our HELLO to the peer
2822 * if this is a new record
2823 * @param cont function to call with the 'struct NeigbhbourList*'
2824 * @param cont_cls closure for cont
2827 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
2829 SetupContinuation cont,
2832 struct NeighbourList *n;
2833 struct BlacklistCheck *bc;
2835 n = find_neighbour(peer);
2841 if (bl_head == NULL)
2844 setup_new_neighbour (peer, do_hello));
2847 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
2848 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2850 bc->do_hello = do_hello;
2852 bc->cont_cls = cont_cls;
2853 bc->bl_pos = bl_head;
2854 bc->task = GNUNET_SCHEDULER_add_now (sched,
2855 &do_blacklist_check,
2861 * Function called with the result of querying a new blacklister about
2862 * it being allowed (or not) to continue to talk to an existing neighbour.
2864 * @param cls the original 'struct NeighbourList'
2865 * @param n NULL if we need to disconnect
2868 confirm_or_drop_neighbour (void *cls,
2869 struct NeighbourList *n)
2871 struct NeighbourList * orig = cls;
2874 disconnect_neighbour (orig, GNUNET_NO);
2879 * Handle a request to start a blacklist.
2881 * @param cls closure (always NULL)
2882 * @param client identification of the client
2883 * @param message the actual message
2886 handle_blacklist_init (void *cls,
2887 struct GNUNET_SERVER_Client *client,
2888 const struct GNUNET_MessageHeader *message)
2890 struct Blacklisters *bl;
2891 struct BlacklistCheck *bc;
2892 struct NeighbourList *n;
2897 if (bl->client == client)
2900 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2905 bl = GNUNET_malloc (sizeof (struct Blacklisters));
2906 bl->client = client;
2907 GNUNET_SERVER_client_keep (client);
2908 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
2909 /* confirm that all existing connections are OK! */
2913 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
2914 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2916 bc->do_hello = GNUNET_NO;
2917 bc->cont = &confirm_or_drop_neighbour;
2920 if (n == neighbours) /* all would wait for the same client, no need to
2921 create more than just the first task right now */
2922 bc->task = GNUNET_SCHEDULER_add_now (sched,
2923 &do_blacklist_check,
2931 * Handle a request to blacklist a peer.
2933 * @param cls closure (always NULL)
2934 * @param client identification of the client
2935 * @param message the actual message
2938 handle_blacklist_reply (void *cls,
2939 struct GNUNET_SERVER_Client *client,
2940 const struct GNUNET_MessageHeader *message)
2942 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
2943 struct Blacklisters *bl;
2944 struct BlacklistCheck *bc;
2947 while ( (bl != NULL) &&
2948 (bl->client != client) )
2952 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2957 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
2959 bc->cont (bc->cont_cls, NULL);
2960 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2965 bc->bl_pos = bc->bl_pos->next;
2966 bc->task = GNUNET_SCHEDULER_add_now (sched,
2967 &do_blacklist_check,
2970 /* check if any other bc's are waiting for this blacklister */
2974 if ( (bc->bl_pos == bl) &&
2975 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
2976 bc->task = GNUNET_SCHEDULER_add_now (sched,
2977 &do_blacklist_check,
2985 * Send periodic PING messages to a given foreign address.
2987 * @param cls our 'struct PeriodicValidationContext*'
2988 * @param tc task context
2991 send_periodic_ping (void *cls,
2992 const struct GNUNET_SCHEDULER_TaskContext *tc)
2994 struct ForeignAddressList *peer_address = cls;
2995 struct TransportPlugin *tp;
2996 struct ValidationEntry *va;
2997 struct NeighbourList *neighbour;
2998 struct TransportPingMessage ping;
2999 struct CheckAddressExistsClosure caec;
3001 uint16_t hello_size;
3004 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3005 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3007 tp = peer_address->ready_list->plugin;
3008 neighbour = peer_address->ready_list->neighbour;
3009 if (GNUNET_YES != neighbour->public_key_valid)
3011 /* no public key yet, try again later */
3012 schedule_next_ping (peer_address);
3015 caec.addr = peer_address->addr;
3016 caec.addrlen = peer_address->addrlen;
3017 caec.tname = tp->short_name;
3018 caec.session = peer_address->session;
3019 caec.exists = GNUNET_NO;
3020 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3021 &check_address_exists,
3023 if (caec.exists == GNUNET_YES)
3025 /* During validation attempts we will likely trigger the other
3026 peer trying to validate our address which in turn will cause
3027 it to send us its HELLO, so we expect to hit this case rather
3028 frequently. Only print something if we are very verbose. */
3029 #if DEBUG_TRANSPORT > 1
3030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3031 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3032 (peer_address->addr != NULL)
3033 ? a2s (tp->short_name,
3035 peer_address->addrlen)
3038 GNUNET_i2s (&neighbour->id));
3040 schedule_next_ping (peer_address);
3043 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3044 va->transport_name = GNUNET_strdup (tp->short_name);
3045 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3047 va->send_time = GNUNET_TIME_absolute_get();
3048 va->session = peer_address->session;
3049 if (peer_address->addr != NULL)
3051 va->addr = (const void*) &va[1];
3052 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3053 va->addrlen = peer_address->addrlen;
3055 memcpy(&va->publicKey,
3056 &neighbour->publicKey,
3057 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3059 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3060 HELLO_VERIFICATION_TIMEOUT,
3061 &timeout_hello_validation,
3063 GNUNET_CONTAINER_multihashmap_put (validation_map,
3064 &neighbour->id.hashPubKey,
3066 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3067 hello_size = GNUNET_HELLO_size(our_hello);
3068 tsize = sizeof(struct TransportPingMessage) + hello_size;
3069 message_buf = GNUNET_malloc(tsize);
3070 ping.challenge = htonl(va->challenge);
3071 ping.header.size = htons(sizeof(struct TransportPingMessage));
3072 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3073 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3074 memcpy(message_buf, our_hello, hello_size);
3075 memcpy(&message_buf[hello_size],
3077 sizeof(struct TransportPingMessage));
3078 #if DEBUG_TRANSPORT_REVALIDATION
3079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3080 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3081 (peer_address->addr != NULL)
3082 ? a2s (peer_address->plugin->short_name,
3084 peer_address->addrlen)
3087 GNUNET_i2s (&neighbour->id),
3088 "HELLO", hello_size,
3089 "PING", sizeof (struct TransportPingMessage));
3091 GNUNET_STATISTICS_update (stats,
3092 gettext_noop ("# PING messages sent for re-validation"),
3095 transmit_to_peer (NULL, peer_address,
3096 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3097 HELLO_VERIFICATION_TIMEOUT,
3099 GNUNET_YES, neighbour);
3100 GNUNET_free(message_buf);
3101 schedule_next_ping (peer_address);
3106 * Schedule the job that will cause us to send a PING to the
3107 * foreign address to evaluate its validity and latency.
3109 * @param fal address to PING
3112 schedule_next_ping (struct ForeignAddressList *fal)
3114 struct GNUNET_TIME_Relative delay;
3116 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3118 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3119 delay.value /= 2; /* do before expiration */
3120 delay = GNUNET_TIME_relative_min (delay,
3121 LATENCY_EVALUATION_MAX_DELAY);
3122 if (GNUNET_YES != fal->estimated)
3124 delay = GNUNET_TIME_UNIT_ZERO;
3125 fal->estimated = GNUNET_YES;
3127 if (GNUNET_YES == fal->connected)
3129 delay = GNUNET_TIME_relative_min (delay,
3130 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3132 /* FIXME: also adjust delay based on how close the last
3133 observed latency is to the latency of the best alternative */
3134 /* bound how fast we can go */
3135 delay = GNUNET_TIME_relative_max (delay,
3136 GNUNET_TIME_UNIT_SECONDS);
3137 /* randomize a bit (to avoid doing all at the same time) */
3138 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3139 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
3141 &send_periodic_ping,
3149 * Function that will be called if we receive some payload
3150 * from another peer.
3152 * @param message the payload
3153 * @param n peer who claimed to be the sender
3156 handle_payload_message (const struct GNUNET_MessageHeader *message,
3157 struct NeighbourList *n)
3159 struct InboundMessage *im;
3160 struct TransportClient *cpos;
3163 msize = ntohs (message->size);
3164 if (n->received_pong == GNUNET_NO)
3166 GNUNET_free_non_null (n->pre_connect_message_buffer);
3167 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3168 memcpy (n->pre_connect_message_buffer, message, msize);
3172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173 "Received message of type %u from `%4s', sending to all clients.\n",
3174 ntohs (message->type),
3175 GNUNET_i2s (&n->id));
3177 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3180 n->quota_violation_count++;
3182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3183 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3184 n->in_tracker.available_bytes_per_s__,
3185 n->quota_violation_count);
3187 /* Discount 32k per violation */
3188 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3193 if (n->quota_violation_count > 0)
3195 /* try to add 32k back */
3196 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3198 n->quota_violation_count--;
3201 GNUNET_STATISTICS_update (stats,
3202 gettext_noop ("# payload received from other peers"),
3205 /* transmit message to all clients */
3206 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3207 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3208 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3209 im->latency = GNUNET_TIME_relative_hton (n->latency);
3211 im->distance = ntohl(n->distance);
3212 memcpy (&im[1], message, msize);
3214 while (cpos != NULL)
3216 transmit_to_client (cpos, &im->header, GNUNET_YES);
3224 * Iterator over hash map entries. Checks if the given validation
3225 * entry is for the same challenge as what is given in the PONG.
3227 * @param cls the 'struct TransportPongMessage*'
3228 * @param key peer identity
3229 * @param value value in the hash map ('struct ValidationEntry')
3230 * @return GNUNET_YES if we should continue to
3231 * iterate (mismatch), GNUNET_NO if not (entry matched)
3234 check_pending_validation (void *cls,
3235 const GNUNET_HashCode * key,
3238 const struct TransportPongMessage *pong = cls;
3239 struct ValidationEntry *ve = value;
3240 struct AddValidatedAddressContext avac;
3241 unsigned int challenge = ntohl(pong->challenge);
3242 struct GNUNET_HELLO_Message *hello;
3243 struct GNUNET_PeerIdentity target;
3244 struct NeighbourList *n;
3245 struct ForeignAddressList *fal;
3246 struct GNUNET_MessageHeader *prem;
3248 if (ve->challenge != challenge)
3253 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
3258 GNUNET_break_op (0);
3264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3265 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3268 ? a2s (ve->transport_name,
3269 (const struct sockaddr *) ve->addr,
3272 ve->transport_name);
3274 GNUNET_STATISTICS_update (stats,
3275 gettext_noop ("# address validation successes"),
3278 /* create the updated HELLO */
3279 GNUNET_CRYPTO_hash (&ve->publicKey,
3280 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3281 &target.hashPubKey);
3282 if (ve->addr != NULL)
3284 avac.done = GNUNET_NO;
3286 hello = GNUNET_HELLO_create (&ve->publicKey,
3287 &add_validated_address,
3289 GNUNET_PEERINFO_add_peer (peerinfo,
3291 GNUNET_free (hello);
3293 n = find_neighbour (&target);
3296 n->publicKey = ve->publicKey;
3297 n->public_key_valid = GNUNET_YES;
3298 fal = add_peer_address (n,
3303 GNUNET_assert (fal != NULL);
3304 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3305 fal->validated = GNUNET_YES;
3306 mark_address_connected (fal);
3307 GNUNET_STATISTICS_update (stats,
3308 gettext_noop ("# peer addresses considered valid"),
3311 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3312 schedule_next_ping (fal);
3313 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
3314 n->latency = fal->latency;
3316 n->latency.value = (fal->latency.value + n->latency.value) / 2;
3318 n->distance = fal->distance;
3319 if (GNUNET_NO == n->received_pong)
3321 n->received_pong = GNUNET_YES;
3322 notify_clients_connect (&target, n->latency, n->distance);
3323 if (NULL != (prem = n->pre_connect_message_buffer))
3325 n->pre_connect_message_buffer = NULL;
3326 handle_payload_message (prem, n);
3330 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3332 GNUNET_SCHEDULER_cancel (sched,
3334 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3335 try_transmission_to_peer (n);
3339 /* clean up validation entry */
3340 GNUNET_assert (GNUNET_YES ==
3341 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3344 GNUNET_SCHEDULER_cancel (sched,
3346 GNUNET_free (ve->transport_name);
3353 * Function that will be called if we receive a validation
3354 * of an address challenge that we transmitted to another
3355 * peer. Note that the validation should only be considered
3356 * acceptable if the challenge matches AND if the sender
3357 * address is at least a plausible address for this peer
3358 * (otherwise we may be seeing a MiM attack).
3360 * @param cls closure
3361 * @param message the pong message
3362 * @param peer who responded to our challenge
3363 * @param sender_address string describing our sender address (as observed
3364 * by the other peer in binary format)
3365 * @param sender_address_len number of bytes in 'sender_address'
3368 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3369 const struct GNUNET_PeerIdentity *peer,
3370 const char *sender_address,
3371 size_t sender_address_len)
3373 #if DEBUG_TRANSPORT > 1
3374 /* we get tons of these that just get discarded, only log
3375 if we are quite verbose */
3376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3377 "Receiving `%s' message from `%4s'.\n", "PONG",
3380 GNUNET_STATISTICS_update (stats,
3381 gettext_noop ("# PONG messages received"),
3384 if (GNUNET_SYSERR !=
3385 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3387 &check_pending_validation,
3390 /* This is *expected* to happen a lot since we send
3391 PONGs to *all* known addresses of the sender of
3392 the PING, so most likely we get multiple PONGs
3393 per PING, and all but the first PONG will end up
3394 here. So really we should not print anything here
3395 unless we want to be very, very verbose... */
3396 #if DEBUG_TRANSPORT > 2
3397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3398 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3410 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3412 * @param cls the 'struct ValidationEntry*'
3413 * @param neighbour neighbour to validate, NULL if validation failed
3416 transmit_hello_and_ping (void *cls,
3417 struct NeighbourList *neighbour)
3419 struct ValidationEntry *va = cls;
3420 struct ForeignAddressList *peer_address;
3421 struct TransportPingMessage ping;
3422 uint16_t hello_size;
3426 if (neighbour == NULL)
3428 /* FIXME: stats... */
3429 GNUNET_free (va->transport_name);
3433 neighbour->publicKey = va->publicKey;
3434 neighbour->public_key_valid = GNUNET_YES;
3435 peer_address = add_peer_address (neighbour,
3436 va->transport_name, NULL,
3437 (const void*) &va[1],
3439 if (peer_address == NULL)
3441 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3442 "Failed to add peer `%4s' for plugin `%s'\n",
3443 GNUNET_i2s (&neighbour->id),
3444 va->transport_name);
3445 GNUNET_free (va->transport_name);
3449 hello_size = GNUNET_HELLO_size(our_hello);
3450 tsize = sizeof(struct TransportPingMessage) + hello_size;
3451 message_buf = GNUNET_malloc(tsize);
3452 ping.challenge = htonl(va->challenge);
3453 ping.header.size = htons(sizeof(struct TransportPingMessage));
3454 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3455 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3456 memcpy(message_buf, our_hello, hello_size);
3457 memcpy(&message_buf[hello_size],
3459 sizeof(struct TransportPingMessage));
3461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3462 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3463 a2s (va->transport_name,
3464 (const void*) &va[1], va->addrlen),
3466 GNUNET_i2s (&neighbour->id),
3467 "HELLO", hello_size,
3468 "PING", sizeof (struct TransportPingMessage));
3470 GNUNET_STATISTICS_update (stats,
3471 gettext_noop ("# PING messages sent for initial validation"),
3474 transmit_to_peer (NULL, peer_address,
3475 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3476 HELLO_VERIFICATION_TIMEOUT,
3478 GNUNET_YES, neighbour);
3479 GNUNET_free(message_buf);
3484 * Check if the given address is already being validated; if not,
3485 * append the given address to the list of entries that are being be
3486 * validated and initiate validation.
3488 * @param cls closure ('struct CheckHelloValidatedContext *')
3489 * @param tname name of the transport
3490 * @param expiration expiration time
3491 * @param addr the address
3492 * @param addrlen length of the address
3493 * @return GNUNET_OK (always)
3496 run_validation (void *cls,
3498 struct GNUNET_TIME_Absolute expiration,
3502 struct CheckHelloValidatedContext *chvc = cls;
3503 struct GNUNET_PeerIdentity id;
3504 struct TransportPlugin *tp;
3505 struct ValidationEntry *va;
3506 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3507 struct CheckAddressExistsClosure caec;
3508 struct OwnAddressList *oal;
3510 GNUNET_assert (addr != NULL);
3511 GNUNET_STATISTICS_update (stats,
3512 gettext_noop ("# peer addresses scheduled for validation"),
3515 tp = find_transport (tname);
3518 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3519 GNUNET_ERROR_TYPE_BULK,
3521 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3523 GNUNET_STATISTICS_update (stats,
3524 gettext_noop ("# peer addresses not validated (plugin not available)"),
3529 /* check if this is one of our own addresses */
3530 oal = tp->addresses;
3533 if ( (oal->addrlen == addrlen) &&
3534 (0 == memcmp (oal->addr,
3538 /* not plausible, this address is equivalent to our own address! */
3539 GNUNET_STATISTICS_update (stats,
3540 gettext_noop ("# peer addresses not validated (loopback)"),
3547 GNUNET_HELLO_get_key (chvc->hello, &pk);
3548 GNUNET_CRYPTO_hash (&pk,
3550 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3553 if (is_blacklisted(&id, tp))
3556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3557 _("Attempted to validate blacklisted peer `%s' using `%s'!\n"), GNUNET_i2s(&id), tname);
3563 caec.addrlen = addrlen;
3564 caec.session = NULL;
3566 caec.exists = GNUNET_NO;
3567 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3568 &check_address_exists,
3570 if (caec.exists == GNUNET_YES)
3572 /* During validation attempts we will likely trigger the other
3573 peer trying to validate our address which in turn will cause
3574 it to send us its HELLO, so we expect to hit this case rather
3575 frequently. Only print something if we are very verbose. */
3576 #if DEBUG_TRANSPORT > 1
3577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3578 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3579 a2s (tname, addr, addrlen),
3583 GNUNET_STATISTICS_update (stats,
3584 gettext_noop ("# peer addresses not validated (in progress)"),
3589 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
3590 va->transport_name = GNUNET_strdup (tname);
3591 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3593 va->send_time = GNUNET_TIME_absolute_get();
3594 va->addr = (const void*) &va[1];
3595 memcpy (&va[1], addr, addrlen);
3596 va->addrlen = addrlen;
3597 GNUNET_HELLO_get_key (chvc->hello,
3599 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3600 HELLO_VERIFICATION_TIMEOUT,
3601 &timeout_hello_validation,
3603 GNUNET_CONTAINER_multihashmap_put (validation_map,
3606 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3607 setup_peer_check_blacklist (&id, GNUNET_NO,
3608 &transmit_hello_and_ping,
3615 * Check if addresses in validated hello "h" overlap with
3616 * those in "chvc->hello" and validate the rest.
3618 * @param cls closure
3619 * @param peer id of the peer, NULL for last call
3620 * @param h hello message for the peer (can be NULL)
3621 * @param trust amount of trust we have in the peer (not used)
3624 check_hello_validated (void *cls,
3625 const struct GNUNET_PeerIdentity *peer,
3626 const struct GNUNET_HELLO_Message *h,
3629 struct CheckHelloValidatedContext *chvc = cls;
3630 struct GNUNET_HELLO_Message *plain_hello;
3631 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3632 struct GNUNET_PeerIdentity target;
3633 struct NeighbourList *n;
3638 GNUNET_CONTAINER_DLL_remove (chvc_head,
3641 if (GNUNET_NO == chvc->hello_known)
3643 /* notify PEERINFO about the peer now, so that we at least
3644 have the public key if some other component needs it */
3645 GNUNET_HELLO_get_key (chvc->hello, &pk);
3646 GNUNET_CRYPTO_hash (&pk,
3647 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3648 &target.hashPubKey);
3649 plain_hello = GNUNET_HELLO_create (&pk,
3652 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
3653 GNUNET_free (plain_hello);
3655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3656 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
3658 GNUNET_i2s (&target));
3660 GNUNET_STATISTICS_update (stats,
3661 gettext_noop ("# new HELLOs requiring full validation"),
3664 GNUNET_HELLO_iterate_addresses (chvc->hello,
3671 GNUNET_STATISTICS_update (stats,
3672 gettext_noop ("# duplicate HELLO (peer known)"),
3682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3683 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
3687 chvc->hello_known = GNUNET_YES;
3688 n = find_neighbour (peer);
3691 GNUNET_HELLO_iterate_addresses (h,
3693 &add_to_foreign_address_list,
3695 try_transmission_to_peer (n);
3699 GNUNET_STATISTICS_update (stats,
3700 gettext_noop ("# no existing neighbour record (validating HELLO)"),
3704 GNUNET_STATISTICS_update (stats,
3705 gettext_noop ("# HELLO validations (update case)"),
3708 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
3710 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
3717 * Process HELLO-message.
3719 * @param plugin transport involved, may be NULL
3720 * @param message the actual message
3721 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
3724 process_hello (struct TransportPlugin *plugin,
3725 const struct GNUNET_MessageHeader *message)
3728 struct GNUNET_PeerIdentity target;
3729 const struct GNUNET_HELLO_Message *hello;
3730 struct CheckHelloValidatedContext *chvc;
3731 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
3733 hsize = ntohs (message->size);
3734 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
3735 (hsize < sizeof (struct GNUNET_MessageHeader)))
3738 return GNUNET_SYSERR;
3740 GNUNET_STATISTICS_update (stats,
3741 gettext_noop ("# HELLOs received for validation"),
3744 /* first, check if load is too high */
3745 if (GNUNET_SCHEDULER_get_load (sched,
3746 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
3748 GNUNET_STATISTICS_update (stats,
3749 gettext_noop ("# HELLOs ignored due to high load"),
3754 hello = (const struct GNUNET_HELLO_Message *) message;
3755 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3757 GNUNET_break_op (0);
3758 return GNUNET_SYSERR;
3760 GNUNET_CRYPTO_hash (&publicKey,
3761 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3762 &target.hashPubKey);
3763 if (0 == memcmp (&my_identity,
3765 sizeof (struct GNUNET_PeerIdentity)))
3767 GNUNET_STATISTICS_update (stats,
3768 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3773 #if DEBUG_TRANSPORT > 1
3774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3775 "Processing `%s' message for `%4s' of size %u\n",
3777 GNUNET_i2s (&target),
3778 GNUNET_HELLO_size(hello));
3780 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3781 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3782 memcpy (&chvc[1], hello, hsize);
3783 GNUNET_CONTAINER_DLL_insert (chvc_head,
3786 /* finally, check if HELLO was previously validated
3787 (continuation will then schedule actual validation) */
3788 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
3791 HELLO_VERIFICATION_TIMEOUT,
3792 &check_hello_validated, chvc);
3798 * The peer specified by the given neighbour has timed-out or a plugin
3799 * has disconnected. We may either need to do nothing (other plugins
3800 * still up), or trigger a full disconnect and clean up. This
3801 * function updates our state and does the necessary notifications.
3802 * Also notifies our clients that the neighbour is now officially
3805 * @param n the neighbour list entry for the peer
3806 * @param check should we just check if all plugins
3807 * disconnected or must we ask all plugins to
3811 disconnect_neighbour (struct NeighbourList *n, int check)
3813 struct ReadyList *rpos;
3814 struct NeighbourList *npos;
3815 struct NeighbourList *nprev;
3816 struct MessageQueue *mq;
3817 struct ForeignAddressList *peer_addresses;
3818 struct ForeignAddressList *peer_pos;
3820 if (GNUNET_YES == check)
3823 while (NULL != rpos)
3825 peer_addresses = rpos->addresses;
3826 while (peer_addresses != NULL)
3828 if (GNUNET_YES == peer_addresses->connected)
3829 return; /* still connected */
3830 peer_addresses = peer_addresses->next;
3836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3837 "Disconnecting from `%4s'\n",
3838 GNUNET_i2s (&n->id));
3840 /* remove n from neighbours list */
3843 while ((npos != NULL) && (npos != n))
3848 GNUNET_assert (npos != NULL);
3850 neighbours = n->next;
3852 nprev->next = n->next;
3854 /* notify all clients about disconnect */
3855 if (GNUNET_YES == n->received_pong)
3856 notify_clients_disconnect (&n->id);
3858 /* clean up all plugins, cancel connections and pending transmissions */
3859 while (NULL != (rpos = n->plugins))
3861 n->plugins = rpos->next;
3862 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3863 while (rpos->addresses != NULL)
3865 peer_pos = rpos->addresses;
3866 rpos->addresses = peer_pos->next;
3867 if (peer_pos->connected == GNUNET_YES)
3868 GNUNET_STATISTICS_update (stats,
3869 gettext_noop ("# connected addresses"),
3872 if (GNUNET_YES == peer_pos->validated)
3873 GNUNET_STATISTICS_update (stats,
3874 gettext_noop ("# peer addresses considered valid"),
3877 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3879 GNUNET_SCHEDULER_cancel (sched,
3880 peer_pos->revalidate_task);
3881 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3883 GNUNET_free(peer_pos);
3888 /* free all messages on the queue */
3889 while (NULL != (mq = n->messages_head))
3891 GNUNET_STATISTICS_update (stats,
3892 gettext_noop ("# bytes in message queue for other peers"),
3893 - (int64_t) mq->message_buf_size,
3895 GNUNET_STATISTICS_update (stats,
3896 gettext_noop ("# bytes discarded due to disconnect"),
3897 mq->message_buf_size,
3899 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3902 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3904 sizeof(struct GNUNET_PeerIdentity)));
3907 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3909 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3910 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3912 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3914 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3915 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3917 if (n->piter != NULL)
3919 GNUNET_PEERINFO_iterate_cancel (n->piter);
3922 /* finally, free n itself */
3923 GNUNET_STATISTICS_update (stats,
3924 gettext_noop ("# active neighbours"),
3927 GNUNET_free_non_null (n->pre_connect_message_buffer);
3933 * We have received a PING message from someone. Need to send a PONG message
3934 * in response to the peer by any means necessary.
3937 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3938 const struct GNUNET_PeerIdentity *peer,
3939 const char *sender_address,
3940 uint16_t sender_address_len)
3942 struct TransportPlugin *plugin = cls;
3943 struct TransportPingMessage *ping;
3944 struct TransportPongMessage *pong;
3945 struct NeighbourList *n;
3946 struct ReadyList *rl;
3947 struct ForeignAddressList *fal;
3949 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3951 GNUNET_break_op (0);
3952 return GNUNET_SYSERR;
3955 ping = (struct TransportPingMessage *) message;
3956 if (0 != memcmp (&ping->target,
3957 plugin->env.my_identity,
3958 sizeof (struct GNUNET_PeerIdentity)))
3960 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3961 _("Received `%s' message not destined for me!\n"),
3963 return GNUNET_SYSERR;
3966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3967 "Processing `%s' from `%s'\n",
3969 (sender_address != NULL)
3970 ? a2s (plugin->short_name,
3971 (const struct sockaddr *)sender_address,
3975 GNUNET_STATISTICS_update (stats,
3976 gettext_noop ("# PING messages received"),
3979 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3980 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3981 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3982 pong->purpose.size =
3983 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3985 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3986 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3987 pong->challenge = ping->challenge;
3988 pong->addrlen = htons(sender_address_len);
3989 memcpy(&pong->signer,
3991 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3992 if (sender_address != NULL)
3993 memcpy (&pong[1], sender_address, sender_address_len);
3995 GNUNET_assert (GNUNET_OK ==
3996 GNUNET_CRYPTO_rsa_sign (my_private_key,
3997 &pong->purpose, &pong->signature));
3999 n = find_neighbour(peer);
4000 GNUNET_assert (n != NULL);
4001 /* first try reliable response transmission */
4005 fal = rl->addresses;
4008 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4011 ntohs (pong->header.size),
4012 TRANSPORT_PONG_PRIORITY,
4013 HELLO_VERIFICATION_TIMEOUT,
4021 GNUNET_STATISTICS_update (stats,
4022 gettext_noop ("# PONGs unicast via reliable transport"),
4032 /* no reliable method found, do multicast */
4033 GNUNET_STATISTICS_update (stats,
4034 gettext_noop ("# PONGs multicast to all available addresses"),
4040 fal = rl->addresses;
4043 transmit_to_peer(NULL, fal,
4044 TRANSPORT_PONG_PRIORITY,
4045 HELLO_VERIFICATION_TIMEOUT,
4047 ntohs(pong->header.size),
4060 * Function called by the plugin for each received message.
4061 * Update data volumes, possibly notify plugins about
4062 * reducing the rate at which they read from the socket
4063 * and generally forward to our receive callback.
4065 * @param cls the "struct TransportPlugin *" we gave to the plugin
4066 * @param peer (claimed) identity of the other peer
4067 * @param message the message, NULL if we only care about
4068 * learning about the delay until we should receive again
4069 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
4070 * @param session identifier used for this session (can be NULL)
4071 * @param sender_address binary address of the sender (if observed)
4072 * @param sender_address_len number of bytes in sender_address
4073 * @return how long the plugin should wait until receiving more data
4074 * (plugins that do not support this, can ignore the return value)
4076 static struct GNUNET_TIME_Relative
4077 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4078 const struct GNUNET_MessageHeader *message,
4080 struct Session *session,
4081 const char *sender_address,
4082 uint16_t sender_address_len)
4084 struct TransportPlugin *plugin = cls;
4085 struct ReadyList *service_context;
4086 struct ForeignAddressList *peer_address;
4088 struct NeighbourList *n;
4089 struct GNUNET_TIME_Relative ret;
4091 if (is_blacklisted (peer, plugin))
4092 return GNUNET_TIME_UNIT_FOREVER_REL;
4094 n = find_neighbour (peer);
4096 n = setup_new_neighbour (peer, GNUNET_YES);
4097 service_context = n->plugins;
4098 while ((service_context != NULL) && (plugin != service_context->plugin))
4099 service_context = service_context->next;
4100 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4101 peer_address = NULL;
4102 if (message != NULL)
4104 if ( (session != NULL) ||
4105 (sender_address != NULL) )
4106 peer_address = add_peer_address (n,
4110 sender_address_len);
4111 if (peer_address != NULL)
4113 peer_address->distance = distance;
4114 if (GNUNET_YES == peer_address->validated)
4115 mark_address_connected (peer_address);
4116 peer_address->timeout
4118 GNUNET_TIME_relative_to_absolute
4119 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4120 schedule_next_ping (peer_address);
4122 /* update traffic received amount ... */
4123 msize = ntohs (message->size);
4124 GNUNET_STATISTICS_update (stats,
4125 gettext_noop ("# bytes received from other peers"),
4128 n->distance = distance;
4130 GNUNET_TIME_relative_to_absolute
4131 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4132 GNUNET_SCHEDULER_cancel (sched,
4135 GNUNET_SCHEDULER_add_delayed (sched,
4136 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4137 &neighbour_timeout_task, n);
4138 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4140 /* dropping message due to frequent inbound volume violations! */
4141 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4142 GNUNET_ERROR_TYPE_BULK,
4144 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4145 n->in_tracker.available_bytes_per_s__,
4146 n->quota_violation_count);
4147 GNUNET_STATISTICS_update (stats,
4148 gettext_noop ("# bandwidth quota violations by other peers"),
4151 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4155 "Received message of type %u from `%4s', sending to all clients.\n",
4156 ntohs (message->type), GNUNET_i2s (peer));
4158 switch (ntohs (message->type))
4160 case GNUNET_MESSAGE_TYPE_HELLO:
4161 GNUNET_STATISTICS_update (stats,
4162 gettext_noop ("# HELLO messages received from other peers"),
4165 process_hello (plugin, message);
4167 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4168 handle_ping (plugin, message, peer, sender_address, sender_address_len);
4170 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4171 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4174 handle_payload_message (message, n);
4178 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4181 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4182 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4183 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4184 (unsigned int) n->in_tracker.available_bytes_per_s__,
4185 (unsigned long long) ret.value);
4186 GNUNET_STATISTICS_update (stats,
4187 gettext_noop ("# ms throttling suggested"),
4188 (int64_t) ret.value,
4195 * Handle START-message. This is the first message sent to us
4196 * by any client which causes us to add it to our list.
4198 * @param cls closure (always NULL)
4199 * @param client identification of the client
4200 * @param message the actual message
4203 handle_start (void *cls,
4204 struct GNUNET_SERVER_Client *client,
4205 const struct GNUNET_MessageHeader *message)
4207 struct TransportClient *c;
4208 struct ConnectInfoMessage cim;
4209 struct NeighbourList *n;
4212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4213 "Received `%s' request from client\n", "START");
4218 if (c->client == client)
4220 /* client already on our list! */
4222 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4227 c = GNUNET_malloc (sizeof (struct TransportClient));
4231 if (our_hello != NULL)
4234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4235 "Sending our own `%s' to new client\n", "HELLO");
4237 transmit_to_client (c,
4238 (const struct GNUNET_MessageHeader *) our_hello,
4240 /* tell new client about all existing connections */
4241 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
4242 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4246 if (GNUNET_YES == n->received_pong)
4249 cim.latency = GNUNET_TIME_relative_hton (n->latency);
4250 cim.distance = htonl (n->distance);
4251 transmit_to_client (c, &cim.header, GNUNET_NO);
4256 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4261 * Handle HELLO-message.
4263 * @param cls closure (always NULL)
4264 * @param client identification of the client
4265 * @param message the actual message
4268 handle_hello (void *cls,
4269 struct GNUNET_SERVER_Client *client,
4270 const struct GNUNET_MessageHeader *message)
4274 GNUNET_STATISTICS_update (stats,
4275 gettext_noop ("# HELLOs received from clients"),
4278 ret = process_hello (NULL, message);
4279 GNUNET_SERVER_receive_done (client, ret);
4284 * Closure for 'transmit_client_message'; followed by
4285 * 'msize' bytes of the actual message.
4287 struct TransmitClientMessageContext
4290 * Client on whom's behalf we are sending.
4292 struct GNUNET_SERVER_Client *client;
4295 * Timeout for the transmission.
4297 struct GNUNET_TIME_Absolute timeout;
4305 * Size of the message in bytes.
4312 * Schedule transmission of a message we got from a client to a peer.
4314 * @param cls the 'struct TransmitClientMessageContext*'
4315 * @param n destination, or NULL on error (in that case, drop the message)
4318 transmit_client_message (void *cls,
4319 struct NeighbourList *n)
4321 struct TransmitClientMessageContext *tcmc = cls;
4322 struct TransportClient *tc;
4325 while ((tc != NULL) && (tc->client != tcmc->client))
4330 transmit_to_peer (tc, NULL, tcmc->priority,
4331 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
4333 tcmc->msize, GNUNET_NO, n);
4335 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
4336 GNUNET_SERVER_client_drop (tcmc->client);
4342 * Handle SEND-message.
4344 * @param cls closure (always NULL)
4345 * @param client identification of the client
4346 * @param message the actual message
4349 handle_send (void *cls,
4350 struct GNUNET_SERVER_Client *client,
4351 const struct GNUNET_MessageHeader *message)
4353 const struct OutboundMessage *obm;
4354 const struct GNUNET_MessageHeader *obmm;
4355 struct TransmitClientMessageContext *tcmc;
4359 size = ntohs (message->size);
4361 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
4364 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4367 GNUNET_STATISTICS_update (stats,
4368 gettext_noop ("# payload received for other peers"),
4371 obm = (const struct OutboundMessage *) message;
4372 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4373 msize = ntohs (obmm->size);
4375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4376 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
4377 "SEND", GNUNET_i2s (&obm->peer),
4381 if (size != msize + sizeof (struct OutboundMessage))
4384 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4387 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
4388 tcmc->client = client;
4389 tcmc->priority = ntohl (obm->priority);
4390 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
4391 tcmc->msize = msize;
4392 memcpy (&tcmc[1], obmm, msize);
4393 GNUNET_SERVER_client_keep (client);
4394 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
4395 &transmit_client_message,
4401 * Handle SET_QUOTA-message.
4403 * @param cls closure (always NULL)
4404 * @param client identification of the client
4405 * @param message the actual message
4408 handle_set_quota (void *cls,
4409 struct GNUNET_SERVER_Client *client,
4410 const struct GNUNET_MessageHeader *message)
4412 const struct QuotaSetMessage *qsm =
4413 (const struct QuotaSetMessage *) message;
4414 struct NeighbourList *n;
4416 GNUNET_STATISTICS_update (stats,
4417 gettext_noop ("# SET QUOTA messages received"),
4420 n = find_neighbour (&qsm->peer);
4423 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4424 GNUNET_STATISTICS_update (stats,
4425 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
4431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4432 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
4434 (unsigned int) ntohl (qsm->quota.value__),
4435 (unsigned int) n->in_tracker.available_bytes_per_s__,
4436 GNUNET_i2s (&qsm->peer));
4438 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
4440 if (0 == ntohl (qsm->quota.value__))
4441 disconnect_neighbour (n, GNUNET_NO);
4442 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4447 * Take the given address and append it to the set of results send back to
4450 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
4451 * @param address the resolved name, NULL to indicate the last response
4454 transmit_address_to_client (void *cls, const char *address)
4456 struct GNUNET_SERVER_TransmitContext *tc = cls;
4459 if (NULL == address)
4462 slen = strlen (address) + 1;
4463 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
4464 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4465 if (NULL == address)
4466 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
4471 * Handle AddressLookup-message.
4473 * @param cls closure (always NULL)
4474 * @param client identification of the client
4475 * @param message the actual message
4478 handle_address_lookup (void *cls,
4479 struct GNUNET_SERVER_Client *client,
4480 const struct GNUNET_MessageHeader *message)
4482 const struct AddressLookupMessage *alum;
4483 struct TransportPlugin *lsPlugin;
4484 const char *nameTransport;
4485 const char *address;
4487 struct GNUNET_SERVER_TransmitContext *tc;
4488 struct GNUNET_TIME_Absolute timeout;
4489 struct GNUNET_TIME_Relative rtimeout;
4492 size = ntohs (message->size);
4493 if (size < sizeof (struct AddressLookupMessage))
4495 GNUNET_break_op (0);
4496 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4499 alum = (const struct AddressLookupMessage *) message;
4500 uint32_t addressLen = ntohl (alum->addrlen);
4501 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
4503 GNUNET_break_op (0);
4504 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4507 address = (const char *) &alum[1];
4508 nameTransport = (const char *) &address[addressLen];
4510 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
4512 GNUNET_break_op (0);
4513 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4516 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4517 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4518 numeric = ntohl (alum->numeric_only);
4519 lsPlugin = find_transport (nameTransport);
4520 if (NULL == lsPlugin)
4522 tc = GNUNET_SERVER_transmit_context_create (client);
4523 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4524 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4525 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4528 tc = GNUNET_SERVER_transmit_context_create (client);
4529 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4531 address, addressLen,
4534 &transmit_address_to_client, tc);
4538 * List of handlers for the messages understood by this
4541 static struct GNUNET_SERVER_MessageHandler handlers[] = {
4542 {&handle_start, NULL,
4543 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4544 {&handle_hello, NULL,
4545 GNUNET_MESSAGE_TYPE_HELLO, 0},
4546 {&handle_send, NULL,
4547 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4548 {&handle_set_quota, NULL,
4549 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4550 {&handle_address_lookup, NULL,
4551 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4553 {&handle_blacklist_init, NULL,
4554 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
4555 {&handle_blacklist_reply, NULL,
4556 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
4562 * Setup the environment for this plugin.
4565 create_environment (struct TransportPlugin *plug)
4567 plug->env.cfg = cfg;
4568 plug->env.sched = sched;
4569 plug->env.my_identity = &my_identity;
4570 plug->env.cls = plug;
4571 plug->env.receive = &plugin_env_receive;
4572 plug->env.notify_address = &plugin_env_notify_address;
4573 plug->env.session_end = &plugin_env_session_end;
4574 plug->env.max_connections = max_connect_per_transport;
4575 plug->env.stats = stats;
4580 * Start the specified transport (load the plugin).
4583 start_transport (struct GNUNET_SERVER_Handle *server,
4586 struct TransportPlugin *plug;
4589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4590 _("Loading `%s' transport plugin\n"), name);
4591 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4592 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4593 create_environment (plug);
4594 plug->short_name = GNUNET_strdup (name);
4595 plug->lib_name = libname;
4596 plug->next = plugins;
4598 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4599 if (plug->api == NULL)
4601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4602 _("Failed to load transport plugin for `%s'\n"), name);
4603 GNUNET_free (plug->short_name);
4604 plugins = plug->next;
4605 GNUNET_free (libname);
4612 * Called whenever a client is disconnected. Frees our
4613 * resources associated with that client.
4615 * @param cls closure
4616 * @param client identification of the client
4619 client_disconnect_notification (void *cls,
4620 struct GNUNET_SERVER_Client *client)
4622 struct TransportClient *pos;
4623 struct TransportClient *prev;
4624 struct ClientMessageQueueEntry *mqe;
4625 struct Blacklisters *bl;
4626 struct BlacklistCheck *bc;
4631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4632 "Client disconnected, cleaning up.\n");
4634 /* clean up blacklister */
4638 if (bl->client == client)
4643 if (bc->bl_pos == bl)
4645 bc->bl_pos = bl->next;
4648 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
4651 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
4652 bc->task = GNUNET_SCHEDULER_add_now (sched,
4653 &do_blacklist_check,
4659 GNUNET_CONTAINER_DLL_remove (bl_head,
4662 GNUNET_SERVER_client_drop (bl->client);
4668 /* clean up 'normal' clients */
4671 while ((pos != NULL) && (pos->client != client))
4678 while (NULL != (mqe = pos->message_queue_head))
4680 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4681 pos->message_queue_tail,
4683 pos->message_count--;
4687 clients = pos->next;
4689 prev->next = pos->next;
4690 if (GNUNET_YES == pos->tcs_pending)
4695 if (pos->th != NULL)
4697 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4700 GNUNET_break (0 == pos->message_count);
4706 * Iterator to free entries in the validation_map.
4708 * @param cls closure (unused)
4709 * @param key current key code
4710 * @param value value in the hash map (validation to abort)
4711 * @return GNUNET_YES (always)
4714 abort_validation (void *cls,
4715 const GNUNET_HashCode * key,
4718 struct ValidationEntry *va = value;
4720 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
4721 GNUNET_free (va->transport_name);
4728 * Function called when the service shuts down. Unloads our plugins
4729 * and cancels pending validations.
4731 * @param cls closure, unused
4732 * @param tc task context (unused)
4735 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4737 struct TransportPlugin *plug;
4738 struct OwnAddressList *al;
4739 struct CheckHelloValidatedContext *chvc;
4741 while (neighbours != NULL)
4742 disconnect_neighbour (neighbours, GNUNET_NO);
4744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4745 "Transport service is unloading plugins...\n");
4747 while (NULL != (plug = plugins))
4749 plugins = plug->next;
4750 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4752 GNUNET_SCHEDULER_cancel (plug->env.sched,
4753 plug->address_update_task);
4754 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4756 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4757 GNUNET_free (plug->lib_name);
4758 GNUNET_free (plug->short_name);
4759 while (NULL != (al = plug->addresses))
4761 plug->addresses = al->next;
4766 if (my_private_key != NULL)
4767 GNUNET_CRYPTO_rsa_key_free (my_private_key);
4768 GNUNET_free_non_null (our_hello);
4770 /* free 'chvc' data structure */
4771 while (NULL != (chvc = chvc_head))
4773 chvc_head = chvc->next;
4774 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
4779 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4782 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4783 validation_map = NULL;
4786 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4790 /* Can we assume those are gone by now, or do we need to clean up
4792 GNUNET_break (bl_head == NULL);
4793 GNUNET_break (bc_head == NULL);
4798 * Initiate transport service.
4800 * @param cls closure
4801 * @param s scheduler to use
4802 * @param serv the initialized server
4803 * @param c configuration to use
4807 struct GNUNET_SCHEDULER_Handle *s,
4808 struct GNUNET_SERVER_Handle *serv,
4809 const struct GNUNET_CONFIGURATION_Handle *c)
4814 unsigned long long tneigh;
4819 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4820 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4821 /* parse configuration */
4823 GNUNET_CONFIGURATION_get_value_number (c,
4828 GNUNET_CONFIGURATION_get_value_filename (c,
4830 "HOSTKEY", &keyfile)))
4832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4834 ("Transport service is lacking key configuration settings. Exiting.\n"));
4835 GNUNET_SCHEDULER_shutdown (s);
4838 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4841 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4842 validation_map = NULL;
4845 max_connect_per_transport = (uint32_t) tneigh;
4846 peerinfo = GNUNET_PEERINFO_connect (sched, cfg);
4847 if (peerinfo == NULL)
4849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4850 _("Could not access PEERINFO service. Exiting.\n"));
4851 GNUNET_SCHEDULER_shutdown (s);
4854 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4857 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4858 validation_map = NULL;
4859 GNUNET_free (keyfile);
4862 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4863 GNUNET_free (keyfile);
4864 if (my_private_key == NULL)
4866 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4868 ("Transport service could not access hostkey. Exiting.\n"));
4869 GNUNET_SCHEDULER_shutdown (s);
4872 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4875 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4876 validation_map = NULL;
4879 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4880 GNUNET_CRYPTO_hash (&my_public_key,
4881 sizeof (my_public_key), &my_identity.hashPubKey);
4882 /* setup notification */
4884 GNUNET_SERVER_disconnect_notify (server,
4885 &client_disconnect_notification, NULL);
4886 /* load plugins... */
4889 GNUNET_CONFIGURATION_get_value_string (c,
4890 "TRANSPORT", "PLUGINS", &plugs))
4892 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4893 _("Starting transport plugins `%s'\n"), plugs);
4894 pos = strtok (plugs, " ");
4897 start_transport (server, pos);
4899 pos = strtok (NULL, " ");
4901 GNUNET_free (plugs);
4903 GNUNET_SCHEDULER_add_delayed (sched,
4904 GNUNET_TIME_UNIT_FOREVER_REL,
4905 &shutdown_task, NULL);
4910 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4912 /* If we have a blacklist file, read from it */
4913 read_blacklist_file(cfg);
4914 /* process client requests */
4915 GNUNET_SERVER_add_handlers (server, handlers);
4920 * The main function for the transport service.
4922 * @param argc number of arguments from the command line
4923 * @param argv command line arguments
4924 * @return 0 ok, 1 on error
4927 main (int argc, char *const *argv)
4929 a2s (NULL, NULL, 0); /* make compiler happy */
4930 return (GNUNET_OK ==
4931 GNUNET_SERVICE_run (argc,
4934 GNUNET_SERVICE_OPTION_NONE,
4935 &run, NULL)) ? 0 : 1;
4938 /* end of gnunet-service-transport.c */