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
27 * - This code uses 'GNUNET_a2s' for debug printing in many places,
28 * which is technically wrong since it assumes we have IP+Port
29 * (v4/v6) addresses. Once we add transports like http or smtp
30 * this will have to be changed!
31 * - Already wrong with dv.
34 #include "gnunet_client_lib.h"
35 #include "gnunet_container_lib.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_getopt_lib.h"
38 #include "gnunet_hello_lib.h"
39 #include "gnunet_os_lib.h"
40 #include "gnunet_peerinfo_service.h"
41 #include "gnunet_plugin_lib.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_service_lib.h"
44 #include "gnunet_signatures.h"
45 #include "plugin_transport.h"
46 #include "transport.h"
48 #define DEBUG_BLACKLIST GNUNET_YES
50 #define DEBUG_PING_PONG GNUNET_YES
53 * Should we do some additional checks (to validate behavior
56 #define EXTRA_CHECKS GNUNET_YES
59 * How many messages can we have pending for a given client process
60 * before we start to drop incoming messages? We typically should
61 * have only one client and so this would be the primary buffer for
62 * messages, so the number should be chosen rather generously.
64 * The expectation here is that most of the time the queue is large
65 * enough so that a drop is virtually never required.
67 #define MAX_PENDING 128
70 * Size of the per-transport blacklist hash maps.
72 #define TRANSPORT_BLACKLIST_HT_SIZE 16
75 * How often should we try to reconnect to a peer using a particular
76 * transport plugin before giving up? Note that the plugin may be
77 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
79 #define MAX_CONNECT_RETRY 3
82 * Limit on the number of ready-to-run tasks when validating
83 * HELLOs. If more tasks are ready to run, we will drop
84 * HELLOs instead of validating them.
86 #define MAX_HELLO_LOAD 4
89 * How often must a peer violate bandwidth quotas before we start
90 * to simply drop its messages?
92 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
95 * How long until a HELLO verification attempt should time out?
96 * Must be rather small, otherwise a partially successful HELLO
97 * validation (some addresses working) might not be available
98 * before a client's request for a connection fails for good.
99 * Besides, if a single request to an address takes a long time,
100 * then the peer is unlikely worthwhile anyway.
102 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
105 * Priority to use for PONG messages.
107 #define TRANSPORT_PONG_PRIORITY 4
110 * How often do we re-add (cheaper) plugins to our list of plugins
111 * to try for a given connected peer?
113 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
116 * After how long do we expire an address in a HELLO that we just
117 * validated? This value is also used for our own addresses when we
120 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
124 * How long before an existing address expires should we again try to
125 * validate it? Must be (significantly) smaller than
126 * HELLO_ADDRESS_EXPIRATION.
128 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
131 * Maximum frequency for re-evaluating latencies for all transport addresses.
133 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
136 * Maximum frequency for re-evaluating latencies for connected addresses.
138 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
142 * List of addresses of other peers
144 struct ForeignAddressList
147 * This is a linked list.
149 struct ForeignAddressList *next;
152 * Which ready list does this entry belong to.
154 struct ReadyList *ready_list;
157 * How long until we auto-expire this address (unless it is
158 * re-confirmed by the transport)?
160 struct GNUNET_TIME_Absolute expires;
163 * Task used to re-validate addresses, updates latencies and
166 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
179 * Session (or NULL if no valid session currently exists or if the
180 * plugin does not use sessions).
182 struct Session *session;
185 * What was the last latency observed for this address, plugin and peer?
187 struct GNUNET_TIME_Relative latency;
190 * If we did not successfully transmit a message to the given peer
191 * via this connection during the specified time, we should consider
192 * the connection to be dead. This is used in the case that a TCP
193 * transport simply stalls writing to the stream but does not
194 * formerly get a signal that the other peer died.
196 struct GNUNET_TIME_Absolute timeout;
199 * How often have we tried to connect using this plugin? Used to
200 * discriminate against addresses that do not work well.
201 * FIXME: not yet used, but should be!
203 unsigned int connect_attempts;
206 * DV distance to this peer (1 if no DV is used).
207 * FIXME: need to set this from transport plugins!
212 * Have we ever estimated the latency of this address? Used to
213 * ensure that the first time we add an address, we immediately
219 * Are we currently connected via this address? The first time we
220 * successfully transmit or receive data to a peer via a particular
221 * address, we set this to GNUNET_YES. If we later get an error
222 * (disconnect notification, transmission failure, timeout), we set
223 * it back to GNUNET_NO.
228 * Is this plugin currently busy transmitting to the specific target?
229 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
230 * messages do not count as 'in transmit'.
235 * Has this address been validated yet?
243 * Entry in linked list of network addresses for ourselves.
245 struct OwnAddressList
248 * This is a linked list.
250 struct OwnAddressList *next;
253 * The address, actually a pointer to the end
254 * of this struct. Do not free!
259 * How long until we auto-expire this address (unless it is
260 * re-confirmed by the transport)?
262 struct GNUNET_TIME_Absolute expires;
273 * Entry in linked list of all of our plugins.
275 struct TransportPlugin
279 * This is a linked list.
281 struct TransportPlugin *next;
284 * API of the transport as returned by the plugin's
285 * initialization function.
287 struct GNUNET_TRANSPORT_PluginFunctions *api;
290 * Short name for the plugin (i.e. "tcp").
295 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
300 * List of our known addresses for this transport.
302 struct OwnAddressList *addresses;
305 * Environment this transport service is using
308 struct GNUNET_TRANSPORT_PluginEnvironment env;
311 * ID of task that is used to clean up expired addresses.
313 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
316 * Set to GNUNET_YES if we need to scrap the existing list of
317 * "addresses" and start fresh when we receive the next address
318 * update from a transport. Set to GNUNET_NO if we should just add
319 * the new address to the list and wait for the commit call.
324 * Hashmap of blacklisted peers for this particular transport.
326 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
329 struct NeighbourList;
332 * For each neighbour we keep a list of messages
333 * that we still want to transmit to the neighbour.
339 * This is a doubly linked list.
341 struct MessageQueue *next;
344 * This is a doubly linked list.
346 struct MessageQueue *prev;
349 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
350 * stuck together in memory. Allocated at the end of this struct.
352 const char *message_buf;
355 * Size of the message buf
357 size_t message_buf_size;
360 * Client responsible for queueing the message;
361 * used to check that a client has no two messages
362 * pending for the same target. Can be NULL.
364 struct TransportClient *client;
367 * Using which specific address should we send this message?
369 struct ForeignAddressList *specific_address;
372 * Peer ID of the Neighbour this entry belongs to.
374 struct GNUNET_PeerIdentity neighbour_id;
377 * Plugin that we used for the transmission.
378 * NULL until we scheduled a transmission.
380 struct TransportPlugin *plugin;
383 * At what time should we fail?
385 struct GNUNET_TIME_Absolute timeout;
388 * Internal message of the transport system that should not be
389 * included in the usual SEND-SEND_OK transmission confirmation
390 * traffic management scheme. Typically, "internal_msg" will
391 * be set whenever "client" is NULL (but it is not strictly
397 * How important is the message?
399 unsigned int priority;
405 * For a given Neighbour, which plugins are available
406 * to talk to this peer and what are their costs?
411 * This is a linked list.
413 struct ReadyList *next;
416 * Which of our transport plugins does this entry
419 struct TransportPlugin *plugin;
422 * Transport addresses, latency, and readiness for
423 * this particular plugin.
425 struct ForeignAddressList *addresses;
428 * To which neighbour does this ready list belong to?
430 struct NeighbourList *neighbour;
436 * Entry in linked list of all of our current neighbours.
442 * This is a linked list.
444 struct NeighbourList *next;
447 * Which of our transports is connected to this peer
448 * and what is their status?
450 struct ReadyList *plugins;
453 * Head of list of messages we would like to send to this peer;
454 * must contain at most one message per client.
456 struct MessageQueue *messages_head;
459 * Tail of list of messages we would like to send to this peer; must
460 * contain at most one message per client.
462 struct MessageQueue *messages_tail;
465 * Buffer for at most one payload message used when we receive
466 * payload data before our PING-PONG has succeeded. We then
467 * store such messages in this intermediary buffer until the
468 * connection is fully up.
470 struct GNUNET_MessageHeader *pre_connect_message_buffer;
473 * Context for peerinfo iteration.
474 * NULL after we are done processing peerinfo's information.
476 struct GNUNET_PEERINFO_IteratorContext *piter;
479 * Public key for this peer. Valid only if the respective flag is set below.
481 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
484 * Identity of this neighbour.
486 struct GNUNET_PeerIdentity id;
489 * ID of task scheduled to run when this peer is about to
490 * time out (will free resources associated with the peer).
492 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
495 * ID of task scheduled to run when we should retry transmitting
496 * the head of the message queue. Actually triggered when the
497 * transmission is timing out (we trigger instantly when we have
498 * a chance of success).
500 GNUNET_SCHEDULER_TaskIdentifier retry_task;
503 * How long until we should consider this peer dead
504 * (if we don't receive another message in the
507 struct GNUNET_TIME_Absolute peer_timeout;
510 * Tracker for inbound bandwidth.
512 struct GNUNET_BANDWIDTH_Tracker in_tracker;
515 * The latency we have seen for this particular address for
516 * this particular peer. This latency may have been calculated
517 * over multiple transports. This value reflects how long it took
518 * us to receive a response when SENDING via this particular
519 * transport/neighbour/address combination!
521 * FIXME: we need to periodically send PINGs to update this
522 * latency (at least more often than the current "huge" (11h?)
525 struct GNUNET_TIME_Relative latency;
528 * How often has the other peer (recently) violated the
529 * inbound traffic limit? Incremented by 10 per violation,
530 * decremented by 1 per non-violation (for each
533 unsigned int quota_violation_count;
536 * DV distance to this peer (1 if no DV is used).
541 * Have we seen an PONG from this neighbour in the past (and
542 * not had a disconnect since)?
547 * Do we have a valid public key for this neighbour?
549 int public_key_valid;
554 * Message used to ask a peer to validate receipt (to check an address
557 struct TransportPingMessage
561 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
563 struct GNUNET_MessageHeader header;
566 * Random challenge number (in network byte order).
568 uint32_t challenge GNUNET_PACKED;
571 * Who is the intended recipient?
573 struct GNUNET_PeerIdentity target;
579 * Message used to validate a HELLO. The challenge is included in the
580 * confirmation to make matching of replies to requests possible. The
581 * signature signs the original challenge number, our public key, the
582 * sender's address (so that the sender can check that the address we
583 * saw is plausible for him and possibly detect a MiM attack) and a
584 * timestamp (to limit replay).<p>
586 * This message is followed by the address of the
587 * client that we are observing (which is part of what
590 struct TransportPongMessage
594 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
596 struct GNUNET_MessageHeader header;
599 * For padding, always zero.
601 uint32_t reserved GNUNET_PACKED;
606 struct GNUNET_CRYPTO_RsaSignature signature;
609 * What are we signing and why?
611 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
614 * Random challenge number (in network byte order).
616 uint32_t challenge GNUNET_PACKED;
619 * Who signed this message?
621 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
624 * Size of address appended to this message
632 * Linked list of messages to be transmitted to the client. Each
633 * entry is followed by the actual message.
635 struct ClientMessageQueueEntry
638 * This is a doubly-linked list.
640 struct ClientMessageQueueEntry *next;
643 * This is a doubly-linked list.
645 struct ClientMessageQueueEntry *prev;
650 * Client connected to the transport service.
652 struct TransportClient
656 * This is a linked list.
658 struct TransportClient *next;
661 * Handle to the client.
663 struct GNUNET_SERVER_Client *client;
666 * Linked list of messages yet to be transmitted to
669 struct ClientMessageQueueEntry *message_queue_head;
672 * Tail of linked list of messages yet to be transmitted to the
675 struct ClientMessageQueueEntry *message_queue_tail;
678 * Current transmit request handle.
680 struct GNUNET_CONNECTION_TransmitHandle *th;
683 * Is a call to "transmit_send_continuation" pending? If so, we
684 * must not free this struct (even if the corresponding client
685 * disconnects) and instead only remove it from the linked list and
686 * set the "client" field to NULL.
691 * Length of the list of messages pending for this client.
693 unsigned int message_count;
699 * Entry in map of all HELLOs awaiting validation.
701 struct ValidationEntry
705 * The address, actually a pointer to the end
706 * of this struct. Do not free!
711 * Name of the transport.
713 char *transport_name;
716 * The public key of the peer.
718 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
721 * ID of task that will clean up this entry if we don't succeed
722 * with the validation first.
724 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
727 * At what time did we send this validation?
729 struct GNUNET_TIME_Absolute send_time;
732 * Session being validated (or NULL for none).
734 struct Session *session;
742 * Challenge number we used.
750 * Context of currently active requests to peerinfo
751 * for validation of HELLOs.
753 struct CheckHelloValidatedContext
757 * This is a doubly-linked list.
759 struct CheckHelloValidatedContext *next;
762 * This is a doubly-linked list.
764 struct CheckHelloValidatedContext *prev;
767 * Hello that we are validating.
769 const struct GNUNET_HELLO_Message *hello;
772 * Context for peerinfo iteration.
773 * NULL after we are done processing peerinfo's information.
775 struct GNUNET_PEERINFO_IteratorContext *piter;
778 * Was a HELLO known for this peer to peerinfo?
789 static struct GNUNET_HELLO_Message *our_hello;
792 * "version" of "our_hello". Used to see if a given neighbour has
793 * already been sent the latest version of our HELLO message.
795 static unsigned int our_hello_version;
800 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
805 static struct GNUNET_PeerIdentity my_identity;
810 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
815 struct GNUNET_SCHEDULER_Handle *sched;
820 const struct GNUNET_CONFIGURATION_Handle *cfg;
823 * Linked list of all clients to this service.
825 static struct TransportClient *clients;
828 * All loaded plugins.
830 static struct TransportPlugin *plugins;
835 static struct GNUNET_SERVER_Handle *server;
838 * Handle to peerinfo service.
840 static struct GNUNET_PEERINFO_Handle *peerinfo;
843 * All known neighbours and their HELLOs.
845 static struct NeighbourList *neighbours;
848 * Number of neighbours we'd like to have.
850 static uint32_t max_connect_per_transport;
853 * Head of linked list.
855 static struct CheckHelloValidatedContext *chvc_head;
858 * Tail of linked list.
860 static struct CheckHelloValidatedContext *chvc_tail;
863 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
864 * of the given peer that we are currently validating).
866 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
869 * Handle for reporting statistics.
871 static struct GNUNET_STATISTICS_Handle *stats;
875 * The peer specified by the given neighbour has timed-out or a plugin
876 * has disconnected. We may either need to do nothing (other plugins
877 * still up), or trigger a full disconnect and clean up. This
878 * function updates our state and do the necessary notifications.
879 * Also notifies our clients that the neighbour is now officially
882 * @param n the neighbour list entry for the peer
883 * @param check should we just check if all plugins
884 * disconnected or must we ask all plugins to
887 static void disconnect_neighbour (struct NeighbourList *n, int check);
890 * Check the ready list for the given neighbour and if a plugin is
891 * ready for transmission (and if we have a message), do so!
893 * @param neighbour target peer for which to transmit
895 static void try_transmission_to_peer (struct NeighbourList *neighbour);
899 * Find an entry in the neighbour list for a particular peer.
901 * @return NULL if not found.
903 static struct NeighbourList *
904 find_neighbour (const struct GNUNET_PeerIdentity *key)
906 struct NeighbourList *head = neighbours;
908 while ((head != NULL) &&
909 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
916 * Find an entry in the transport list for a particular transport.
918 * @return NULL if not found.
920 static struct TransportPlugin *
921 find_transport (const char *short_name)
923 struct TransportPlugin *head = plugins;
924 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
930 * Is a particular peer blacklisted for a particular transport?
932 * @param peer the peer to check for
933 * @param plugin the plugin used to connect to the peer
935 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
938 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
941 if (plugin->blacklist != NULL)
943 if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
946 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
947 _("Peer `%s:%s' is blacklisted!\n"),
948 plugin->short_name, GNUNET_i2s (peer));
959 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
961 struct TransportPlugin *plugin;
963 plugin = find_transport(transport_name);
964 if (plugin == NULL) /* Nothing to do */
966 if (plugin->blacklist == NULL)
967 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
968 GNUNET_assert(plugin->blacklist != NULL);
969 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
971 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
976 * Read the blacklist file, containing transport:peer entries.
977 * Provided the transport is loaded, set up hashmap with these
978 * entries to blacklist peers by transport.
982 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
989 struct GNUNET_PeerIdentity pid;
991 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
992 unsigned int entries_found;
993 char *transport_name;
996 GNUNET_CONFIGURATION_get_value_filename (cfg,
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 _("Option `%s' in section `%s' not specified!\n"),
1007 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1008 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1009 | GNUNET_DISK_PERM_USER_WRITE);
1010 if (0 != STAT (fn, &frstat))
1012 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1013 _("Could not read blacklist file `%s'\n"), fn);
1017 if (frstat.st_size == 0)
1019 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1020 _("Blacklist file `%s' is empty.\n"),
1025 /* FIXME: use mmap */
1026 data = GNUNET_malloc_large (frstat.st_size);
1027 if (frstat.st_size !=
1028 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1030 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1031 _("Failed to read blacklist from `%s'\n"), fn);
1038 while ((pos < frstat.st_size) && isspace (data[pos]))
1040 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1041 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1044 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace (data[colon_pos]))
1047 if (colon_pos >= frstat.st_size)
1049 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1050 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1051 (unsigned long long) colon_pos);
1057 if (isspace(data[colon_pos]))
1059 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1060 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1061 (unsigned long long) colon_pos);
1063 while ((pos < frstat.st_size) && isspace (data[pos]))
1067 tsize = colon_pos - pos;
1068 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size))
1070 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1071 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1072 (unsigned long long) colon_pos);
1078 transport_name = GNUNET_malloc(tsize);
1079 memcpy(transport_name, &data[pos], tsize);
1080 pos = colon_pos + 1;
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084 _("Read transport name %s in blacklist file.\n"),
1087 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1088 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1090 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1091 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1092 (unsigned long long) pos);
1094 while ((pos < frstat.st_size) && (!isspace (data[pos])))
1096 GNUNET_free_non_null(transport_name);
1099 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1100 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1102 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1103 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1104 (unsigned long long) pos,
1109 if (0 != memcmp (&pid,
1111 sizeof (struct GNUNET_PeerIdentity)))
1114 add_peer_to_blacklist (&pid,
1116 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1117 _("Found blacklisted peer `%s:%s' in configuration\n"),
1118 transport_name, GNUNET_i2s (&pid));
1122 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1123 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1127 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1128 GNUNET_free_non_null(transport_name);
1129 while ((pos < frstat.st_size) && isspace (data[pos]))
1138 * Function called to notify a client about the socket being ready to
1139 * queue more data. "buf" will be NULL and "size" zero if the socket
1140 * was closed for writing in the meantime.
1142 * @param cls closure
1143 * @param size number of bytes available in buf
1144 * @param buf where the callee should write the message
1145 * @return number of bytes written to buf
1148 transmit_to_client_callback (void *cls, size_t size, void *buf)
1150 struct TransportClient *client = cls;
1151 struct ClientMessageQueueEntry *q;
1154 const struct GNUNET_MessageHeader *msg;
1160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1161 "Transmission to client failed, closing connection.\n");
1162 /* fatal error with client, free message queue! */
1163 while (NULL != (q = client->message_queue_head))
1165 GNUNET_STATISTICS_update (stats,
1166 gettext_noop ("# bytes discarded (could not transmit to client)"),
1167 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1169 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1170 client->message_queue_tail,
1174 client->message_count = 0;
1179 while (NULL != (q = client->message_queue_head))
1181 msg = (const struct GNUNET_MessageHeader *) &q[1];
1182 msize = ntohs (msg->size);
1183 if (msize + tsize > size)
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Transmitting message of type %u to client.\n",
1190 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1191 client->message_queue_tail,
1193 memcpy (&cbuf[tsize], msg, msize);
1196 client->message_count--;
1200 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1201 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1203 GNUNET_TIME_UNIT_FOREVER_REL,
1204 &transmit_to_client_callback,
1206 GNUNET_assert (client->th != NULL);
1213 * Mark the given FAL entry as 'connected' (and hence preferred for
1214 * sending); also mark all others for the same peer as 'not connected'
1215 * (since only one can be preferred).
1217 * @param fal address to set to 'connected'
1220 mark_address_connected (struct ForeignAddressList *fal)
1222 struct ForeignAddressList *pos;
1225 GNUNET_assert (GNUNET_YES == fal->validated);
1226 if (fal->connected == GNUNET_YES)
1227 return; /* nothing to do */
1229 pos = fal->ready_list->addresses;
1232 if (GNUNET_YES == pos->connected)
1234 GNUNET_break (cnt == GNUNET_YES);
1236 pos->connected = GNUNET_NO;
1240 fal->connected = GNUNET_YES;
1241 if (GNUNET_YES == cnt)
1243 GNUNET_STATISTICS_update (stats,
1244 gettext_noop ("# connected addresses"),
1252 * Send the specified message to the specified client. Since multiple
1253 * messages may be pending for the same client at a time, this code
1254 * makes sure that no message is lost.
1256 * @param client client to transmit the message to
1257 * @param msg the message to send
1258 * @param may_drop can this message be dropped if the
1259 * message queue for this client is getting far too large?
1262 transmit_to_client (struct TransportClient *client,
1263 const struct GNUNET_MessageHeader *msg, int may_drop)
1265 struct ClientMessageQueueEntry *q;
1268 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1270 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1272 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1273 client->message_count, MAX_PENDING);
1274 /* TODO: call to statistics... */
1277 msize = ntohs (msg->size);
1278 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1279 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1280 memcpy (&q[1], msg, msize);
1281 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1282 client->message_queue_tail,
1283 client->message_queue_tail,
1285 client->message_count++;
1286 if (client->th == NULL)
1288 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1290 GNUNET_TIME_UNIT_FOREVER_REL,
1291 &transmit_to_client_callback,
1293 GNUNET_assert (client->th != NULL);
1299 * Transmit a 'SEND_OK' notification to the given client for the
1302 * @param client who to notify
1303 * @param n neighbour to notify about
1304 * @param result status code for the transmission request
1307 transmit_send_ok (struct TransportClient *client,
1308 struct NeighbourList *n,
1311 struct SendOkMessage send_ok_msg;
1313 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1314 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1315 send_ok_msg.success = htonl (result);
1316 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1317 send_ok_msg.peer = n->id;
1318 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1323 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1324 * upon "completion" of a send request. This tells the API
1325 * that it is now legal to send another message to the given
1328 * @param cls closure, identifies the entry on the
1329 * message queue that was transmitted and the
1330 * client responsible for queueing the message
1331 * @param target the peer receiving the message
1332 * @param result GNUNET_OK on success, if the transmission
1333 * failed, we should not tell the client to transmit
1337 transmit_send_continuation (void *cls,
1338 const struct GNUNET_PeerIdentity *target,
1341 struct MessageQueue *mq = cls;
1342 struct NeighbourList *n;
1344 GNUNET_STATISTICS_update (stats,
1345 gettext_noop ("# bytes pending with plugins"),
1346 - (int64_t) mq->message_buf_size,
1348 if (result == GNUNET_OK)
1350 GNUNET_STATISTICS_update (stats,
1351 gettext_noop ("# bytes successfully transmitted by plugins"),
1352 mq->message_buf_size,
1357 GNUNET_STATISTICS_update (stats,
1358 gettext_noop ("# bytes with transmission failure by plugins"),
1359 mq->message_buf_size,
1362 n = find_neighbour(&mq->neighbour_id);
1363 GNUNET_assert (n != NULL);
1364 if (mq->specific_address != NULL)
1366 if (result == GNUNET_OK)
1368 mq->specific_address->timeout =
1369 GNUNET_TIME_relative_to_absolute
1370 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1371 if (mq->specific_address->validated == GNUNET_YES)
1372 mark_address_connected (mq->specific_address);
1376 if (mq->specific_address->connected != GNUNET_NO)
1378 GNUNET_STATISTICS_update (stats,
1379 gettext_noop ("# connected addresses"),
1382 mq->specific_address->connected = GNUNET_NO;
1385 if (! mq->internal_msg)
1386 mq->specific_address->in_transmit = GNUNET_NO;
1388 if (mq->client != NULL)
1389 transmit_send_ok (mq->client, n, result);
1391 try_transmission_to_peer (n);
1396 * Convert an address to a string.
1398 * @param plugin name of the plugin responsible for the address
1399 * @param addr binary address
1400 * @param addr_len number of bytes in addr
1401 * @return NULL on error, otherwise address string
1404 a2s (const char *plugin,
1408 struct TransportPlugin *p;
1412 p = find_transport (plugin);
1415 return p->api->address_to_string (p->api->cls,
1422 * Find an address in any of the available transports for
1423 * the given neighbour that would be good for message
1424 * transmission. This is essentially the transport selection
1427 * @param neighbour for whom to select an address
1428 * @return selected address, NULL if we have none
1430 struct ForeignAddressList *
1431 find_ready_address(struct NeighbourList *neighbour)
1433 struct ReadyList *head = neighbour->plugins;
1434 struct ForeignAddressList *addresses;
1435 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1436 struct ForeignAddressList *best_address;
1438 best_address = NULL;
1439 while (head != NULL)
1441 addresses = head->addresses;
1442 while (addresses != NULL)
1444 if ( (addresses->timeout.value < now.value) &&
1445 (addresses->connected == GNUNET_YES) )
1448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1449 "Marking long-time inactive connection to `%4s' as down.\n",
1450 GNUNET_i2s (&neighbour->id));
1452 GNUNET_STATISTICS_update (stats,
1453 gettext_noop ("# connected addresses"),
1456 addresses->connected = GNUNET_NO;
1458 addresses = addresses->next;
1461 addresses = head->addresses;
1462 while (addresses != NULL)
1464 #if DEBUG_TRANSPORT > 1
1465 if (addresses->addr != NULL)
1466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1467 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1468 a2s (head->plugin->short_name,
1470 addresses->addrlen),
1471 GNUNET_i2s (&neighbour->id),
1472 addresses->connected,
1473 addresses->in_transmit,
1474 addresses->validated,
1475 addresses->connect_attempts,
1476 (unsigned long long) addresses->timeout.value,
1477 (unsigned int) addresses->distance);
1479 if ( ( (best_address == NULL) ||
1480 (addresses->connected == GNUNET_YES) ||
1481 (best_address->connected == GNUNET_NO) ) &&
1482 (addresses->in_transmit == GNUNET_NO) &&
1483 ( (best_address == NULL) ||
1484 (addresses->latency.value < best_address->latency.value)) )
1485 best_address = addresses;
1486 /* FIXME: also give lower-latency addresses that are not
1487 connected a chance some times... */
1488 addresses = addresses->next;
1492 if (best_address != NULL)
1495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1496 "Best address found has latency of %llu ms.\n",
1497 best_address->latency.value);
1502 GNUNET_STATISTICS_update (stats,
1503 gettext_noop ("# transmission attempts failed (no address)"),
1507 return best_address;
1513 * We should re-try transmitting to the given peer,
1514 * hopefully we've learned something in the meantime.
1517 retry_transmission_task (void *cls,
1518 const struct GNUNET_SCHEDULER_TaskContext *tc)
1520 struct NeighbourList *n = cls;
1522 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1523 try_transmission_to_peer (n);
1528 * Check the ready list for the given neighbour and if a plugin is
1529 * ready for transmission (and if we have a message), do so!
1531 * @param neighbour target peer for which to transmit
1534 try_transmission_to_peer (struct NeighbourList *neighbour)
1536 struct ReadyList *rl;
1537 struct MessageQueue *mq;
1538 struct GNUNET_TIME_Relative timeout;
1542 if (neighbour->messages_head == NULL)
1545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1546 "Transmission queue for `%4s' is empty\n",
1547 GNUNET_i2s (&neighbour->id));
1549 return; /* nothing to do */
1552 mq = neighbour->messages_head;
1553 force_address = GNUNET_YES;
1554 if (mq->specific_address == NULL)
1556 mq->specific_address = find_ready_address(neighbour);
1557 GNUNET_STATISTICS_update (stats,
1558 gettext_noop ("# transport selected peer address freely"),
1561 force_address = GNUNET_NO;
1563 if (mq->specific_address == NULL)
1565 GNUNET_STATISTICS_update (stats,
1566 gettext_noop ("# transport failed to selected peer address"),
1569 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1570 if (timeout.value == 0)
1573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574 "No destination address available to transmit message of size %u to peer `%4s'\n",
1575 mq->message_buf_size,
1576 GNUNET_i2s (&mq->neighbour_id));
1578 GNUNET_STATISTICS_update (stats,
1579 gettext_noop ("# bytes in message queue for other peers"),
1580 - (int64_t) mq->message_buf_size,
1582 GNUNET_STATISTICS_update (stats,
1583 gettext_noop ("# bytes discarded (no destination address available)"),
1584 mq->message_buf_size,
1586 if (mq->client != NULL)
1587 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1588 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1589 neighbour->messages_tail,
1592 return; /* nobody ready */
1594 GNUNET_STATISTICS_update (stats,
1595 gettext_noop ("# message delivery deferred (no address)"),
1598 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1599 GNUNET_SCHEDULER_cancel (sched,
1600 neighbour->retry_task);
1601 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1603 &retry_transmission_task,
1606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1607 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1608 mq->message_buf_size,
1609 GNUNET_i2s (&mq->neighbour_id),
1612 /* FIXME: might want to trigger peerinfo lookup here
1613 (unless that's already pending...) */
1616 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1617 neighbour->messages_tail,
1619 if (mq->specific_address->connected == GNUNET_NO)
1620 mq->specific_address->connect_attempts++;
1621 rl = mq->specific_address->ready_list;
1622 mq->plugin = rl->plugin;
1623 if (!mq->internal_msg)
1624 mq->specific_address->in_transmit = GNUNET_YES;
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1628 mq->message_buf_size,
1629 GNUNET_i2s (&neighbour->id),
1630 (mq->specific_address->addr != NULL)
1631 ? a2s (mq->specific_address->plugin->short_name,
1632 mq->specific_address->addr,
1633 mq->specific_address->addrlen)
1635 rl->plugin->short_name);
1637 GNUNET_STATISTICS_update (stats,
1638 gettext_noop ("# bytes in message queue for other peers"),
1639 - (int64_t) mq->message_buf_size,
1641 GNUNET_STATISTICS_update (stats,
1642 gettext_noop ("# bytes pending with plugins"),
1643 mq->message_buf_size,
1645 ret = rl->plugin->api->send (rl->plugin->api->cls,
1648 mq->message_buf_size,
1650 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1651 mq->specific_address->session,
1652 mq->specific_address->addr,
1653 mq->specific_address->addrlen,
1655 &transmit_send_continuation, mq);
1658 /* failure, but 'send' would not call continuation in this case,
1659 so we need to do it here! */
1660 transmit_send_continuation (mq,
1668 * Send the specified message to the specified peer.
1670 * @param client source of the transmission request (can be NULL)
1671 * @param peer_address ForeignAddressList where we should send this message
1672 * @param priority how important is the message
1673 * @param timeout how long do we have to transmit?
1674 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1675 * @param message_buf_size total size of all messages in message_buf
1676 * @param is_internal is this an internal message; these are pre-pended and
1677 * also do not count for plugins being "ready" to transmit
1678 * @param neighbour handle to the neighbour for transmission
1681 transmit_to_peer (struct TransportClient *client,
1682 struct ForeignAddressList *peer_address,
1683 unsigned int priority,
1684 struct GNUNET_TIME_Relative timeout,
1685 const char *message_buf,
1686 size_t message_buf_size,
1687 int is_internal, struct NeighbourList *neighbour)
1689 struct MessageQueue *mq;
1694 /* check for duplicate submission */
1695 mq = neighbour->messages_head;
1698 if (mq->client == client)
1700 /* client transmitted to same peer twice
1701 before getting SEND_OK! */
1709 GNUNET_STATISTICS_update (stats,
1710 gettext_noop ("# bytes in message queue for other peers"),
1713 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1714 mq->specific_address = peer_address;
1715 mq->client = client;
1716 memcpy (&mq[1], message_buf, message_buf_size);
1717 mq->message_buf = (const char*) &mq[1];
1718 mq->message_buf_size = message_buf_size;
1719 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1720 mq->internal_msg = is_internal;
1721 mq->priority = priority;
1722 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1724 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1725 neighbour->messages_tail,
1728 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1729 neighbour->messages_tail,
1730 neighbour->messages_tail,
1732 try_transmission_to_peer (neighbour);
1739 struct GeneratorContext
1741 struct TransportPlugin *plug_pos;
1742 struct OwnAddressList *addr_pos;
1743 struct GNUNET_TIME_Absolute expiration;
1751 address_generator (void *cls, size_t max, void *buf)
1753 struct GeneratorContext *gc = cls;
1756 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1758 gc->plug_pos = gc->plug_pos->next;
1759 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1761 if (NULL == gc->plug_pos)
1766 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1769 gc->addr_pos->addrlen, buf, max);
1770 gc->addr_pos = gc->addr_pos->next;
1776 * Construct our HELLO message from all of the addresses of
1777 * all of the transports.
1782 struct GNUNET_HELLO_Message *hello;
1783 struct TransportClient *cpos;
1784 struct NeighbourList *npos;
1785 struct GeneratorContext gc;
1787 gc.plug_pos = plugins;
1788 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1789 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1790 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1793 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1795 GNUNET_STATISTICS_update (stats,
1796 gettext_noop ("# refreshed my HELLO"),
1800 while (cpos != NULL)
1802 transmit_to_client (cpos,
1803 (const struct GNUNET_MessageHeader *) hello,
1808 GNUNET_free_non_null (our_hello);
1810 our_hello_version++;
1811 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1813 while (npos != NULL)
1816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1817 "Transmitting updated `%s' to neighbour `%4s'\n",
1818 "HELLO", GNUNET_i2s (&npos->id));
1820 GNUNET_STATISTICS_update (stats,
1821 gettext_noop ("# transmitted my HELLO to other peers"),
1824 transmit_to_peer (NULL, NULL, 0,
1825 HELLO_ADDRESS_EXPIRATION,
1826 (const char *) our_hello,
1827 GNUNET_HELLO_size(our_hello),
1835 * Task used to clean up expired addresses for a plugin.
1837 * @param cls closure
1841 expire_address_task (void *cls,
1842 const struct GNUNET_SCHEDULER_TaskContext *tc);
1846 * Update the list of addresses for this plugin,
1847 * expiring those that are past their expiration date.
1849 * @param plugin addresses of which plugin should be recomputed?
1850 * @param fresh set to GNUNET_YES if a new address was added
1851 * and we need to regenerate the HELLO even if nobody
1855 update_addresses (struct TransportPlugin *plugin, int fresh)
1857 static struct GNUNET_TIME_Absolute last_update;
1858 struct GNUNET_TIME_Relative min_remaining;
1859 struct GNUNET_TIME_Relative remaining;
1860 struct GNUNET_TIME_Absolute now;
1861 struct OwnAddressList *pos;
1862 struct OwnAddressList *prev;
1863 struct OwnAddressList *next;
1866 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1867 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1868 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1869 now = GNUNET_TIME_absolute_get ();
1870 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1871 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1873 pos = plugin->addresses;
1877 if (pos->expires.value < now.value)
1879 expired = GNUNET_YES;
1881 plugin->addresses = pos->next;
1883 prev->next = pos->next;
1888 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1889 if (remaining.value < min_remaining.value)
1890 min_remaining = remaining;
1896 if (expired || fresh)
1901 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1902 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1904 plugin->address_update_task
1905 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1907 &expire_address_task, plugin);
1912 * Task used to clean up expired addresses for a plugin.
1914 * @param cls closure
1918 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1920 struct TransportPlugin *plugin = cls;
1922 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1923 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1924 update_addresses (plugin, GNUNET_NO);
1929 * Iterator over hash map entries that NULLs the session of validation
1930 * entries that match the given session.
1932 * @param cls closure (the 'struct Session*' to match against)
1933 * @param key current key code (peer ID, not used)
1934 * @param value value in the hash map ('struct ValidationEntry*')
1935 * @return GNUNET_YES (we should continue to iterate)
1938 remove_session_validations (void *cls,
1939 const GNUNET_HashCode * key,
1942 struct Session *session = cls;
1943 struct ValidationEntry *ve = value;
1945 if (session == ve->session)
1952 * Function that will be called whenever the plugin internally
1953 * cleans up a session pointer and hence the service needs to
1954 * discard all of those sessions as well. Plugins that do not
1955 * use sessions can simply omit calling this function and always
1956 * use NULL wherever a session pointer is needed.
1958 * @param cls closure
1959 * @param peer which peer was the session for
1960 * @param session which session is being destoyed
1963 plugin_env_session_end (void *cls,
1964 const struct GNUNET_PeerIdentity *peer,
1965 struct Session *session)
1967 struct TransportPlugin *p = cls;
1968 struct NeighbourList *nl;
1969 struct ReadyList *rl;
1970 struct ForeignAddressList *pos;
1971 struct ForeignAddressList *prev;
1973 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1974 &remove_session_validations,
1976 nl = find_neighbour (peer);
1982 if (rl->plugin == p)
1989 pos = rl->addresses;
1990 while ( (pos != NULL) &&
1991 (pos->session != session) )
1998 pos->session = NULL;
1999 if (pos->addrlen != 0)
2002 rl->addresses = pos->next;
2004 prev->next = pos->next;
2005 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2007 GNUNET_SCHEDULER_cancel (sched,
2008 pos->revalidate_task);
2009 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2012 if (nl->received_pong == GNUNET_NO)
2013 return; /* nothing to do */
2014 /* check if we have any validated addresses left */
2015 pos = rl->addresses;
2022 /* no valid addresses left, signal disconnect! */
2023 disconnect_neighbour (nl, GNUNET_NO);
2028 * Function that must be called by each plugin to notify the
2029 * transport service about the addresses under which the transport
2030 * provided by the plugin can be reached.
2032 * @param cls closure
2033 * @param name name of the transport that generated the address
2034 * @param addr one of the addresses of the host, NULL for the last address
2035 * the specific address format depends on the transport
2036 * @param addrlen length of the address
2037 * @param expires when should this address automatically expire?
2040 plugin_env_notify_address (void *cls,
2044 struct GNUNET_TIME_Relative expires)
2046 struct TransportPlugin *p = cls;
2047 struct OwnAddressList *al;
2048 struct GNUNET_TIME_Absolute abex;
2050 GNUNET_assert (addr != NULL);
2051 abex = GNUNET_TIME_relative_to_absolute (expires);
2052 GNUNET_assert (p == find_transport (name));
2056 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2058 if (al->expires.value < abex.value)
2065 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2067 al->next = p->addresses;
2070 al->addrlen = addrlen;
2071 memcpy (&al[1], addr, addrlen);
2072 update_addresses (p, GNUNET_YES);
2077 * Notify all of our clients about a peer connecting.
2080 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2081 struct GNUNET_TIME_Relative latency,
2084 struct ConnectInfoMessage cim;
2085 struct TransportClient *cpos;
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089 "Notifying clients about connection from `%s'\n",
2092 GNUNET_STATISTICS_update (stats,
2093 gettext_noop ("# peers connected"),
2096 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2097 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2098 cim.distance = htonl (distance);
2099 cim.latency = GNUNET_TIME_relative_hton (latency);
2100 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
2102 while (cpos != NULL)
2104 transmit_to_client (cpos, &cim.header, GNUNET_NO);
2111 * Notify all of our clients about a peer disconnecting.
2114 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2116 struct DisconnectInfoMessage dim;
2117 struct TransportClient *cpos;
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Notifying clients about lost connection to `%s'\n",
2124 GNUNET_STATISTICS_update (stats,
2125 gettext_noop ("# peers connected"),
2128 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2129 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2130 dim.reserved = htonl (0);
2131 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2133 while (cpos != NULL)
2135 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2142 * Find a ForeignAddressList entry for the given neighbour
2143 * that matches the given address and transport.
2145 * @param neighbour which peer we care about
2146 * @param tname name of the transport plugin
2147 * @param session session to look for, NULL for 'any'; otherwise
2148 * can be used for the service to "learn" this session ID
2150 * @param addr binary address
2151 * @param addrlen length of addr
2152 * @return NULL if no such entry exists
2154 static struct ForeignAddressList *
2155 find_peer_address(struct NeighbourList *neighbour,
2157 struct Session *session,
2161 struct ReadyList *head;
2162 struct ForeignAddressList *pos;
2164 head = neighbour->plugins;
2165 while (head != NULL)
2167 if (0 == strcmp (tname, head->plugin->short_name))
2173 pos = head->addresses;
2174 while ( (pos != NULL) &&
2175 ( (pos->addrlen != addrlen) ||
2176 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2178 if ( (session != NULL) &&
2179 (pos->session == session) )
2183 if ( (session != NULL) && (pos != NULL) )
2184 pos->session = session; /* learn it! */
2190 * Get the peer address struct for the given neighbour and
2191 * address. If it doesn't yet exist, create it.
2193 * @param neighbour which peer we care about
2194 * @param tname name of the transport plugin
2195 * @param session session of the plugin, or NULL for none
2196 * @param addr binary address
2197 * @param addrlen length of addr
2198 * @return NULL if we do not have a transport plugin for 'tname'
2200 static struct ForeignAddressList *
2201 add_peer_address (struct NeighbourList *neighbour,
2203 struct Session *session,
2207 struct ReadyList *head;
2208 struct ForeignAddressList *ret;
2210 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2213 head = neighbour->plugins;
2215 while (head != NULL)
2217 if (0 == strcmp (tname, head->plugin->short_name))
2223 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2224 ret->session = session;
2227 ret->addr = (const char*) &ret[1];
2228 memcpy (&ret[1], addr, addrlen);
2234 ret->addrlen = addrlen;
2235 ret->expires = GNUNET_TIME_relative_to_absolute
2236 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2237 ret->latency = GNUNET_TIME_relative_get_forever();
2239 ret->timeout = GNUNET_TIME_relative_to_absolute
2240 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2241 ret->ready_list = head;
2242 ret->next = head->addresses;
2243 head->addresses = ret;
2249 * Closure for 'add_validated_address'.
2251 struct AddValidatedAddressContext
2254 * Entry that has been validated.
2256 const struct ValidationEntry *ve;
2259 * Flag set after we have added the address so
2260 * that we terminate the iteration next time.
2267 * Callback function used to fill a buffer of max bytes with a list of
2268 * addresses in the format used by HELLOs. Should use
2269 * "GNUNET_HELLO_add_address" as a helper function.
2271 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2272 * @param max maximum number of bytes that can be written to buf
2273 * @param buf where to write the address information
2274 * @return number of bytes written, 0 to signal the
2275 * end of the iteration.
2278 add_validated_address (void *cls,
2279 size_t max, void *buf)
2281 struct AddValidatedAddressContext *avac = cls;
2282 const struct ValidationEntry *ve = avac->ve;
2284 if (GNUNET_YES == avac->done)
2286 avac->done = GNUNET_YES;
2287 return GNUNET_HELLO_add_address (ve->transport_name,
2288 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2298 * Closure for 'check_address_exists'.
2300 struct CheckAddressExistsClosure
2303 * Address to check for.
2308 * Name of the transport.
2315 struct Session *session;
2323 * Set to GNUNET_YES if the address exists.
2330 * Iterator over hash map entries. Checks if the given
2331 * validation entry is for the same address as what is given
2334 * @param cls the 'struct CheckAddressExistsClosure*'
2335 * @param key current key code (ignored)
2336 * @param value value in the hash map ('struct ValidationEntry')
2337 * @return GNUNET_YES if we should continue to
2338 * iterate (mismatch), GNUNET_NO if not (entry matched)
2341 check_address_exists (void *cls,
2342 const GNUNET_HashCode * key,
2345 struct CheckAddressExistsClosure *caec = cls;
2346 struct ValidationEntry *ve = value;
2348 if ( (0 == strcmp (caec->tname,
2349 ve->transport_name)) &&
2350 (caec->addrlen == ve->addrlen) &&
2351 (0 == memcmp (caec->addr,
2355 caec->exists = GNUNET_YES;
2358 if ( (ve->session != NULL) &&
2359 (caec->session == ve->session) )
2361 caec->exists = GNUNET_YES;
2369 * HELLO validation cleanup task (validation failed).
2371 * @param cls the 'struct ValidationEntry' that failed
2372 * @param tc scheduler context (unused)
2375 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2377 struct ValidationEntry *va = cls;
2378 struct GNUNET_PeerIdentity pid;
2380 GNUNET_STATISTICS_update (stats,
2381 gettext_noop ("# address validation timeouts"),
2384 GNUNET_CRYPTO_hash (&va->publicKey,
2386 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
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,
2440 const void *addr, size_t addrlen)
2442 struct NeighbourList *n = cls;
2443 struct ForeignAddressList *fal;
2446 GNUNET_STATISTICS_update (stats,
2447 gettext_noop ("# valid peer addresses returned by peerinfo"),
2451 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2456 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2457 a2s (tname, addr, addrlen),
2459 GNUNET_i2s (&n->id),
2462 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2465 GNUNET_STATISTICS_update (stats,
2466 gettext_noop ("# previously validated addresses lacking transport"),
2472 fal->expires = GNUNET_TIME_absolute_max (expiration,
2474 schedule_next_ping (fal);
2480 fal->expires = GNUNET_TIME_absolute_max (expiration,
2485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2486 "Failed to add new address for `%4s'\n",
2487 GNUNET_i2s (&n->id));
2490 if (fal->validated == GNUNET_NO)
2492 fal->validated = GNUNET_YES;
2493 GNUNET_STATISTICS_update (stats,
2494 gettext_noop ("# peer addresses considered valid"),
2498 if (try == GNUNET_YES)
2500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2501 "Have new addresses, will try to trigger transmissions.\n");
2502 try_transmission_to_peer (n);
2509 * Add addresses in validated HELLO "h" to the set of addresses
2510 * we have for this peer.
2512 * @param cls closure ('struct NeighbourList*')
2513 * @param peer id of the peer, NULL for last call
2514 * @param h hello message for the peer (can be NULL)
2515 * @param trust amount of trust we have in the peer (not used)
2518 add_hello_for_peer (void *cls,
2519 const struct GNUNET_PeerIdentity *peer,
2520 const struct GNUNET_HELLO_Message *h,
2523 struct NeighbourList *n = cls;
2531 return; /* no HELLO available */
2533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2534 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2538 if (GNUNET_YES != n->public_key_valid)
2540 GNUNET_HELLO_get_key (h, &n->publicKey);
2541 n->public_key_valid = GNUNET_YES;
2543 GNUNET_HELLO_iterate_addresses (h,
2545 &add_to_foreign_address_list,
2551 * Create a fresh entry in our neighbour list for the given peer.
2552 * Will try to transmit our current HELLO to the new neighbour.
2553 * Do not call this function directly, use 'setup_peer_check_blacklist.
2555 * @param peer the peer for which we create the entry
2556 * @param do_hello should we schedule transmitting a HELLO
2557 * @return the new neighbour list entry
2559 static struct NeighbourList *
2560 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2563 struct NeighbourList *n;
2564 struct TransportPlugin *tp;
2565 struct ReadyList *rl;
2567 GNUNET_assert (our_hello != NULL);
2568 GNUNET_STATISTICS_update (stats,
2569 gettext_noop ("# active neighbours"),
2572 n = GNUNET_malloc (sizeof (struct NeighbourList));
2573 n->next = neighbours;
2577 GNUNET_TIME_relative_to_absolute
2578 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2579 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2580 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2581 MAX_BANDWIDTH_CARRY_S);
2585 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2587 rl = GNUNET_malloc (sizeof (struct ReadyList));
2589 rl->next = n->plugins;
2592 rl->addresses = NULL;
2596 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2598 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2599 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2600 &neighbour_timeout_task, n);
2603 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2604 0, GNUNET_TIME_UNIT_FOREVER_REL,
2605 &add_hello_for_peer, n);
2606 transmit_to_peer (NULL, NULL, 0,
2607 HELLO_ADDRESS_EXPIRATION,
2608 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2616 * Function called after we have checked if communicating
2617 * with a given peer is acceptable.
2619 * @param cls closure
2620 * @param n NULL if communication is not acceptable
2622 typedef void (*SetupContinuation)(void *cls,
2623 struct NeighbourList *n);
2627 * Information kept for each client registered to perform
2633 * This is a linked list.
2635 struct Blacklisters *next;
2638 * This is a linked list.
2640 struct Blacklisters *prev;
2643 * Client responsible for this entry.
2645 struct GNUNET_SERVER_Client *client;
2648 * Blacklist check that we're currently performing.
2650 struct BlacklistCheck *bc;
2656 * Head of DLL of blacklisting clients.
2658 static struct Blacklisters *bl_head;
2661 * Tail of DLL of blacklisting clients.
2663 static struct Blacklisters *bl_tail;
2667 * Context we use when performing a blacklist check.
2669 struct BlacklistCheck
2673 * This is a linked list.
2675 struct BlacklistCheck *next;
2678 * This is a linked list.
2680 struct BlacklistCheck *prev;
2683 * Peer being checked.
2685 struct GNUNET_PeerIdentity peer;
2688 * Option for setup neighbour afterwards.
2693 * Continuation to call with the result.
2695 SetupContinuation cont;
2703 * Current transmission request handle for this client, or NULL if no
2704 * request is pending.
2706 struct GNUNET_CONNECTION_TransmitHandle *th;
2709 * Our current position in the blacklisters list.
2711 struct Blacklisters *bl_pos;
2714 * Current task performing the check.
2716 GNUNET_SCHEDULER_TaskIdentifier task;
2721 * Head of DLL of active blacklisting queries.
2723 static struct BlacklistCheck *bc_head;
2726 * Tail of DLL of active blacklisting queries.
2728 static struct BlacklistCheck *bc_tail;
2732 * Perform next action in the blacklist check.
2734 * @param cls the 'struct BlacklistCheck*'
2738 do_blacklist_check (void *cls,
2739 const struct GNUNET_SCHEDULER_TaskContext *tc);
2743 * Transmit blacklist query to the client.
2745 * @param cls the 'struct BlacklistCheck'
2746 * @param size number of bytes allowed
2747 * @param buf where to copy the message
2748 * @return number of bytes copied to buf
2751 transmit_blacklist_message (void *cls,
2755 struct BlacklistCheck *bc = cls;
2756 struct Blacklisters *bl;
2757 struct BlacklistMessage bm;
2762 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
2763 bc->task = GNUNET_SCHEDULER_add_now (sched,
2764 &do_blacklist_check,
2769 bm.header.size = htons (sizeof (struct BlacklistMessage));
2770 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2771 bm.is_allowed = htonl (0);
2773 memcpy (buf, &bm, sizeof (bm));
2774 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
2780 * Perform next action in the blacklist check.
2782 * @param cls the 'struct BlacklistCheck*'
2786 do_blacklist_check (void *cls,
2787 const struct GNUNET_SCHEDULER_TaskContext *tc)
2789 struct BlacklistCheck *bc = cls;
2790 struct Blacklisters *bl;
2792 bc->task = GNUNET_SCHEDULER_NO_TASK;
2796 bc->cont (bc->cont_cls,
2797 setup_new_neighbour (&bc->peer, bc->do_hello));
2804 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
2805 sizeof (struct BlacklistMessage),
2806 GNUNET_TIME_UNIT_FOREVER_REL,
2807 &transmit_blacklist_message,
2814 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
2815 * does not yet exist, check the blacklist. If the blacklist says creating
2816 * one is acceptable, create one and call the continuation; otherwise
2817 * call the continuation with NULL.
2819 * @param peer peer to setup or look up a struct NeighbourList for
2820 * @param do_hello should we also schedule sending our HELLO to the peer
2821 * if this is a new record
2822 * @param cont function to call with the 'struct NeigbhbourList*'
2823 * @param cont_cls closure for cont
2826 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
2828 SetupContinuation cont,
2831 struct NeighbourList *n;
2832 struct BlacklistCheck *bc;
2834 n = find_neighbour(peer);
2840 if (bl_head == NULL)
2843 setup_new_neighbour (peer, do_hello));
2846 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
2847 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2849 bc->do_hello = do_hello;
2851 bc->cont_cls = cont_cls;
2852 bc->bl_pos = bl_head;
2853 bc->task = GNUNET_SCHEDULER_add_now (sched,
2854 &do_blacklist_check,
2860 * Function called with the result of querying a new blacklister about
2861 * it being allowed (or not) to continue to talk to an existing neighbour.
2863 * @param cls the original 'struct NeighbourList'
2864 * @param n NULL if we need to disconnect
2867 confirm_or_drop_neighbour (void *cls,
2868 struct NeighbourList *n)
2870 struct NeighbourList * orig = cls;
2873 disconnect_neighbour (orig, GNUNET_NO);
2878 * Handle a request to start a blacklist.
2880 * @param cls closure (always NULL)
2881 * @param client identification of the client
2882 * @param message the actual message
2885 handle_blacklist_init (void *cls,
2886 struct GNUNET_SERVER_Client *client,
2887 const struct GNUNET_MessageHeader *message)
2889 struct Blacklisters *bl;
2890 struct BlacklistCheck *bc;
2891 struct NeighbourList *n;
2896 if (bl->client == client)
2899 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2904 bl = GNUNET_malloc (sizeof (struct Blacklisters));
2905 bl->client = client;
2906 GNUNET_SERVER_client_keep (client);
2907 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
2908 /* confirm that all existing connections are OK! */
2912 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
2913 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2915 bc->do_hello = GNUNET_NO;
2916 bc->cont = &confirm_or_drop_neighbour;
2919 if (n == neighbours) /* all would wait for the same client, no need to
2920 create more than just the first task right now */
2921 bc->task = GNUNET_SCHEDULER_add_now (sched,
2922 &do_blacklist_check,
2930 * Handle a request to blacklist a peer.
2932 * @param cls closure (always NULL)
2933 * @param client identification of the client
2934 * @param message the actual message
2937 handle_blacklist_reply (void *cls,
2938 struct GNUNET_SERVER_Client *client,
2939 const struct GNUNET_MessageHeader *message)
2941 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
2942 struct Blacklisters *bl;
2943 struct BlacklistCheck *bc;
2946 while ( (bl != NULL) &&
2947 (bl->client != client) )
2951 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2956 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
2958 bc->cont (bc->cont_cls, NULL);
2959 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2964 bc->bl_pos = bc->bl_pos->next;
2965 bc->task = GNUNET_SCHEDULER_add_now (sched,
2966 &do_blacklist_check,
2969 /* check if any other bc's are waiting for this blacklister */
2973 if ( (bc->bl_pos == bl) &&
2974 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
2975 bc->task = GNUNET_SCHEDULER_add_now (sched,
2976 &do_blacklist_check,
2984 * Send periodic PING messages to a give foreign address.
2986 * @param cls our 'struct PeriodicValidationContext*'
2987 * @param tc task context
2990 send_periodic_ping (void *cls,
2991 const struct GNUNET_SCHEDULER_TaskContext *tc)
2993 struct ForeignAddressList *peer_address = cls;
2994 struct TransportPlugin *tp;
2995 struct ValidationEntry *va;
2996 struct NeighbourList *neighbour;
2997 struct TransportPingMessage ping;
2998 struct CheckAddressExistsClosure caec;
3000 uint16_t hello_size;
3003 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3004 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3006 tp = peer_address->ready_list->plugin;
3007 neighbour = peer_address->ready_list->neighbour;
3008 if (GNUNET_YES != neighbour->public_key_valid)
3010 /* no public key yet, try again later */
3011 schedule_next_ping (peer_address);
3014 caec.addr = peer_address->addr;
3015 caec.addrlen = peer_address->addrlen;
3016 caec.tname = tp->short_name;
3017 caec.session = peer_address->session;
3018 caec.exists = GNUNET_NO;
3019 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3020 &check_address_exists,
3022 if (caec.exists == GNUNET_YES)
3024 /* During validation attempts we will likely trigger the other
3025 peer trying to validate our address which in turn will cause
3026 it to send us its HELLO, so we expect to hit this case rather
3027 frequently. Only print something if we are very verbose. */
3028 #if DEBUG_TRANSPORT > 1
3029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3030 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3031 (peer_address->addr != NULL)
3032 ? a2s (peer_address->plugin->short_name,
3034 peer_address->addrlen)
3037 GNUNET_i2s (&neighbour->id));
3039 schedule_next_ping (peer_address);
3042 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3043 va->transport_name = GNUNET_strdup (tp->short_name);
3044 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3046 va->send_time = GNUNET_TIME_absolute_get();
3047 va->session = peer_address->session;
3048 if (peer_address->addr != NULL)
3050 va->addr = (const void*) &va[1];
3051 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3052 va->addrlen = peer_address->addrlen;
3054 memcpy(&va->publicKey,
3055 &neighbour->publicKey,
3056 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3058 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3059 HELLO_VERIFICATION_TIMEOUT,
3060 &timeout_hello_validation,
3062 GNUNET_CONTAINER_multihashmap_put (validation_map,
3063 &neighbour->id.hashPubKey,
3065 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3066 hello_size = GNUNET_HELLO_size(our_hello);
3067 tsize = sizeof(struct TransportPingMessage) + hello_size;
3068 message_buf = GNUNET_malloc(tsize);
3069 ping.challenge = htonl(va->challenge);
3070 ping.header.size = htons(sizeof(struct TransportPingMessage));
3071 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3072 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3073 memcpy(message_buf, our_hello, hello_size);
3074 memcpy(&message_buf[hello_size],
3076 sizeof(struct TransportPingMessage));
3077 #if DEBUG_TRANSPORT_REVALIDATION
3078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3079 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3080 (peer_address->addr != NULL)
3081 ? a2s (peer_address->plugin->short_name,
3083 peer_address->addrlen)
3086 GNUNET_i2s (&neighbour->id),
3087 "HELLO", hello_size,
3088 "PING", sizeof (struct TransportPingMessage));
3090 GNUNET_STATISTICS_update (stats,
3091 gettext_noop ("# PING messages sent for re-validation"),
3094 transmit_to_peer (NULL, peer_address,
3095 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3096 HELLO_VERIFICATION_TIMEOUT,
3098 GNUNET_YES, neighbour);
3099 GNUNET_free(message_buf);
3100 schedule_next_ping (peer_address);
3105 * Schedule the job that will cause us to send a PING to the
3106 * foreign address to evaluate its validity and latency.
3108 * @param fal address to PING
3111 schedule_next_ping (struct ForeignAddressList *fal)
3113 struct GNUNET_TIME_Relative delay;
3115 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3117 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3118 delay.value /= 2; /* do before expiration */
3119 delay = GNUNET_TIME_relative_min (delay,
3120 LATENCY_EVALUATION_MAX_DELAY);
3121 if (GNUNET_YES != fal->estimated)
3123 delay = GNUNET_TIME_UNIT_ZERO;
3124 fal->estimated = GNUNET_YES;
3126 if (GNUNET_YES == fal->connected)
3128 delay = GNUNET_TIME_relative_min (delay,
3129 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3131 /* FIXME: also adjust delay based on how close the last
3132 observed latency is to the latency of the best alternative */
3133 /* bound how fast we can go */
3134 delay = GNUNET_TIME_relative_max (delay,
3135 GNUNET_TIME_UNIT_SECONDS);
3136 /* randomize a bit (to avoid doing all at the same time) */
3137 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3138 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
3140 &send_periodic_ping,
3148 * Function that will be called if we receive some payload
3149 * from another peer.
3151 * @param message the payload
3152 * @param n peer who claimed to be the sender
3155 handle_payload_message (const struct GNUNET_MessageHeader *message,
3156 struct NeighbourList *n)
3158 struct InboundMessage *im;
3159 struct TransportClient *cpos;
3162 msize = ntohs (message->size);
3163 if (n->received_pong == GNUNET_NO)
3165 GNUNET_free_non_null (n->pre_connect_message_buffer);
3166 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3167 memcpy (n->pre_connect_message_buffer, message, msize);
3171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3172 "Received message of type %u from `%4s', sending to all clients.\n",
3173 ntohs (message->type),
3174 GNUNET_i2s (&n->id));
3176 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3179 n->quota_violation_count++;
3181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3183 n->in_tracker.available_bytes_per_s__,
3184 n->quota_violation_count);
3186 /* Discount 32k per violation */
3187 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3192 if (n->quota_violation_count > 0)
3194 /* try to add 32k back */
3195 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3197 n->quota_violation_count--;
3200 GNUNET_STATISTICS_update (stats,
3201 gettext_noop ("# payload received from other peers"),
3204 /* transmit message to all clients */
3205 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3206 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3207 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3208 im->latency = GNUNET_TIME_relative_hton (n->latency);
3210 im->distance = ntohl(n->distance);
3211 memcpy (&im[1], message, msize);
3213 while (cpos != NULL)
3215 transmit_to_client (cpos, &im->header, GNUNET_YES);
3223 * Iterator over hash map entries. Checks if the given validation
3224 * entry is for the same challenge as what is given in the PONG.
3226 * @param cls the 'struct TransportPongMessage*'
3227 * @param key peer identity
3228 * @param value value in the hash map ('struct ValidationEntry')
3229 * @return GNUNET_YES if we should continue to
3230 * iterate (mismatch), GNUNET_NO if not (entry matched)
3233 check_pending_validation (void *cls,
3234 const GNUNET_HashCode * key,
3237 const struct TransportPongMessage *pong = cls;
3238 struct ValidationEntry *ve = value;
3239 struct AddValidatedAddressContext avac;
3240 unsigned int challenge = ntohl(pong->challenge);
3241 struct GNUNET_HELLO_Message *hello;
3242 struct GNUNET_PeerIdentity target;
3243 struct NeighbourList *n;
3244 struct ForeignAddressList *fal;
3245 struct GNUNET_MessageHeader *prem;
3247 if (ve->challenge != challenge)
3250 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
3255 GNUNET_break_op (0);
3260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3261 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3264 ? a2s (ve->transport_name,
3265 (const struct sockaddr *) ve->addr,
3268 ve->transport_name);
3270 GNUNET_STATISTICS_update (stats,
3271 gettext_noop ("# address validation successes"),
3274 /* create the updated HELLO */
3275 GNUNET_CRYPTO_hash (&ve->publicKey,
3276 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3277 &target.hashPubKey);
3278 if (ve->addr != NULL)
3280 avac.done = GNUNET_NO;
3282 hello = GNUNET_HELLO_create (&ve->publicKey,
3283 &add_validated_address,
3285 GNUNET_PEERINFO_add_peer (peerinfo,
3287 GNUNET_free (hello);
3289 n = find_neighbour (&target);
3292 n->publicKey = ve->publicKey;
3293 n->public_key_valid = GNUNET_YES;
3294 fal = add_peer_address (n,
3299 GNUNET_assert (fal != NULL);
3300 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3301 fal->validated = GNUNET_YES;
3302 mark_address_connected (fal);
3303 GNUNET_STATISTICS_update (stats,
3304 gettext_noop ("# peer addresses considered valid"),
3307 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3308 schedule_next_ping (fal);
3309 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
3310 n->latency = fal->latency;
3312 n->latency.value = (fal->latency.value + n->latency.value) / 2;
3314 n->distance = fal->distance;
3315 if (GNUNET_NO == n->received_pong)
3317 n->received_pong = GNUNET_YES;
3318 notify_clients_connect (&target, n->latency, n->distance);
3319 if (NULL != (prem = n->pre_connect_message_buffer))
3321 n->pre_connect_message_buffer = NULL;
3322 handle_payload_message (prem, n);
3326 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3328 GNUNET_SCHEDULER_cancel (sched,
3330 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3331 try_transmission_to_peer (n);
3335 /* clean up validation entry */
3336 GNUNET_assert (GNUNET_YES ==
3337 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3340 GNUNET_SCHEDULER_cancel (sched,
3342 GNUNET_free (ve->transport_name);
3349 * Function that will be called if we receive a validation
3350 * of an address challenge that we transmitted to another
3351 * peer. Note that the validation should only be considered
3352 * acceptable if the challenge matches AND if the sender
3353 * address is at least a plausible address for this peer
3354 * (otherwise we may be seeing a MiM attack).
3356 * @param cls closure
3357 * @param message the pong message
3358 * @param peer who responded to our challenge
3359 * @param sender_address string describing our sender address (as observed
3360 * by the other peer in binary format)
3361 * @param sender_address_len number of bytes in 'sender_address'
3364 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3365 const struct GNUNET_PeerIdentity *peer,
3366 const char *sender_address,
3367 size_t sender_address_len)
3369 #if DEBUG_TRANSPORT > 1
3370 /* we get tons of these that just get discarded, only log
3371 if we are quite verbose */
3372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3373 "Receiving `%s' message from `%4s'.\n", "PONG",
3376 GNUNET_STATISTICS_update (stats,
3377 gettext_noop ("# PONG messages received"),
3380 if (GNUNET_SYSERR !=
3381 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3383 &check_pending_validation,
3386 /* This is *expected* to happen a lot since we send
3387 PONGs to *all* known addresses of the sender of
3388 the PING, so most likely we get multiple PONGs
3389 per PING, and all but the first PONG will end up
3390 here. So really we should not print anything here
3391 unless we want to be very, very verbose... */
3392 #if DEBUG_TRANSPORT > 2
3393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3394 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3406 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3408 * @param cls the 'struct ValidationEntry*'
3409 * @param neighbour neighbour to validate, NULL if validation failed
3412 transmit_hello_and_ping (void *cls,
3413 struct NeighbourList *neighbour)
3415 struct ValidationEntry *va = cls;
3416 struct ForeignAddressList *peer_address;
3417 struct TransportPingMessage ping;
3418 uint16_t hello_size;
3422 if (neighbour == NULL)
3424 /* FIXME: stats... */
3425 GNUNET_free (va->transport_name);
3429 neighbour->publicKey = va->publicKey;
3430 neighbour->public_key_valid = GNUNET_YES;
3431 peer_address = add_peer_address (neighbour,
3432 va->transport_name, NULL,
3433 (const void*) &va[1],
3435 if (peer_address == NULL)
3437 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3438 "Failed to add peer `%4s' for plugin `%s'\n",
3439 GNUNET_i2s (&neighbour->id),
3440 va->transport_name);
3441 GNUNET_free (va->transport_name);
3445 hello_size = GNUNET_HELLO_size(our_hello);
3446 tsize = sizeof(struct TransportPingMessage) + hello_size;
3447 message_buf = GNUNET_malloc(tsize);
3448 ping.challenge = htonl(va->challenge);
3449 ping.header.size = htons(sizeof(struct TransportPingMessage));
3450 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3451 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3452 memcpy(message_buf, our_hello, hello_size);
3453 memcpy(&message_buf[hello_size],
3455 sizeof(struct TransportPingMessage));
3457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3458 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3459 a2s (va->transport_name,
3460 (const void*) &va[1], va->addrlen),
3462 GNUNET_i2s (&neighbour->id),
3463 "HELLO", hello_size,
3464 "PING", sizeof (struct TransportPingMessage));
3466 GNUNET_STATISTICS_update (stats,
3467 gettext_noop ("# PING messages sent for initial validation"),
3470 transmit_to_peer (NULL, peer_address,
3471 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3472 HELLO_VERIFICATION_TIMEOUT,
3474 GNUNET_YES, neighbour);
3475 GNUNET_free(message_buf);
3480 * Check if the given address is already being validated; if not,
3481 * append the given address to the list of entries that are being be
3482 * validated and initiate validation.
3484 * @param cls closure ('struct CheckHelloValidatedContext *')
3485 * @param tname name of the transport
3486 * @param expiration expiration time
3487 * @param addr the address
3488 * @param addrlen length of the address
3489 * @return GNUNET_OK (always)
3492 run_validation (void *cls,
3494 struct GNUNET_TIME_Absolute expiration,
3495 const void *addr, size_t addrlen)
3497 struct CheckHelloValidatedContext *chvc = cls;
3498 struct GNUNET_PeerIdentity id;
3499 struct TransportPlugin *tp;
3500 struct ValidationEntry *va;
3501 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3502 struct CheckAddressExistsClosure caec;
3503 struct OwnAddressList *oal;
3505 GNUNET_assert (addr != NULL);
3506 GNUNET_STATISTICS_update (stats,
3507 gettext_noop ("# peer addresses scheduled for validation"),
3510 tp = find_transport (tname);
3513 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3514 GNUNET_ERROR_TYPE_BULK,
3516 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3518 GNUNET_STATISTICS_update (stats,
3519 gettext_noop ("# peer addresses not validated (plugin not available)"),
3524 /* check if this is one of our own addresses */
3525 oal = tp->addresses;
3528 if ( (oal->addrlen == addrlen) &&
3529 (0 == memcmp (oal->addr,
3533 /* not plausible, this address is equivalent to our own address! */
3534 GNUNET_STATISTICS_update (stats,
3535 gettext_noop ("# peer addresses not validated (loopback)"),
3542 GNUNET_HELLO_get_key (chvc->hello, &pk);
3543 GNUNET_CRYPTO_hash (&pk,
3545 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3548 if (is_blacklisted(&id, tp))
3551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3552 _("Attempted to validate blacklisted peer `%s' using `%s'!\n"), GNUNET_i2s(&id), tname);
3558 caec.addrlen = addrlen;
3559 caec.session = NULL;
3561 caec.exists = GNUNET_NO;
3562 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3563 &check_address_exists,
3565 if (caec.exists == GNUNET_YES)
3567 /* During validation attempts we will likely trigger the other
3568 peer trying to validate our address which in turn will cause
3569 it to send us its HELLO, so we expect to hit this case rather
3570 frequently. Only print something if we are very verbose. */
3571 #if DEBUG_TRANSPORT > 1
3572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3573 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3574 a2s (tname, addr, addrlen),
3578 GNUNET_STATISTICS_update (stats,
3579 gettext_noop ("# peer addresses not validated (in progress)"),
3584 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
3585 va->transport_name = GNUNET_strdup (tname);
3586 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3588 va->send_time = GNUNET_TIME_absolute_get();
3589 va->addr = (const void*) &va[1];
3590 memcpy (&va[1], addr, addrlen);
3591 va->addrlen = addrlen;
3592 GNUNET_HELLO_get_key (chvc->hello,
3594 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3595 HELLO_VERIFICATION_TIMEOUT,
3596 &timeout_hello_validation,
3598 GNUNET_CONTAINER_multihashmap_put (validation_map,
3601 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3602 setup_peer_check_blacklist (&id, GNUNET_NO,
3603 &transmit_hello_and_ping,
3610 * Check if addresses in validated hello "h" overlap with
3611 * those in "chvc->hello" and validate the rest.
3613 * @param cls closure
3614 * @param peer id of the peer, NULL for last call
3615 * @param h hello message for the peer (can be NULL)
3616 * @param trust amount of trust we have in the peer (not used)
3619 check_hello_validated (void *cls,
3620 const struct GNUNET_PeerIdentity *peer,
3621 const struct GNUNET_HELLO_Message *h,
3624 struct CheckHelloValidatedContext *chvc = cls;
3625 struct GNUNET_HELLO_Message *plain_hello;
3626 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3627 struct GNUNET_PeerIdentity target;
3628 struct NeighbourList *n;
3633 GNUNET_CONTAINER_DLL_remove (chvc_head,
3636 if (GNUNET_NO == chvc->hello_known)
3638 /* notify PEERINFO about the peer now, so that we at least
3639 have the public key if some other component needs it */
3640 GNUNET_HELLO_get_key (chvc->hello, &pk);
3641 GNUNET_CRYPTO_hash (&pk,
3642 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3643 &target.hashPubKey);
3644 plain_hello = GNUNET_HELLO_create (&pk,
3647 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
3648 GNUNET_free (plain_hello);
3650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3651 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
3653 GNUNET_i2s (&target));
3655 GNUNET_STATISTICS_update (stats,
3656 gettext_noop ("# new HELLOs requiring full validation"),
3659 GNUNET_HELLO_iterate_addresses (chvc->hello,
3666 GNUNET_STATISTICS_update (stats,
3667 gettext_noop ("# duplicate HELLO (peer known)"),
3677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3678 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
3682 chvc->hello_known = GNUNET_YES;
3683 n = find_neighbour (peer);
3686 GNUNET_HELLO_iterate_addresses (h,
3688 &add_to_foreign_address_list,
3690 try_transmission_to_peer (n);
3694 GNUNET_STATISTICS_update (stats,
3695 gettext_noop ("# no existing neighbour record (validating HELLO)"),
3699 GNUNET_STATISTICS_update (stats,
3700 gettext_noop ("# HELLO validations (update case)"),
3703 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
3705 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
3712 * Process HELLO-message.
3714 * @param plugin transport involved, may be NULL
3715 * @param message the actual message
3716 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
3719 process_hello (struct TransportPlugin *plugin,
3720 const struct GNUNET_MessageHeader *message)
3723 struct GNUNET_PeerIdentity target;
3724 const struct GNUNET_HELLO_Message *hello;
3725 struct CheckHelloValidatedContext *chvc;
3726 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
3728 hsize = ntohs (message->size);
3729 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
3730 (hsize < sizeof (struct GNUNET_MessageHeader)))
3733 return GNUNET_SYSERR;
3735 GNUNET_STATISTICS_update (stats,
3736 gettext_noop ("# HELLOs received for validation"),
3739 /* first, check if load is too high */
3740 if (GNUNET_SCHEDULER_get_load (sched,
3741 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
3743 GNUNET_STATISTICS_update (stats,
3744 gettext_noop ("# HELLOs ignored due to high load"),
3749 hello = (const struct GNUNET_HELLO_Message *) message;
3750 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3752 GNUNET_break_op (0);
3753 return GNUNET_SYSERR;
3755 GNUNET_CRYPTO_hash (&publicKey,
3756 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3757 &target.hashPubKey);
3758 if (0 == memcmp (&my_identity,
3760 sizeof (struct GNUNET_PeerIdentity)))
3762 GNUNET_STATISTICS_update (stats,
3763 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3768 #if DEBUG_TRANSPORT > 1
3769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3770 "Processing `%s' message for `%4s' of size %u\n",
3772 GNUNET_i2s (&target),
3773 GNUNET_HELLO_size(hello));
3775 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3776 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3777 memcpy (&chvc[1], hello, hsize);
3778 GNUNET_CONTAINER_DLL_insert (chvc_head,
3781 /* finally, check if HELLO was previously validated
3782 (continuation will then schedule actual validation) */
3783 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
3786 HELLO_VERIFICATION_TIMEOUT,
3787 &check_hello_validated, chvc);
3793 * The peer specified by the given neighbour has timed-out or a plugin
3794 * has disconnected. We may either need to do nothing (other plugins
3795 * still up), or trigger a full disconnect and clean up. This
3796 * function updates our state and does the necessary notifications.
3797 * Also notifies our clients that the neighbour is now officially
3800 * @param n the neighbour list entry for the peer
3801 * @param check should we just check if all plugins
3802 * disconnected or must we ask all plugins to
3806 disconnect_neighbour (struct NeighbourList *n, int check)
3808 struct ReadyList *rpos;
3809 struct NeighbourList *npos;
3810 struct NeighbourList *nprev;
3811 struct MessageQueue *mq;
3812 struct ForeignAddressList *peer_addresses;
3813 struct ForeignAddressList *peer_pos;
3815 if (GNUNET_YES == check)
3818 while (NULL != rpos)
3820 peer_addresses = rpos->addresses;
3821 while (peer_addresses != NULL)
3823 if (GNUNET_YES == peer_addresses->connected)
3824 return; /* still connected */
3825 peer_addresses = peer_addresses->next;
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3832 "Disconnecting from `%4s'\n",
3833 GNUNET_i2s (&n->id));
3835 /* remove n from neighbours list */
3838 while ((npos != NULL) && (npos != n))
3843 GNUNET_assert (npos != NULL);
3845 neighbours = n->next;
3847 nprev->next = n->next;
3849 /* notify all clients about disconnect */
3850 if (GNUNET_YES == n->received_pong)
3851 notify_clients_disconnect (&n->id);
3853 /* clean up all plugins, cancel connections and pending transmissions */
3854 while (NULL != (rpos = n->plugins))
3856 n->plugins = rpos->next;
3857 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3858 while (rpos->addresses != NULL)
3860 peer_pos = rpos->addresses;
3861 rpos->addresses = peer_pos->next;
3862 if (peer_pos->connected == GNUNET_YES)
3863 GNUNET_STATISTICS_update (stats,
3864 gettext_noop ("# connected addresses"),
3867 if (GNUNET_YES == peer_pos->validated)
3868 GNUNET_STATISTICS_update (stats,
3869 gettext_noop ("# peer addresses considered valid"),
3872 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3874 GNUNET_SCHEDULER_cancel (sched,
3875 peer_pos->revalidate_task);
3876 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3878 GNUNET_free(peer_pos);
3883 /* free all messages on the queue */
3884 while (NULL != (mq = n->messages_head))
3886 GNUNET_STATISTICS_update (stats,
3887 gettext_noop ("# bytes in message queue for other peers"),
3888 - (int64_t) mq->message_buf_size,
3890 GNUNET_STATISTICS_update (stats,
3891 gettext_noop ("# bytes discarded due to disconnect"),
3892 mq->message_buf_size,
3894 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3897 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3899 sizeof(struct GNUNET_PeerIdentity)));
3902 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3904 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3905 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3907 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3909 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3910 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3912 if (n->piter != NULL)
3914 GNUNET_PEERINFO_iterate_cancel (n->piter);
3917 /* finally, free n itself */
3918 GNUNET_STATISTICS_update (stats,
3919 gettext_noop ("# active neighbours"),
3922 GNUNET_free_non_null (n->pre_connect_message_buffer);
3928 * We have received a PING message from someone. Need to send a PONG message
3929 * in response to the peer by any means necessary.
3932 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3933 const struct GNUNET_PeerIdentity *peer,
3934 const char *sender_address,
3935 size_t sender_address_len)
3937 struct TransportPlugin *plugin = cls;
3938 struct TransportPingMessage *ping;
3939 struct TransportPongMessage *pong;
3940 struct NeighbourList *n;
3941 struct ReadyList *rl;
3942 struct ForeignAddressList *fal;
3944 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3946 GNUNET_break_op (0);
3947 return GNUNET_SYSERR;
3950 ping = (struct TransportPingMessage *) message;
3951 if (0 != memcmp (&ping->target,
3952 plugin->env.my_identity,
3953 sizeof (struct GNUNET_PeerIdentity)))
3955 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3956 _("Received `%s' message not destined for me!\n"),
3958 return GNUNET_SYSERR;
3961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3962 "Processing `%s' from `%s'\n",
3964 (sender_address != NULL)
3965 ? a2s (plugin->short_name,
3966 (const struct sockaddr *)sender_address,
3970 GNUNET_STATISTICS_update (stats,
3971 gettext_noop ("# PING messages received"),
3974 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3975 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3976 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3977 pong->purpose.size =
3978 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3980 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3981 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3982 pong->challenge = ping->challenge;
3983 pong->addrlen = htons(sender_address_len);
3984 memcpy(&pong->signer,
3986 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3987 if (sender_address != NULL)
3988 memcpy (&pong[1], sender_address, sender_address_len);
3989 GNUNET_assert (GNUNET_OK ==
3990 GNUNET_CRYPTO_rsa_sign (my_private_key,
3991 &pong->purpose, &pong->signature));
3992 n = find_neighbour(peer);
3993 GNUNET_assert (n != NULL);
3994 /* first try reliable response transmission */
3998 fal = rl->addresses;
4001 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4004 ntohs (pong->header.size),
4005 TRANSPORT_PONG_PRIORITY,
4006 HELLO_VERIFICATION_TIMEOUT,
4014 GNUNET_STATISTICS_update (stats,
4015 gettext_noop ("# PONGs unicast via reliable transport"),
4025 /* no reliable method found, do multicast */
4026 GNUNET_STATISTICS_update (stats,
4027 gettext_noop ("# PONGs multicast to all available addresses"),
4033 fal = rl->addresses;
4036 transmit_to_peer(NULL, fal,
4037 TRANSPORT_PONG_PRIORITY,
4038 HELLO_VERIFICATION_TIMEOUT,
4040 ntohs(pong->header.size),
4053 * Function called by the plugin for each received message.
4054 * Update data volumes, possibly notify plugins about
4055 * reducing the rate at which they read from the socket
4056 * and generally forward to our receive callback.
4058 * @param cls the "struct TransportPlugin *" we gave to the plugin
4059 * @param peer (claimed) identity of the other peer
4060 * @param message the message, NULL if we only care about
4061 * learning about the delay until we should receive again
4062 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
4063 * @param session identifier used for this session (can be NULL)
4064 * @param sender_address binary address of the sender (if observed)
4065 * @param sender_address_len number of bytes in sender_address
4066 * @return how long the plugin should wait until receiving more data
4067 * (plugins that do not support this, can ignore the return value)
4069 static struct GNUNET_TIME_Relative
4070 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4071 const struct GNUNET_MessageHeader *message,
4073 struct Session *session,
4074 const char *sender_address,
4075 size_t sender_address_len)
4077 struct TransportPlugin *plugin = cls;
4078 struct ReadyList *service_context;
4079 struct ForeignAddressList *peer_address;
4081 struct NeighbourList *n;
4082 struct GNUNET_TIME_Relative ret;
4084 if (is_blacklisted (peer, plugin))
4085 return GNUNET_TIME_UNIT_FOREVER_REL;
4087 n = find_neighbour (peer);
4089 n = setup_new_neighbour (peer, GNUNET_YES);
4090 service_context = n->plugins;
4091 while ((service_context != NULL) && (plugin != service_context->plugin))
4092 service_context = service_context->next;
4093 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4094 peer_address = NULL;
4095 if (message != NULL)
4097 if ( (session != NULL) ||
4098 (sender_address != NULL) )
4099 peer_address = add_peer_address (n,
4103 sender_address_len);
4104 if (peer_address != NULL)
4106 peer_address->distance = distance;
4107 if (GNUNET_YES == peer_address->validated)
4108 mark_address_connected (peer_address);
4109 peer_address->timeout
4111 GNUNET_TIME_relative_to_absolute
4112 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4113 schedule_next_ping (peer_address);
4115 /* update traffic received amount ... */
4116 msize = ntohs (message->size);
4117 GNUNET_STATISTICS_update (stats,
4118 gettext_noop ("# bytes received from other peers"),
4121 n->distance = distance;
4123 GNUNET_TIME_relative_to_absolute
4124 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4125 GNUNET_SCHEDULER_cancel (sched,
4128 GNUNET_SCHEDULER_add_delayed (sched,
4129 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4130 &neighbour_timeout_task, n);
4131 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4133 /* dropping message due to frequent inbound volume violations! */
4134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4135 GNUNET_ERROR_TYPE_BULK,
4137 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4138 n->in_tracker.available_bytes_per_s__,
4139 n->quota_violation_count);
4140 GNUNET_STATISTICS_update (stats,
4141 gettext_noop ("# bandwidth quota violations by other peers"),
4144 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4148 "Received message of type %u from `%4s', sending to all clients.\n",
4149 ntohs (message->type), GNUNET_i2s (peer));
4151 switch (ntohs (message->type))
4153 case GNUNET_MESSAGE_TYPE_HELLO:
4154 GNUNET_STATISTICS_update (stats,
4155 gettext_noop ("# HELLO messages received from other peers"),
4158 process_hello (plugin, message);
4160 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4161 handle_ping (plugin, message, peer, sender_address, sender_address_len);
4163 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4164 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4167 handle_payload_message (message, n);
4171 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4174 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4175 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4176 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4177 (unsigned int) n->in_tracker.available_bytes_per_s__,
4178 (unsigned long long) ret.value);
4179 GNUNET_STATISTICS_update (stats,
4180 gettext_noop ("# ms throttling suggested"),
4181 (int64_t) ret.value,
4188 * Handle START-message. This is the first message sent to us
4189 * by any client which causes us to add it to our list.
4191 * @param cls closure (always NULL)
4192 * @param client identification of the client
4193 * @param message the actual message
4196 handle_start (void *cls,
4197 struct GNUNET_SERVER_Client *client,
4198 const struct GNUNET_MessageHeader *message)
4200 struct TransportClient *c;
4201 struct ConnectInfoMessage cim;
4202 struct NeighbourList *n;
4205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4206 "Received `%s' request from client\n", "START");
4211 if (c->client == client)
4213 /* client already on our list! */
4215 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4220 c = GNUNET_malloc (sizeof (struct TransportClient));
4224 if (our_hello != NULL)
4227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4228 "Sending our own `%s' to new client\n", "HELLO");
4230 transmit_to_client (c,
4231 (const struct GNUNET_MessageHeader *) our_hello,
4233 /* tell new client about all existing connections */
4234 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
4235 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4239 if (GNUNET_YES == n->received_pong)
4242 cim.latency = GNUNET_TIME_relative_hton (n->latency);
4243 cim.distance = htonl (n->distance);
4244 transmit_to_client (c, &cim.header, GNUNET_NO);
4249 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4254 * Handle HELLO-message.
4256 * @param cls closure (always NULL)
4257 * @param client identification of the client
4258 * @param message the actual message
4261 handle_hello (void *cls,
4262 struct GNUNET_SERVER_Client *client,
4263 const struct GNUNET_MessageHeader *message)
4267 GNUNET_STATISTICS_update (stats,
4268 gettext_noop ("# HELLOs received from clients"),
4271 ret = process_hello (NULL, message);
4272 GNUNET_SERVER_receive_done (client, ret);
4277 * Closure for 'transmit_client_message'; followed by
4278 * 'msize' bytes of the actual message.
4280 struct TransmitClientMessageContext
4283 * Client on whom's behalf we are sending.
4285 struct GNUNET_SERVER_Client *client;
4288 * Timeout for the transmission.
4290 struct GNUNET_TIME_Absolute timeout;
4298 * Size of the message in bytes.
4305 * Schedule transmission of a message we got from a client to a peer.
4307 * @param cls the 'struct TransmitClientMessageContext*'
4308 * @param n destination, or NULL on error (in that case, drop the message)
4311 transmit_client_message (void *cls,
4312 struct NeighbourList *n)
4314 struct TransmitClientMessageContext *tcmc = cls;
4315 struct TransportClient *tc;
4318 while ((tc != NULL) && (tc->client != tcmc->client))
4323 transmit_to_peer (tc, NULL, tcmc->priority,
4324 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
4326 tcmc->msize, GNUNET_NO, n);
4328 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
4329 GNUNET_SERVER_client_drop (tcmc->client);
4335 * Handle SEND-message.
4337 * @param cls closure (always NULL)
4338 * @param client identification of the client
4339 * @param message the actual message
4342 handle_send (void *cls,
4343 struct GNUNET_SERVER_Client *client,
4344 const struct GNUNET_MessageHeader *message)
4346 const struct OutboundMessage *obm;
4347 const struct GNUNET_MessageHeader *obmm;
4348 struct TransmitClientMessageContext *tcmc;
4352 size = ntohs (message->size);
4354 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
4357 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4360 GNUNET_STATISTICS_update (stats,
4361 gettext_noop ("# payload received for other peers"),
4364 obm = (const struct OutboundMessage *) message;
4365 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4366 msize = ntohs (obmm->size);
4368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4369 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
4370 "SEND", GNUNET_i2s (&obm->peer),
4374 if (size != msize + sizeof (struct OutboundMessage))
4377 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4380 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
4381 tcmc->client = client;
4382 tcmc->priority = ntohl (obm->priority);
4383 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
4384 tcmc->msize = msize;
4385 memcpy (&tcmc[1], obmm, msize);
4386 GNUNET_SERVER_client_keep (client);
4387 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
4388 &transmit_client_message,
4394 * Handle SET_QUOTA-message.
4396 * @param cls closure (always NULL)
4397 * @param client identification of the client
4398 * @param message the actual message
4401 handle_set_quota (void *cls,
4402 struct GNUNET_SERVER_Client *client,
4403 const struct GNUNET_MessageHeader *message)
4405 const struct QuotaSetMessage *qsm =
4406 (const struct QuotaSetMessage *) message;
4407 struct NeighbourList *n;
4409 GNUNET_STATISTICS_update (stats,
4410 gettext_noop ("# SET QUOTA messages received"),
4413 n = find_neighbour (&qsm->peer);
4416 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4417 GNUNET_STATISTICS_update (stats,
4418 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
4424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4425 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
4427 (unsigned int) ntohl (qsm->quota.value__),
4428 (unsigned int) n->in_tracker.available_bytes_per_s__,
4429 GNUNET_i2s (&qsm->peer));
4431 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
4433 if (0 == ntohl (qsm->quota.value__))
4434 disconnect_neighbour (n, GNUNET_NO);
4435 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4440 * Take the given address and append it to the set of results send back to
4443 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
4444 * @param address the resolved name, NULL to indicate the last response
4447 transmit_address_to_client (void *cls, const char *address)
4449 struct GNUNET_SERVER_TransmitContext *tc = cls;
4452 if (NULL == address)
4455 slen = strlen (address) + 1;
4456 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
4457 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4458 if (NULL == address)
4459 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
4464 * Handle AddressLookup-message.
4466 * @param cls closure (always NULL)
4467 * @param client identification of the client
4468 * @param message the actual message
4471 handle_address_lookup (void *cls,
4472 struct GNUNET_SERVER_Client *client,
4473 const struct GNUNET_MessageHeader *message)
4475 const struct AddressLookupMessage *alum;
4476 struct TransportPlugin *lsPlugin;
4477 const char *nameTransport;
4478 const char *address;
4480 struct GNUNET_SERVER_TransmitContext *tc;
4481 struct GNUNET_TIME_Absolute timeout;
4482 struct GNUNET_TIME_Relative rtimeout;
4485 size = ntohs (message->size);
4486 if (size < sizeof (struct AddressLookupMessage))
4488 GNUNET_break_op (0);
4489 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4492 alum = (const struct AddressLookupMessage *) message;
4493 uint32_t addressLen = ntohl (alum->addrlen);
4494 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
4496 GNUNET_break_op (0);
4497 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4500 address = (const char *) &alum[1];
4501 nameTransport = (const char *) &address[addressLen];
4503 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
4505 GNUNET_break_op (0);
4506 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4509 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4510 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4511 numeric = ntohl (alum->numeric_only);
4512 lsPlugin = find_transport (nameTransport);
4513 if (NULL == lsPlugin)
4515 tc = GNUNET_SERVER_transmit_context_create (client);
4516 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4517 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4518 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4521 tc = GNUNET_SERVER_transmit_context_create (client);
4522 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4524 address, addressLen,
4527 &transmit_address_to_client, tc);
4531 * List of handlers for the messages understood by this
4534 static struct GNUNET_SERVER_MessageHandler handlers[] = {
4535 {&handle_start, NULL,
4536 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4537 {&handle_hello, NULL,
4538 GNUNET_MESSAGE_TYPE_HELLO, 0},
4539 {&handle_send, NULL,
4540 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4541 {&handle_set_quota, NULL,
4542 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4543 {&handle_address_lookup, NULL,
4544 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4546 {&handle_blacklist_init, NULL,
4547 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
4548 {&handle_blacklist_reply, NULL,
4549 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
4555 * Setup the environment for this plugin.
4558 create_environment (struct TransportPlugin *plug)
4560 plug->env.cfg = cfg;
4561 plug->env.sched = sched;
4562 plug->env.my_identity = &my_identity;
4563 plug->env.cls = plug;
4564 plug->env.receive = &plugin_env_receive;
4565 plug->env.notify_address = &plugin_env_notify_address;
4566 plug->env.session_end = &plugin_env_session_end;
4567 plug->env.max_connections = max_connect_per_transport;
4568 plug->env.stats = stats;
4573 * Start the specified transport (load the plugin).
4576 start_transport (struct GNUNET_SERVER_Handle *server,
4579 struct TransportPlugin *plug;
4582 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4583 _("Loading `%s' transport plugin\n"), name);
4584 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4585 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4586 create_environment (plug);
4587 plug->short_name = GNUNET_strdup (name);
4588 plug->lib_name = libname;
4589 plug->next = plugins;
4591 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4592 if (plug->api == NULL)
4594 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4595 _("Failed to load transport plugin for `%s'\n"), name);
4596 GNUNET_free (plug->short_name);
4597 plugins = plug->next;
4598 GNUNET_free (libname);
4605 * Called whenever a client is disconnected. Frees our
4606 * resources associated with that client.
4608 * @param cls closure
4609 * @param client identification of the client
4612 client_disconnect_notification (void *cls,
4613 struct GNUNET_SERVER_Client *client)
4615 struct TransportClient *pos;
4616 struct TransportClient *prev;
4617 struct ClientMessageQueueEntry *mqe;
4618 struct Blacklisters *bl;
4619 struct BlacklistCheck *bc;
4624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4625 "Client disconnected, cleaning up.\n");
4627 /* clean up blacklister */
4631 if (bl->client == client)
4636 if (bc->bl_pos == bl)
4638 bc->bl_pos = bl->next;
4641 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
4644 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
4645 bc->task = GNUNET_SCHEDULER_add_now (sched,
4646 &do_blacklist_check,
4652 GNUNET_CONTAINER_DLL_remove (bl_head,
4655 GNUNET_SERVER_client_drop (bl->client);
4661 /* clean up 'normal' clients */
4664 while ((pos != NULL) && (pos->client != client))
4671 while (NULL != (mqe = pos->message_queue_head))
4673 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4674 pos->message_queue_tail,
4676 pos->message_count--;
4680 clients = pos->next;
4682 prev->next = pos->next;
4683 if (GNUNET_YES == pos->tcs_pending)
4688 if (pos->th != NULL)
4690 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4693 GNUNET_break (0 == pos->message_count);
4699 * Iterator to free entries in the validation_map.
4701 * @param cls closure (unused)
4702 * @param key current key code
4703 * @param value value in the hash map (validation to abort)
4704 * @return GNUNET_YES (always)
4707 abort_validation (void *cls,
4708 const GNUNET_HashCode * key,
4711 struct ValidationEntry *va = value;
4713 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
4714 GNUNET_free (va->transport_name);
4721 * Function called when the service shuts down. Unloads our plugins
4722 * and cancels pending validations.
4724 * @param cls closure, unused
4725 * @param tc task context (unused)
4728 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4730 struct TransportPlugin *plug;
4731 struct OwnAddressList *al;
4732 struct CheckHelloValidatedContext *chvc;
4734 while (neighbours != NULL)
4735 disconnect_neighbour (neighbours, GNUNET_NO);
4737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4738 "Transport service is unloading plugins...\n");
4740 while (NULL != (plug = plugins))
4742 plugins = plug->next;
4743 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4745 GNUNET_SCHEDULER_cancel (plug->env.sched,
4746 plug->address_update_task);
4747 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4749 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4750 GNUNET_free (plug->lib_name);
4751 GNUNET_free (plug->short_name);
4752 while (NULL != (al = plug->addresses))
4754 plug->addresses = al->next;
4759 if (my_private_key != NULL)
4760 GNUNET_CRYPTO_rsa_key_free (my_private_key);
4761 GNUNET_free_non_null (our_hello);
4763 /* free 'chvc' data structure */
4764 while (NULL != (chvc = chvc_head))
4766 chvc_head = chvc->next;
4767 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
4772 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4775 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4776 validation_map = NULL;
4779 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4783 /* Can we assume those are gone by now, or do we need to clean up
4785 GNUNET_break (bl_head == NULL);
4786 GNUNET_break (bc_head == NULL);
4791 * Initiate transport service.
4793 * @param cls closure
4794 * @param s scheduler to use
4795 * @param serv the initialized server
4796 * @param c configuration to use
4800 struct GNUNET_SCHEDULER_Handle *s,
4801 struct GNUNET_SERVER_Handle *serv,
4802 const struct GNUNET_CONFIGURATION_Handle *c)
4807 unsigned long long tneigh;
4812 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4813 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4814 /* parse configuration */
4816 GNUNET_CONFIGURATION_get_value_number (c,
4821 GNUNET_CONFIGURATION_get_value_filename (c,
4823 "HOSTKEY", &keyfile)))
4825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4827 ("Transport service is lacking key configuration settings. Exiting.\n"));
4828 GNUNET_SCHEDULER_shutdown (s);
4831 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4834 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4835 validation_map = NULL;
4838 max_connect_per_transport = (uint32_t) tneigh;
4839 peerinfo = GNUNET_PEERINFO_connect (sched, cfg);
4840 if (peerinfo == NULL)
4842 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4843 _("Could not access PEERINFO service. Exiting.\n"));
4844 GNUNET_SCHEDULER_shutdown (s);
4847 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4850 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4851 validation_map = NULL;
4852 GNUNET_free (keyfile);
4855 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4856 GNUNET_free (keyfile);
4857 if (my_private_key == NULL)
4859 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4861 ("Transport service could not access hostkey. Exiting.\n"));
4862 GNUNET_SCHEDULER_shutdown (s);
4865 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4868 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4869 validation_map = NULL;
4872 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4873 GNUNET_CRYPTO_hash (&my_public_key,
4874 sizeof (my_public_key), &my_identity.hashPubKey);
4875 /* setup notification */
4877 GNUNET_SERVER_disconnect_notify (server,
4878 &client_disconnect_notification, NULL);
4879 /* load plugins... */
4882 GNUNET_CONFIGURATION_get_value_string (c,
4883 "TRANSPORT", "PLUGINS", &plugs))
4885 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4886 _("Starting transport plugins `%s'\n"), plugs);
4887 pos = strtok (plugs, " ");
4890 start_transport (server, pos);
4892 pos = strtok (NULL, " ");
4894 GNUNET_free (plugs);
4896 GNUNET_SCHEDULER_add_delayed (sched,
4897 GNUNET_TIME_UNIT_FOREVER_REL,
4898 &shutdown_task, NULL);
4903 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4905 /* If we have a blacklist file, read from it */
4906 read_blacklist_file(cfg);
4907 /* process client requests */
4908 GNUNET_SERVER_add_handlers (server, handlers);
4913 * The main function for the transport service.
4915 * @param argc number of arguments from the command line
4916 * @param argv command line arguments
4917 * @return 0 ok, 1 on error
4920 main (int argc, char *const *argv)
4922 a2s (NULL, NULL, 0); /* make compiler happy */
4923 return (GNUNET_OK ==
4924 GNUNET_SERVICE_run (argc,
4927 GNUNET_SERVICE_OPTION_NONE,
4928 &run, NULL)) ? 0 : 1;
4931 /* end of gnunet-service-transport.c */