2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "gnunet-service-transport_ats.h"
41 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_INBOUND GNUNET_NO
54 * Should we do some additional checks (to validate behavior
57 #define EXTRA_CHECKS GNUNET_YES
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
71 #define MAX_PENDING (128 * 1024)
74 * Size of the per-transport blacklist hash maps.
76 #define TRANSPORT_BLACKLIST_HT_SIZE 16
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
83 #define MAX_CONNECT_RETRY 3
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
90 #define MAX_HELLO_LOAD 4
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
96 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
106 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
115 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
118 * Priority to use for PONG messages.
120 #define TRANSPORT_PONG_PRIORITY 4
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
126 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
133 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
141 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * List of addresses of other peers
146 struct ForeignAddressList
149 * This is a linked list.
151 struct ForeignAddressList *next;
154 * Which ready list does this entry belong to.
156 struct ReadyList *ready_list;
159 * How long until we auto-expire this address (unless it is
160 * re-confirmed by the transport)?
162 struct GNUNET_TIME_Absolute expires;
165 * Task used to re-validate addresses, updates latencies and
168 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176 * Session (or NULL if no valid session currently exists or if the
177 * plugin does not use sessions).
179 struct Session *session;
181 struct ATS_ressource_entry * ressources;
183 struct ATS_quality_entry * quality;
186 * What was the last latency observed for this address, plugin and peer?
188 struct GNUNET_TIME_Relative latency;
191 * If we did not successfully transmit a message to the given peer
192 * via this connection during the specified time, we should consider
193 * the connection to be dead. This is used in the case that a TCP
194 * transport simply stalls writing to the stream but does not
195 * formerly get a signal that the other peer died.
197 struct GNUNET_TIME_Absolute timeout;
200 * How often have we tried to connect using this plugin? Used to
201 * discriminate against addresses that do not work well.
202 * FIXME: not yet used, but should be!
204 unsigned int connect_attempts;
207 * DV distance to this peer (1 if no DV is used).
208 * FIXME: need to set this from transport plugins!
218 * Have we ever estimated the latency of this address? Used to
219 * ensure that the first time we add an address, we immediately
225 * Are we currently connected via this address? The first time we
226 * successfully transmit or receive data to a peer via a particular
227 * address, we set this to GNUNET_YES. If we later get an error
228 * (disconnect notification, transmission failure, timeout), we set
229 * it back to GNUNET_NO.
234 * Is this plugin currently busy transmitting to the specific target?
235 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
236 * messages do not count as 'in transmit'.
241 * Has this address been validated yet?
249 * Entry in linked list of network addresses for ourselves. Also
250 * includes a cached signature for 'struct TransportPongMessage's.
252 struct OwnAddressList
255 * This is a linked list.
257 struct OwnAddressList *next;
260 * How long until the current signature expires? (ZERO if the
261 * signature was never created).
263 struct GNUNET_TIME_Absolute pong_sig_expires;
266 * Signature for a 'struct TransportPongMessage' for this address.
268 struct GNUNET_CRYPTO_RsaSignature pong_signature;
279 * Entry in linked list of all of our plugins.
281 struct TransportPlugin
284 * This is a linked list.
286 struct TransportPlugin *next;
289 * API of the transport as returned by the plugin's
290 * initialization function.
292 struct GNUNET_TRANSPORT_PluginFunctions *api;
295 * Short name for the plugin (i.e. "tcp").
300 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
305 * List of our known addresses for this transport.
307 struct OwnAddressList *addresses;
310 * Environment this transport service is using
313 struct GNUNET_TRANSPORT_PluginEnvironment env;
316 * ID of task that is used to clean up expired addresses.
318 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
321 * Set to GNUNET_YES if we need to scrap the existing list of
322 * "addresses" and start fresh when we receive the next address
323 * update from a transport. Set to GNUNET_NO if we should just add
324 * the new address to the list and wait for the commit call.
328 struct ATS_plugin * rc;
331 * Hashmap of blacklisted peers for this particular transport.
333 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
336 struct NeighbourMapEntry;
339 * For each neighbour we keep a list of messages
340 * that we still want to transmit to the neighbour.
346 * This is a doubly linked list.
348 struct MessageQueue *next;
351 * This is a doubly linked list.
353 struct MessageQueue *prev;
356 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
357 * stuck together in memory. Allocated at the end of this struct.
359 const char *message_buf;
362 * Size of the message buf
364 size_t message_buf_size;
367 * Client responsible for queueing the message;
368 * used to check that a client has no two messages
369 * pending for the same target. Can be NULL.
371 struct TransportClient *client;
374 * Using which specific address should we send this message?
376 struct ForeignAddressList *specific_address;
379 * Peer ID of the Neighbour this entry belongs to.
381 struct GNUNET_PeerIdentity neighbour_id;
384 * Plugin that we used for the transmission.
385 * NULL until we scheduled a transmission.
387 struct TransportPlugin *plugin;
390 * At what time should we fail?
392 struct GNUNET_TIME_Absolute timeout;
395 * Internal message of the transport system that should not be
396 * included in the usual SEND-SEND_OK transmission confirmation
397 * traffic management scheme. Typically, "internal_msg" will
398 * be set whenever "client" is NULL (but it is not strictly
404 * How important is the message?
406 unsigned int priority;
412 * For a given Neighbour, which plugins are available
413 * to talk to this peer and what are their costs?
418 * This is a linked list.
420 struct ReadyList *next;
423 * Which of our transport plugins does this entry
426 struct TransportPlugin *plugin;
429 * Transport addresses, latency, and readiness for
430 * this particular plugin.
432 struct ForeignAddressList *addresses;
435 * To which neighbour does this ready list belong to?
437 struct NeighbourMapEntry *neighbour;
442 * Entry in neighbours.
444 struct NeighbourMapEntry
448 * Which of our transports is connected to this peer
449 * and what is their status?
451 struct ReadyList *plugins;
454 * Head of list of messages we would like to send to this peer;
455 * must contain at most one message per client.
457 struct MessageQueue *messages_head;
460 * Tail of list of messages we would like to send to this peer; must
461 * contain at most one message per client.
463 struct MessageQueue *messages_tail;
466 * Head of list of messages of messages we expected the continuation
467 * to be called to destroy the message
469 struct MessageQueue *cont_head;
472 * Tail of list of messages of messages we expected the continuation
473 * to be called to destroy the message
475 struct MessageQueue *cont_tail;
478 * Buffer for at most one payload message used when we receive
479 * payload data before our PING-PONG has succeeded. We then
480 * store such messages in this intermediary buffer until the
481 * connection is fully up.
483 struct GNUNET_MessageHeader *pre_connect_message_buffer;
486 * Context for peerinfo iteration.
487 * NULL after we are done processing peerinfo's information.
489 struct GNUNET_PEERINFO_IteratorContext *piter;
492 * Public key for this peer. Valid only if the respective flag is set below.
494 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
497 * Identity of this neighbour.
499 struct GNUNET_PeerIdentity id;
502 * ID of task scheduled to run when this peer is about to
503 * time out (will free resources associated with the peer).
505 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
508 * ID of task scheduled to run when we should retry transmitting
509 * the head of the message queue. Actually triggered when the
510 * transmission is timing out (we trigger instantly when we have
511 * a chance of success).
513 GNUNET_SCHEDULER_TaskIdentifier retry_task;
516 * How long until we should consider this peer dead
517 * (if we don't receive another message in the
520 struct GNUNET_TIME_Absolute peer_timeout;
523 * Tracker for inbound bandwidth.
525 struct GNUNET_BANDWIDTH_Tracker in_tracker;
528 * The latency we have seen for this particular address for
529 * this particular peer. This latency may have been calculated
530 * over multiple transports. This value reflects how long it took
531 * us to receive a response when SENDING via this particular
532 * transport/neighbour/address combination!
534 * FIXME: we need to periodically send PINGs to update this
535 * latency (at least more often than the current "huge" (11h?)
538 struct GNUNET_TIME_Relative latency;
541 * How often has the other peer (recently) violated the
542 * inbound traffic limit? Incremented by 10 per violation,
543 * decremented by 1 per non-violation (for each
546 unsigned int quota_violation_count;
549 * DV distance to this peer (1 if no DV is used).
554 * Have we seen an PONG from this neighbour in the past (and
555 * not had a disconnect since)?
560 * Do we have a valid public key for this neighbour?
562 int public_key_valid;
565 * Are we already in the process of disconnecting this neighbour?
570 * Performance data for the peer.
572 struct GNUNET_TRANSPORT_ATS_Information *ats;
576 * Message used to ask a peer to validate receipt (to check an address
577 * from a HELLO). Followed by the address we are trying to validate,
578 * or an empty address if we are just sending a PING to confirm that a
579 * connection which the receiver (of the PING) initiated is still valid.
581 struct TransportPingMessage
585 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
587 struct GNUNET_MessageHeader header;
590 * Challenge code (to ensure fresh reply).
592 uint32_t challenge GNUNET_PACKED;
595 * Who is the intended recipient?
597 struct GNUNET_PeerIdentity target;
603 * Message used to validate a HELLO. The challenge is included in the
604 * confirmation to make matching of replies to requests possible. The
605 * signature signs our public key, an expiration time and our address.<p>
607 * This message is followed by our transport address that the PING tried
608 * to confirm (if we liked it). The address can be empty (zero bytes)
609 * if the PING had not address either (and we received the request via
610 * a connection that we initiated).
612 struct TransportPongMessage
616 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
618 struct GNUNET_MessageHeader header;
621 * Challenge code from PING (showing freshness). Not part of what
622 * is signed so that we can re-use signatures.
624 uint32_t challenge GNUNET_PACKED;
629 struct GNUNET_CRYPTO_RsaSignature signature;
632 * What are we signing and why? Two possible reason codes can be here:
633 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
634 * plausible address for this peer (pid is set to identity of signer); or
635 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
636 * an address we used to connect to the peer with the given pid.
638 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
641 * When does this signature expire?
643 struct GNUNET_TIME_AbsoluteNBO expiration;
646 * Either the identity of the peer Who signed this message, or the
647 * identity of the peer that we're connected to using the given
648 * address (depending on purpose.type).
650 struct GNUNET_PeerIdentity pid;
653 * Size of address appended to this message (part of what is
654 * being signed, hence not redundant).
662 * Linked list of messages to be transmitted to the client. Each
663 * entry is followed by the actual message.
665 struct ClientMessageQueueEntry
668 * This is a doubly-linked list.
670 struct ClientMessageQueueEntry *next;
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *prev;
680 * Client connected to the transport service.
682 struct TransportClient
686 * This is a linked list.
688 struct TransportClient *next;
691 * Handle to the client.
693 struct GNUNET_SERVER_Client *client;
696 * Linked list of messages yet to be transmitted to
699 struct ClientMessageQueueEntry *message_queue_head;
702 * Tail of linked list of messages yet to be transmitted to the
705 struct ClientMessageQueueEntry *message_queue_tail;
708 * Current transmit request handle.
710 struct GNUNET_CONNECTION_TransmitHandle *th;
713 * Is a call to "transmit_send_continuation" pending? If so, we
714 * must not free this struct (even if the corresponding client
715 * disconnects) and instead only remove it from the linked list and
716 * set the "client" field to NULL.
721 * Length of the list of messages pending for this client.
723 unsigned int message_count;
729 * Context of currently active requests to peerinfo
730 * for validation of HELLOs.
732 struct CheckHelloValidatedContext;
736 * Entry in map of all HELLOs awaiting validation.
738 struct ValidationEntry
742 * NULL if this entry is not part of a larger HELLO validation.
744 struct CheckHelloValidatedContext *chvc;
747 * The address, actually a pointer to the end
748 * of this struct. Do not free!
753 * Name of the transport.
755 char *transport_name;
758 * The public key of the peer.
760 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
763 * ID of task that will clean up this entry if we don't succeed
764 * with the validation first.
766 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
769 * At what time did we send this validation?
771 struct GNUNET_TIME_Absolute send_time;
774 * Session being validated (or NULL for none).
776 struct Session *session;
779 * Challenge number we used.
792 * Context of currently active requests to peerinfo
793 * for validation of HELLOs.
795 struct CheckHelloValidatedContext
799 * This is a doubly-linked list.
801 struct CheckHelloValidatedContext *next;
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *prev;
809 * Hello that we are validating.
811 const struct GNUNET_HELLO_Message *hello;
814 * Context for peerinfo iteration.
815 * NULL after we are done processing peerinfo's information.
817 struct GNUNET_PEERINFO_IteratorContext *piter;
820 * Was a HELLO known for this peer to peerinfo?
825 * Number of validation entries currently referring to this
828 unsigned int ve_count;
833 * All zero hash for comparison.
835 static GNUNET_HashCode null_hash;
840 static struct GNUNET_HELLO_Message *our_hello;
845 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
850 static struct GNUNET_PeerIdentity my_identity;
855 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
860 const struct GNUNET_CONFIGURATION_Handle *cfg;
863 * Linked list of all clients to this service.
865 static struct TransportClient *clients;
868 * All loaded plugins.
870 static struct TransportPlugin *plugins;
873 * Handle to peerinfo service.
875 static struct GNUNET_PEERINFO_Handle *peerinfo;
878 * All known neighbours and their HELLOs.
880 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
883 * Number of neighbours we'd like to have.
885 static uint32_t max_connect_per_transport;
888 * Head of linked list.
890 static struct CheckHelloValidatedContext *chvc_head;
893 * Tail of linked list.
895 static struct CheckHelloValidatedContext *chvc_tail;
898 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
899 * of the given peer that we are currently validating).
901 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
904 * Handle for reporting statistics.
906 static struct GNUNET_STATISTICS_Handle *stats;
909 * Identifier of 'refresh_hello' task.
911 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
914 * Identifier of ats scheduler task.
916 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
919 * Is transport service shutting down ?
921 static int shutdown_in_progress;
924 * Handle for ats information
926 static struct ATS_Handle *ats;
929 * Time of last ats execution
931 struct GNUNET_TIME_Absolute last_ats_execution;
933 * Minimum interval between two ATS executions
935 struct GNUNET_TIME_Relative ats_minimum_interval;
937 * Regular interval when ATS execution is triggered
939 struct GNUNET_TIME_Relative ats_regular_interval;
942 * The peer specified by the given neighbour has timed-out or a plugin
943 * has disconnected. We may either need to do nothing (other plugins
944 * still up), or trigger a full disconnect and clean up. This
945 * function updates our state and do the necessary notifications.
946 * Also notifies our clients that the neighbour is now officially
949 * @param n the neighbour list entry for the peer
950 * @param check should we just check if all plugins
951 * disconnected or must we ask all plugins to
954 static void disconnect_neighbour (struct NeighbourMapEntry *n, int check);
957 * Check the ready list for the given neighbour and if a plugin is
958 * ready for transmission (and if we have a message), do so!
960 * @param nexi target peer for which to transmit
962 static void try_transmission_to_peer (struct NeighbourMapEntry *n);
964 struct ForeignAddressList * get_preferred_ats_address (
965 struct NeighbourMapEntry *n);
968 * Find an entry in the neighbour list for a particular peer.
970 * @return NULL if not found.
972 static struct NeighbourMapEntry *
973 find_neighbour (const struct GNUNET_PeerIdentity *key)
975 return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
978 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
982 for (c=0; c<available_quality_metrics; c++)
984 if (ats_index == qm[c].atis_index)
986 fal->quality[c].values[0] = fal->quality[c].values[1];
987 fal->quality[c].values[1] = fal->quality[c].values[2];
988 fal->quality[c].values[2] = value;
991 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
995 if (set == GNUNET_NO)
997 for (c=0; c<available_ressources; c++)
999 if (ats_index == ressources[c].atis_index)
1001 fal->ressources[c].c = value;
1004 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1013 update_addr_ats (struct ForeignAddressList *fal,
1014 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1019 for (c1=0; c1<ats_count; c1++)
1021 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1027 * Find an entry in the transport list for a particular transport.
1029 * @return NULL if not found.
1031 static struct TransportPlugin *
1032 find_transport (const char *short_name)
1034 struct TransportPlugin *head = plugins;
1035 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1041 * Is a particular peer blacklisted for a particular transport?
1043 * @param peer the peer to check for
1044 * @param plugin the plugin used to connect to the peer
1046 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1049 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1052 if (plugin->blacklist != NULL)
1054 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1058 "Peer `%s:%s' is blacklisted!\n",
1059 plugin->short_name, GNUNET_i2s (peer));
1062 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1072 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1073 char *transport_name)
1075 struct TransportPlugin *plugin;
1077 plugin = find_transport(transport_name);
1078 if (plugin == NULL) /* Nothing to do */
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Adding peer `%s' with plugin `%s' to blacklist\n",
1086 if (plugin->blacklist == NULL)
1087 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1088 GNUNET_assert(plugin->blacklist != NULL);
1089 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1091 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1096 * Read the blacklist file, containing transport:peer entries.
1097 * Provided the transport is loaded, set up hashmap with these
1098 * entries to blacklist peers by transport.
1102 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1109 struct GNUNET_PeerIdentity pid;
1111 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1112 unsigned int entries_found;
1113 char *transport_name;
1116 GNUNET_CONFIGURATION_get_value_filename (cfg,
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 "Option `%s' in section `%s' not specified!\n",
1129 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1130 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1131 | GNUNET_DISK_PERM_USER_WRITE);
1132 if (0 != STAT (fn, &frstat))
1134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1135 _("Could not read blacklist file `%s'\n"), fn);
1139 if (frstat.st_size == 0)
1142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1143 _("Blacklist file `%s' is empty.\n"),
1149 /* FIXME: use mmap */
1150 data = GNUNET_malloc_large (frstat.st_size);
1151 GNUNET_assert(data != NULL);
1152 if (frstat.st_size !=
1153 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1155 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1156 _("Failed to read blacklist from `%s'\n"), fn);
1163 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1165 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1166 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1169 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1172 if (colon_pos >= frstat.st_size)
1174 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1175 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1176 (unsigned long long) colon_pos);
1182 if (isspace( (unsigned char) data[colon_pos]))
1184 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1185 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1186 (unsigned long long) colon_pos);
1188 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1192 tsize = colon_pos - pos;
1193 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1195 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1196 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1197 (unsigned long long) colon_pos);
1206 transport_name = GNUNET_malloc(tsize + 1);
1207 memcpy(transport_name, &data[pos], tsize);
1208 pos = colon_pos + 1;
1210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1211 "Read transport name %s in blacklist file.\n",
1214 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1215 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1217 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1218 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1219 (unsigned long long) pos);
1221 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1223 GNUNET_free_non_null(transport_name);
1226 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1227 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1229 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1230 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1231 (unsigned long long) pos,
1236 if (0 != memcmp (&pid,
1238 sizeof (struct GNUNET_PeerIdentity)))
1241 add_peer_to_blacklist (&pid,
1246 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1247 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1251 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1252 GNUNET_free_non_null(transport_name);
1253 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1256 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1263 * Function called to notify a client about the socket being ready to
1264 * queue more data. "buf" will be NULL and "size" zero if the socket
1265 * was closed for writing in the meantime.
1267 * @param cls closure
1268 * @param size number of bytes available in buf
1269 * @param buf where the callee should write the message
1270 * @return number of bytes written to buf
1273 transmit_to_client_callback (void *cls, size_t size, void *buf)
1275 struct TransportClient *client = cls;
1276 struct ClientMessageQueueEntry *q;
1279 const struct GNUNET_MessageHeader *msg;
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1287 "Transmission to client failed, closing connection.\n");
1289 /* fatal error with client, free message queue! */
1290 while (NULL != (q = client->message_queue_head))
1292 GNUNET_STATISTICS_update (stats,
1293 gettext_noop ("# bytes discarded (could not transmit to client)"),
1294 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1296 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1297 client->message_queue_tail,
1301 client->message_count = 0;
1306 while (NULL != (q = client->message_queue_head))
1308 msg = (const struct GNUNET_MessageHeader *) &q[1];
1309 msize = ntohs (msg->size);
1310 if (msize + tsize > size)
1313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1314 "Transmitting message of type %u to client.\n",
1317 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1318 client->message_queue_tail,
1320 memcpy (&cbuf[tsize], msg, msize);
1323 client->message_count--;
1327 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1328 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1330 GNUNET_TIME_UNIT_FOREVER_REL,
1331 &transmit_to_client_callback,
1333 GNUNET_assert (client->th != NULL);
1340 * Convert an address to a string.
1342 * @param plugin name of the plugin responsible for the address
1343 * @param addr binary address
1344 * @param addr_len number of bytes in addr
1345 * @return NULL on error, otherwise address string
1348 a2s (const char *plugin,
1352 struct TransportPlugin *p;
1356 p = find_transport (plugin);
1357 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1359 return p->api->address_to_string (NULL,
1368 * Iterator to free entries in the validation_map.
1370 * @param cls closure (unused)
1371 * @param key current key code
1372 * @param value value in the hash map (validation to abort)
1373 * @return GNUNET_YES (always)
1376 abort_validation (void *cls,
1377 const GNUNET_HashCode * key,
1380 struct ValidationEntry *va = value;
1382 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1383 GNUNET_SCHEDULER_cancel (va->timeout_task);
1384 GNUNET_free (va->transport_name);
1385 if (va->chvc != NULL)
1387 va->chvc->ve_count--;
1388 if (va->chvc->ve_count == 0)
1390 GNUNET_CONTAINER_DLL_remove (chvc_head,
1393 GNUNET_free (va->chvc);
1403 * HELLO validation cleanup task (validation failed).
1405 * @param cls the 'struct ValidationEntry' that failed
1406 * @param tc scheduler context (unused)
1409 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1411 struct ValidationEntry *va = cls;
1412 struct GNUNET_PeerIdentity pid;
1414 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1415 GNUNET_STATISTICS_update (stats,
1416 gettext_noop ("# address validation timeouts"),
1419 GNUNET_CRYPTO_hash (&va->publicKey,
1421 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1423 GNUNET_break (GNUNET_OK ==
1424 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1427 abort_validation (NULL, NULL, va);
1433 * Send the specified message to the specified client. Since multiple
1434 * messages may be pending for the same client at a time, this code
1435 * makes sure that no message is lost.
1437 * @param client client to transmit the message to
1438 * @param msg the message to send
1439 * @param may_drop can this message be dropped if the
1440 * message queue for this client is getting far too large?
1443 transmit_to_client (struct TransportClient *client,
1444 const struct GNUNET_MessageHeader *msg, int may_drop)
1446 struct ClientMessageQueueEntry *q;
1449 /* Client==NULL when GNUNET_SERVER_Client disconnected and was
1450 * freed in client_disconnect_notification
1452 if (client->client == NULL)
1458 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1460 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1462 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1465 client->message_count,
1467 GNUNET_STATISTICS_update (stats,
1468 gettext_noop ("# messages dropped due to slow client"),
1473 msize = ntohs (msg->size);
1474 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1475 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1476 memcpy (&q[1], msg, msize);
1477 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1478 client->message_queue_tail,
1480 client->message_count++;
1481 if (client->th == NULL)
1483 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1485 GNUNET_TIME_UNIT_FOREVER_REL,
1486 &transmit_to_client_callback,
1488 GNUNET_assert (client->th != NULL);
1494 * Transmit a 'SEND_OK' notification to the given client for the
1497 * @param client who to notify
1498 * @param n neighbour to notify about, can be NULL (on failure)
1499 * @param target target of the transmission
1500 * @param result status code for the transmission request
1503 transmit_send_ok (struct TransportClient *client,
1504 struct NeighbourMapEntry *n,
1505 const struct GNUNET_PeerIdentity *target,
1508 struct SendOkMessage send_ok_msg;
1510 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1511 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1512 send_ok_msg.success = htonl (result);
1514 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1516 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1517 send_ok_msg.peer = *target;
1518 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1523 * Mark the given FAL entry as 'connected' (and hence preferred for
1524 * sending); also mark all others for the same peer as 'not connected'
1525 * (since only one can be preferred).
1527 * @param fal address to set to 'connected'
1530 mark_address_connected (struct ForeignAddressList *fal);
1535 * We should re-try transmitting to the given peer,
1536 * hopefully we've learned something in the meantime.
1539 retry_transmission_task (void *cls,
1540 const struct GNUNET_SCHEDULER_TaskContext *tc)
1542 struct NeighbourMapEntry *n = cls;
1544 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1545 try_transmission_to_peer (n);
1550 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1551 * upon "completion" of a send request. This tells the API
1552 * that it is now legal to send another message to the given
1555 * @param cls closure, identifies the entry on the
1556 * message queue that was transmitted and the
1557 * client responsible for queuing the message
1558 * @param target the peer receiving the message
1559 * @param result GNUNET_OK on success, if the transmission
1560 * failed, we should not tell the client to transmit
1564 transmit_send_continuation (void *cls,
1565 const struct GNUNET_PeerIdentity *target,
1568 struct MessageQueue *mq = cls;
1569 struct NeighbourMapEntry *n;
1571 GNUNET_STATISTICS_update (stats,
1572 gettext_noop ("# bytes pending with plugins"),
1573 - (int64_t) mq->message_buf_size,
1575 if (result == GNUNET_OK)
1577 GNUNET_STATISTICS_update (stats,
1578 gettext_noop ("# bytes successfully transmitted by plugins"),
1579 mq->message_buf_size,
1584 GNUNET_STATISTICS_update (stats,
1585 gettext_noop ("# bytes with transmission failure by plugins"),
1586 mq->message_buf_size,
1589 if (mq->specific_address != NULL)
1591 if (result == GNUNET_OK)
1593 mq->specific_address->timeout =
1594 GNUNET_TIME_relative_to_absolute
1595 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1596 if (mq->specific_address->validated == GNUNET_YES)
1597 mark_address_connected (mq->specific_address);
1601 if (mq->specific_address->connected == GNUNET_YES)
1604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1605 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1606 a2s (mq->specific_address->ready_list->plugin->short_name,
1607 mq->specific_address->addr,
1608 mq->specific_address->addrlen));
1610 GNUNET_STATISTICS_update (stats,
1611 gettext_noop ("# connected addresses"),
1614 mq->specific_address->connected = GNUNET_NO;
1617 if (! mq->internal_msg)
1618 mq->specific_address->in_transmit = GNUNET_NO;
1620 n = find_neighbour (&mq->neighbour_id);
1621 if (mq->client != NULL)
1622 transmit_send_ok (mq->client, n, target, result);
1623 GNUNET_assert (n != NULL);
1624 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1628 if (result == GNUNET_OK)
1629 try_transmission_to_peer (n);
1630 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1631 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1637 * Check the ready list for the given neighbour and if a plugin is
1638 * ready for transmission (and if we have a message), do so!
1640 * @param neighbour target peer for which to transmit
1643 try_transmission_to_peer (struct NeighbourMapEntry *n)
1645 struct ReadyList *rl;
1646 struct MessageQueue *mq;
1647 struct GNUNET_TIME_Relative timeout;
1651 if (n->messages_head == NULL)
1654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1655 "Transmission queue for `%4s' is empty\n",
1656 GNUNET_i2s (&n->id));
1658 return; /* nothing to do */
1661 mq = n->messages_head;
1662 force_address = GNUNET_YES;
1663 if (mq->specific_address == NULL)
1666 mq->specific_address = get_preferred_ats_address(n);
1667 GNUNET_STATISTICS_update (stats,
1668 gettext_noop ("# transport selected peer address freely"),
1671 force_address = GNUNET_NO;
1673 if (mq->specific_address == NULL)
1675 GNUNET_STATISTICS_update (stats,
1676 gettext_noop ("# transport failed to selected peer address"),
1679 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1680 if (timeout.rel_value == 0)
1683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1684 "No destination address available to transmit message of size %u to peer `%4s'\n",
1685 mq->message_buf_size,
1686 GNUNET_i2s (&mq->neighbour_id));
1688 GNUNET_STATISTICS_update (stats,
1689 gettext_noop ("# bytes in message queue for other peers"),
1690 - (int64_t) mq->message_buf_size,
1692 GNUNET_STATISTICS_update (stats,
1693 gettext_noop ("# bytes discarded (no destination address available)"),
1694 mq->message_buf_size,
1696 if (mq->client != NULL)
1697 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1698 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1702 return; /* nobody ready */
1704 GNUNET_STATISTICS_update (stats,
1705 gettext_noop ("# message delivery deferred (no address)"),
1708 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1709 GNUNET_SCHEDULER_cancel (n->retry_task);
1710 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1711 &retry_transmission_task,
1714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1715 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1716 mq->message_buf_size,
1717 GNUNET_i2s (&mq->neighbour_id),
1720 /* FIXME: might want to trigger peerinfo lookup here
1721 (unless that's already pending...) */
1724 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1727 if (mq->specific_address->connected == GNUNET_NO)
1728 mq->specific_address->connect_attempts++;
1729 rl = mq->specific_address->ready_list;
1730 mq->plugin = rl->plugin;
1731 if (!mq->internal_msg)
1732 mq->specific_address->in_transmit = GNUNET_YES;
1734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1735 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1736 mq->message_buf_size,
1737 GNUNET_i2s (&n->id),
1738 (mq->specific_address->addr != NULL)
1739 ? a2s (mq->plugin->short_name,
1740 mq->specific_address->addr,
1741 mq->specific_address->addrlen)
1743 rl->plugin->short_name);
1745 GNUNET_STATISTICS_update (stats,
1746 gettext_noop ("# bytes in message queue for other peers"),
1747 - (int64_t) mq->message_buf_size,
1749 GNUNET_STATISTICS_update (stats,
1750 gettext_noop ("# bytes pending with plugins"),
1751 mq->message_buf_size,
1754 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1758 ret = rl->plugin->api->send (rl->plugin->api->cls,
1761 mq->message_buf_size,
1763 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1764 mq->specific_address->session,
1765 mq->specific_address->addr,
1766 mq->specific_address->addrlen,
1768 &transmit_send_continuation, mq);
1771 /* failure, but 'send' would not call continuation in this case,
1772 so we need to do it here! */
1773 transmit_send_continuation (mq,
1781 * Send the specified message to the specified peer.
1783 * @param client source of the transmission request (can be NULL)
1784 * @param peer_address ForeignAddressList where we should send this message
1785 * @param priority how important is the message
1786 * @param timeout how long do we have to transmit?
1787 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1788 * @param message_buf_size total size of all messages in message_buf
1789 * @param is_internal is this an internal message; these are pre-pended and
1790 * also do not count for plugins being "ready" to transmit
1791 * @param neighbour handle to the neighbour for transmission
1794 transmit_to_peer (struct TransportClient *client,
1795 struct ForeignAddressList *peer_address,
1796 unsigned int priority,
1797 struct GNUNET_TIME_Relative timeout,
1798 const char *message_buf,
1799 size_t message_buf_size,
1800 int is_internal, struct NeighbourMapEntry *neighbour)
1802 struct MessageQueue *mq;
1807 /* check for duplicate submission */
1808 mq = neighbour->messages_head;
1811 if (mq->client == client)
1813 /* client transmitted to same peer twice
1814 before getting SEND_OK! */
1822 GNUNET_STATISTICS_update (stats,
1823 gettext_noop ("# bytes in message queue for other peers"),
1826 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1827 mq->specific_address = peer_address;
1828 mq->client = client;
1829 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1830 memcpy (&mq[1], message_buf, message_buf_size);
1831 mq->message_buf = (const char*) &mq[1];
1832 mq->message_buf_size = message_buf_size;
1833 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1834 mq->internal_msg = is_internal;
1835 mq->priority = priority;
1836 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1838 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1839 neighbour->messages_tail,
1842 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1843 neighbour->messages_tail,
1844 neighbour->messages_tail,
1846 try_transmission_to_peer (neighbour);
1851 * Send a plain PING (without address or our HELLO) to the given
1852 * foreign address to try to establish a connection (and validate
1853 * that the other peer is really who he claimed he is).
1855 * @param n neighbour to PING
1858 transmit_plain_ping (struct NeighbourMapEntry *n)
1860 struct ValidationEntry *ve;
1861 struct TransportPingMessage ping;
1862 struct ReadyList *rl;
1863 struct TransportPlugin *plugin;
1864 struct ForeignAddressList *fal;
1866 if (! n->public_key_valid)
1868 /* This should not happen since the other peer
1869 should send us a HELLO prior to sending his
1871 GNUNET_break_op (0);
1872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1873 "Could not transmit plain PING to `%s': public key not known\n",
1874 GNUNET_i2s (&n->id));
1877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1878 "Looking for addresses to transmit plain PING to `%s'\n",
1879 GNUNET_i2s (&n->id));
1880 for (rl = n->plugins; rl != NULL; rl = rl->next)
1882 plugin = rl->plugin;
1883 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1885 if (! fal->connected)
1887 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1888 ve->transport_name = GNUNET_strdup (plugin->short_name);
1889 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1891 ve->send_time = GNUNET_TIME_absolute_get();
1892 ve->session = fal->session;
1893 memcpy(&ve->publicKey,
1895 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1896 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1897 &timeout_hello_validation,
1899 GNUNET_CONTAINER_multihashmap_put (validation_map,
1902 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1903 ping.header.size = htons(sizeof(struct TransportPingMessage));
1904 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1905 ping.challenge = htonl(ve->challenge);
1906 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1907 GNUNET_STATISTICS_update (stats,
1908 gettext_noop ("# PING without HELLO messages sent"),
1911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1912 "Transmitting plain PING to `%s'\n",
1913 GNUNET_i2s (&n->id));
1914 transmit_to_peer (NULL,
1916 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1917 HELLO_VERIFICATION_TIMEOUT,
1918 (const char*) &ping, sizeof (ping),
1926 * Mark the given FAL entry as 'connected' (and hence preferred for
1927 * sending); also mark all others for the same peer as 'not connected'
1928 * (since only one can be preferred).
1930 * @param fal address to set to 'connected'
1933 mark_address_connected(struct ForeignAddressList *fal)
1935 struct ForeignAddressList *pos;
1936 struct ForeignAddressList *inbound;
1937 struct ForeignAddressList *outbound;
1939 GNUNET_assert (GNUNET_YES == fal->validated);
1940 if (fal->connected == GNUNET_YES)
1941 return; /* nothing to do */
1945 pos = fal->ready_list->addresses;
1948 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1949 if ( (GNUNET_YES == pos->connected) &&
1950 (0 == pos->addrlen) &&
1951 (0 == fal->addrlen) )
1953 if ( (0 == pos->addrlen) &&
1954 (GNUNET_YES == pos->connected) )
1959 pos = fal->ready_list->addresses;
1962 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1963 if ( (GNUNET_YES == pos->connected) &&
1964 (0 < pos->addrlen) &&
1965 (0 < fal->addrlen) )
1967 if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
1973 if (inbound != NULL)
1974 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1975 if (outbound != NULL)
1976 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1979 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1980 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1981 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1982 &my_identity.hashPubKey, &null_hash)))
1985 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1989 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1990 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1991 &my_identity.hashPubKey, &null_hash))))
1994 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
1999 pos = fal->ready_list->addresses;
2002 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2006 "Marking address `%s' as no longer connected (due to connect on other address)\n",
2007 a2s (pos->ready_list->plugin->short_name, pos->addr,
2012 "Peer: %s, setting %s connection to disconnected.\n",
2013 GNUNET_i2s(&my_identity),
2014 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2016 pos->connected = GNUNET_NO;
2017 GNUNET_STATISTICS_update (stats,
2018 gettext_noop ("# connected addresses"), -1,
2023 GNUNET_assert (GNUNET_NO == fal->connected);
2024 fal->connected = GNUNET_YES;
2025 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2031 * Find an address in any of the available transports for
2032 * the given neighbour that would be good for message
2033 * transmission. This is essentially the transport selection
2036 * @param neighbour for whom to select an address
2037 * @return selected address, NULL if we have none
2039 struct ForeignAddressList *
2040 find_ready_address(struct NeighbourMapEntry *neighbour)
2042 struct ReadyList *head = neighbour->plugins;
2043 struct ForeignAddressList *addresses;
2044 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2045 struct ForeignAddressList *best_address;
2047 /* Hack to prefer unix domain sockets */
2048 struct ForeignAddressList *unix_address = NULL;
2050 best_address = NULL;
2051 while (head != NULL)
2053 addresses = head->addresses;
2054 while (addresses != NULL)
2056 if ( (addresses->timeout.abs_value < now.abs_value) &&
2057 (addresses->connected == GNUNET_YES) )
2060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2061 "Marking long-time inactive connection to `%4s' as down.\n",
2062 GNUNET_i2s (&neighbour->id));
2064 GNUNET_STATISTICS_update (stats,
2065 gettext_noop ("# connected addresses"),
2068 addresses->connected = GNUNET_NO;
2070 addresses = addresses->next;
2073 addresses = head->addresses;
2074 while (addresses != NULL)
2077 if (addresses->addr != NULL)
2078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2079 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2080 a2s (head->plugin->short_name,
2082 addresses->addrlen),
2083 GNUNET_i2s (&neighbour->id),
2084 addresses->connected,
2085 addresses->in_transmit,
2086 addresses->validated,
2087 addresses->connect_attempts,
2088 (unsigned long long) addresses->timeout.abs_value,
2089 (unsigned int) addresses->distance);
2091 if (0==strcmp(head->plugin->short_name,"unix"))
2093 if ( (unix_address == NULL) ||
2094 ( (unix_address != NULL) &&
2095 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2096 unix_address = addresses;
2098 if ( ( (best_address == NULL) ||
2099 (addresses->connected == GNUNET_YES) ||
2100 (best_address->connected == GNUNET_NO) ) &&
2101 (addresses->in_transmit == GNUNET_NO) &&
2102 ( (best_address == NULL) ||
2103 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2104 best_address = addresses;
2105 /* FIXME: also give lower-latency addresses that are not
2106 connected a chance some times... */
2107 addresses = addresses->next;
2109 if (unix_address != NULL)
2113 if (unix_address != NULL)
2115 best_address = unix_address;
2117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2118 "Found UNIX address, forced this address\n");
2121 if (best_address != NULL)
2124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2125 "Best address found (`%s') has latency of %llu ms.\n",
2126 (best_address->addrlen > 0)
2127 ? a2s (best_address->ready_list->plugin->short_name,
2129 best_address->addrlen)
2131 best_address->latency.rel_value);
2136 GNUNET_STATISTICS_update (stats,
2137 gettext_noop ("# transmission attempts failed (no address)"),
2142 return best_address;
2149 struct GeneratorContext
2151 struct TransportPlugin *plug_pos;
2152 struct OwnAddressList *addr_pos;
2153 struct GNUNET_TIME_Absolute expiration;
2161 address_generator (void *cls, size_t max, void *buf)
2163 struct GeneratorContext *gc = cls;
2166 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2168 gc->plug_pos = gc->plug_pos->next;
2169 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2171 if (NULL == gc->plug_pos)
2176 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2179 gc->addr_pos->addrlen, buf, max);
2180 gc->addr_pos = gc->addr_pos->next;
2187 transmit_our_hello_if_pong (void *cls,
2188 const GNUNET_HashCode *key,
2191 struct NeighbourMapEntry *npos = value;
2193 if (GNUNET_YES != npos->received_pong)
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2197 "Transmitting updated `%s' to neighbour `%4s'\n",
2198 "HELLO", GNUNET_i2s (&npos->id));
2200 GNUNET_STATISTICS_update (stats,
2201 gettext_noop ("# transmitted my HELLO to other peers"),
2204 transmit_to_peer (NULL, NULL, 0,
2205 HELLO_ADDRESS_EXPIRATION,
2206 (const char *) our_hello,
2207 GNUNET_HELLO_size(our_hello),
2214 * Construct our HELLO message from all of the addresses of
2215 * all of the transports.
2218 * @param tc scheduler context
2221 refresh_hello_task (void *cls,
2222 const struct GNUNET_SCHEDULER_TaskContext *tc)
2224 struct GNUNET_HELLO_Message *hello;
2225 struct TransportClient *cpos;
2226 struct GeneratorContext gc;
2228 hello_task = GNUNET_SCHEDULER_NO_TASK;
2229 gc.plug_pos = plugins;
2230 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2231 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2232 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2235 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2237 GNUNET_STATISTICS_update (stats,
2238 gettext_noop ("# refreshed my HELLO"),
2242 while (cpos != NULL)
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 "Transmitting my HELLO to client!\n");
2246 transmit_to_client (cpos,
2247 (const struct GNUNET_MessageHeader *) hello,
2252 GNUNET_free_non_null (our_hello);
2254 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2255 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2256 &transmit_our_hello_if_pong,
2262 * Schedule task to refresh hello (unless such a
2263 * task exists already).
2268 #if DEBUG_TRANSPORT_HELLO
2269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2270 "refresh_hello() called!\n");
2272 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2275 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2281 * Iterator over hash map entries that NULLs the session of validation
2282 * entries that match the given session.
2284 * @param cls closure (the 'struct Session*' to match against)
2285 * @param key current key code (peer ID, not used)
2286 * @param value value in the hash map ('struct ValidationEntry*')
2287 * @return GNUNET_YES (we should continue to iterate)
2290 remove_session_validations (void *cls,
2291 const GNUNET_HashCode * key,
2294 struct Session *session = cls;
2295 struct ValidationEntry *ve = value;
2297 if (session == ve->session)
2304 * We've been disconnected from the other peer (for some
2305 * connection-oriented transport). Either quickly
2306 * re-establish the connection or signal the disconnect
2309 * Only signal CORE level disconnect if ALL addresses
2310 * for the peer are exhausted.
2312 * @param p overall plugin context
2313 * @param nl neighbour that was disconnected
2316 try_fast_reconnect (struct TransportPlugin *p,
2317 struct NeighbourMapEntry *nl)
2319 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2320 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2321 "try_fast_reconnect not implemented!\n");
2322 /* Note: the idea here is to hide problems with transports (or
2323 switching between plugins) from the core to eliminate the need to
2324 re-negotiate session keys and the like; OTOH, we should tell core
2325 quickly (much faster than timeout) `if a connection was lost and
2326 could not be re-established (i.e. other peer went down or is
2327 unable / refuses to communicate);
2329 So we should consider:
2330 1) ideally: our own willingness / need to connect
2331 2) prior failures to connect to this peer (by plugin)
2332 3) ideally: reasons why other peer terminated (as far as knowable)
2334 Most importantly, it must be POSSIBLE for another peer to terminate
2335 a connection for a while (without us instantly re-establishing it).
2336 Similarly, if another peer is gone we should quickly notify CORE.
2337 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2338 on the other end), we should reconnect in such a way that BOTH CORE
2339 services never even notice.
2340 Furthermore, the same mechanism (or small variation) could be used
2341 to switch to a better-performing plugin (ATS).
2343 Finally, this needs to be tested throughly... */
2346 * GNUNET_NO in the call below makes transport disconnect the peer,
2347 * even if only a single address (out of say, six) went away. This
2348 * function must be careful to ONLY disconnect if the peer is gone,
2349 * not just a specific address.
2351 * More specifically, half the places it was used had it WRONG.
2354 /* No reconnect, signal disconnect instead! */
2357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2358 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2359 "try_fast_reconnect");
2361 GNUNET_STATISTICS_update (stats,
2362 gettext_noop ("# disconnects due to try_fast_reconnect"),
2366 disconnect_neighbour (nl, GNUNET_YES);
2372 * Function that will be called whenever the plugin internally
2373 * cleans up a session pointer and hence the service needs to
2374 * discard all of those sessions as well. Plugins that do not
2375 * use sessions can simply omit calling this function and always
2376 * use NULL wherever a session pointer is needed.
2378 * @param cls closure
2379 * @param peer which peer was the session for
2380 * @param session which session is being destoyed
2383 plugin_env_session_end (void *cls,
2384 const struct GNUNET_PeerIdentity *peer,
2385 struct Session *session)
2387 struct TransportPlugin *p = cls;
2388 struct NeighbourMapEntry *nl;
2389 struct ReadyList *rl;
2390 struct ForeignAddressList *pos;
2391 struct ForeignAddressList *prev;
2394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395 "Session ended with peer `%4s', %s\n",
2397 "plugin_env_session_end");
2399 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2400 &remove_session_validations,
2402 nl = find_neighbour (peer);
2406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2407 "No neighbour record found for peer `%4s'\n",
2410 return; /* was never marked as connected */
2415 if (rl->plugin == p)
2422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2423 "Plugin was associated with peer `%4s'\n",
2426 GNUNET_STATISTICS_update (stats,
2427 gettext_noop ("# disconnects due to session end"),
2430 disconnect_neighbour (nl, GNUNET_YES);
2434 pos = rl->addresses;
2435 while ( (pos != NULL) &&
2436 (pos->session != session) )
2444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2445 "Session was never marked as ready for peer `%4s'\n",
2449 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2451 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2452 if (validations_pending ==GNUNET_YES)
2455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2456 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2461 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2462 GNUNET_STATISTICS_update (stats,
2463 gettext_noop ("# disconnects due to unready session"),
2467 disconnect_neighbour (nl, GNUNET_YES);
2468 return; /* was never marked as connected */
2470 pos->session = NULL;
2471 if (GNUNET_YES == pos->connected)
2473 pos->connected = GNUNET_NO;
2474 GNUNET_STATISTICS_update (stats,
2475 gettext_noop ("# connected addresses"),
2479 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2481 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2482 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2485 if (pos->addrlen != 0)
2487 if (nl->received_pong != GNUNET_NO)
2489 GNUNET_STATISTICS_update (stats,
2490 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2493 if (GNUNET_YES == pos->connected)
2494 try_fast_reconnect (p, nl);
2498 GNUNET_STATISTICS_update (stats,
2499 gettext_noop ("# disconnects due to missing pong"),
2502 /* FIXME this is never true?! See: line 2416*/
2503 if (GNUNET_YES == pos->connected)
2504 disconnect_neighbour (nl, GNUNET_YES);
2509 /* was inbound connection, free 'pos' */
2511 rl->addresses = pos->next;
2513 prev->next = pos->next;
2514 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2516 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2517 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2519 GNUNET_free_non_null (pos->ressources);
2520 GNUNET_free_non_null (pos->quality);
2522 ats_modify_problem_state (ats, ATS_MODIFIED);
2524 if (GNUNET_YES != pos->connected)
2526 /* nothing else to do, connection was never up... */
2530 pos->connected = GNUNET_NO;
2531 GNUNET_STATISTICS_update (stats,
2532 gettext_noop ("# connected addresses"),
2537 if (nl->received_pong == GNUNET_NO)
2539 GNUNET_STATISTICS_update (stats,
2540 gettext_noop ("# disconnects due to NO pong"),
2543 disconnect_neighbour (nl, GNUNET_YES);
2544 return; /* nothing to do, never connected... */
2546 /* check if we have any validated addresses left */
2547 pos = rl->addresses;
2550 if (GNUNET_YES == pos->validated)
2552 GNUNET_STATISTICS_update (stats,
2553 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2556 try_fast_reconnect (p, nl);
2561 /* no valid addresses left, signal disconnect! */
2564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2565 "Disconnecting peer `%4s', %s\n",
2567 "plugin_env_session_end");
2569 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2570 * it means there aren't any left for this PLUGIN/PEER combination! So
2571 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2572 * when it isn't necessary. Using GNUNET_YES at least checks to see
2573 * if there are any addresses that work first, so as not to overdo it.
2576 GNUNET_STATISTICS_update (stats,
2577 gettext_noop ("# disconnects due to plugin_env_session_end"),
2580 disconnect_neighbour (nl, GNUNET_YES);
2585 * Function that must be called by each plugin to notify the
2586 * transport service about the addresses under which the transport
2587 * provided by the plugin can be reached.
2589 * @param cls closure
2590 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2591 * @param addr one of the addresses of the host, NULL for the last address
2592 * the specific address format depends on the transport
2593 * @param addrlen length of the address
2596 plugin_env_notify_address (void *cls,
2601 struct TransportPlugin *p = cls;
2602 struct OwnAddressList *al;
2603 struct OwnAddressList *prev;
2605 GNUNET_assert (p->api != NULL);
2607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2608 (add_remove == GNUNET_YES)
2609 ? "Adding `%s':%s to the set of our addresses\n"
2610 : "Removing `%s':%s from the set of our addresses\n",
2615 GNUNET_assert (addr != NULL);
2616 if (GNUNET_NO == add_remove)
2622 if ( (addrlen == al->addrlen) &&
2623 (0 == memcmp (addr, &al[1], addrlen)) )
2626 p->addresses = al->next;
2628 prev->next = al->next;
2639 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2640 al->next = p->addresses;
2642 al->addrlen = addrlen;
2643 memcpy (&al[1], addr, addrlen);
2649 * Notify all of our clients about a peer connecting.
2652 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2653 struct GNUNET_TIME_Relative latency,
2656 struct ConnectInfoMessage * cim;
2657 struct TransportClient *cpos;
2661 if (0 == memcmp (peer,
2663 sizeof (struct GNUNET_PeerIdentity)))
2669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2670 "Notifying clients about connection with `%s'\n",
2673 GNUNET_STATISTICS_update (stats,
2674 gettext_noop ("# peers connected"),
2679 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2680 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2681 cim = GNUNET_malloc (size);
2682 cim->header.size = htons (size);
2683 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2684 cim->ats_count = htonl(2);
2685 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2686 (&cim->ats)[0].value = htonl (distance);
2687 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2688 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2689 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2690 (&cim->ats)[2].value = htonl (0);
2691 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2693 /* notify ats about connecting peer */
2694 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2697 ats_modify_problem_state(ats, ATS_MODIFIED);
2698 ats_calculate_bandwidth_distribution (ats);
2702 while (cpos != NULL)
2704 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2712 * Notify all of our clients about a peer disconnecting.
2715 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2717 struct DisconnectInfoMessage dim;
2718 struct TransportClient *cpos;
2720 if (0 == memcmp (peer,
2722 sizeof (struct GNUNET_PeerIdentity)))
2728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2729 "Notifying clients about lost connection to `%s'\n",
2732 GNUNET_STATISTICS_update (stats,
2733 gettext_noop ("# peers connected"),
2736 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2737 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2738 dim.reserved = htonl (0);
2739 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2741 /* notify ats about connecting peer */
2742 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2745 ats_modify_problem_state(ats, ATS_MODIFIED);
2746 ats_calculate_bandwidth_distribution (ats);
2751 while (cpos != NULL)
2753 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2760 * Find a ForeignAddressList entry for the given neighbour
2761 * that matches the given address and transport.
2763 * @param neighbour which peer we care about
2764 * @param tname name of the transport plugin
2765 * @param session session to look for, NULL for 'any'; otherwise
2766 * can be used for the service to "learn" this session ID
2768 * @param addr binary address
2769 * @param addrlen length of addr
2770 * @return NULL if no such entry exists
2772 static struct ForeignAddressList *
2773 find_peer_address(struct NeighbourMapEntry *neighbour,
2775 struct Session *session,
2779 struct ReadyList *head;
2780 struct ForeignAddressList *pos;
2782 head = neighbour->plugins;
2783 while (head != NULL)
2785 if (0 == strcmp (tname, head->plugin->short_name))
2791 pos = head->addresses;
2792 while ( (pos != NULL) &&
2793 ( (pos->addrlen != addrlen) ||
2794 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2796 if ( (session != NULL) &&
2797 (pos->session == session) )
2801 if ( (session != NULL) && (pos != NULL) )
2802 pos->session = session; /* learn it! */
2808 * Get the peer address struct for the given neighbour and
2809 * address. If it doesn't yet exist, create it.
2811 * @param neighbour which peer we care about
2812 * @param tname name of the transport plugin
2813 * @param session session of the plugin, or NULL for none
2814 * @param addr binary address
2815 * @param addrlen length of addr
2816 * @return NULL if we do not have a transport plugin for 'tname'
2818 static struct ForeignAddressList *
2819 add_peer_address (struct NeighbourMapEntry *neighbour,
2821 struct Session *session,
2825 struct ReadyList *head;
2826 struct ForeignAddressList *ret;
2829 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2832 head = neighbour->plugins;
2834 while (head != NULL)
2836 if (0 == strcmp (tname, head->plugin->short_name))
2842 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2843 ret->session = session;
2844 if ((addrlen > 0) && (addr != NULL))
2846 ret->addr = (const char*) &ret[1];
2847 memcpy (&ret[1], addr, addrlen);
2854 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2855 for (c=0; c<available_ressources; c++)
2857 struct ATS_ressource_entry *r = ret->ressources;
2859 r[c].atis_index = ressources[c].atis_index;
2860 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2862 r[c].c = ressources[c].c_unix;
2864 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2866 r[c].c = ressources[c].c_udp;
2868 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2870 r[c].c = ressources[c].c_tcp;
2872 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2874 r[c].c = ressources[c].c_http;
2876 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2878 r[c].c = ressources[c].c_https;
2880 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2882 r[c].c = ressources[c].c_wlan;
2886 r[c].c = ressources[c].c_default;
2887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2888 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2889 GNUNET_i2s(&neighbour->id),
2890 neighbour->plugins->plugin->short_name);
2894 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2895 ret->addrlen = addrlen;
2896 ret->expires = GNUNET_TIME_relative_to_absolute
2897 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2898 ret->latency = GNUNET_TIME_relative_get_forever();
2900 ret->timeout = GNUNET_TIME_relative_to_absolute
2901 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2902 ret->ready_list = head;
2903 ret->next = head->addresses;
2904 head->addresses = ret;
2910 * Closure for 'add_validated_address'.
2912 struct AddValidatedAddressContext
2915 * Entry that has been validated.
2917 const struct ValidationEntry *ve;
2920 * Flag set after we have added the address so
2921 * that we terminate the iteration next time.
2928 * Callback function used to fill a buffer of max bytes with a list of
2929 * addresses in the format used by HELLOs. Should use
2930 * "GNUNET_HELLO_add_address" as a helper function.
2932 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2933 * @param max maximum number of bytes that can be written to buf
2934 * @param buf where to write the address information
2935 * @return number of bytes written, 0 to signal the
2936 * end of the iteration.
2939 add_validated_address (void *cls,
2940 size_t max, void *buf)
2942 struct AddValidatedAddressContext *avac = cls;
2943 const struct ValidationEntry *ve = avac->ve;
2945 if (GNUNET_YES == avac->done)
2947 avac->done = GNUNET_YES;
2948 return GNUNET_HELLO_add_address (ve->transport_name,
2949 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2959 * Closure for 'check_address_exists'.
2961 struct CheckAddressExistsClosure
2964 * Address to check for.
2969 * Name of the transport.
2976 struct Session *session;
2979 * Set to GNUNET_YES if the address exists.
2992 * Iterator over hash map entries. Checks if the given
2993 * validation entry is for the same address as what is given
2996 * @param cls the 'struct CheckAddressExistsClosure*'
2997 * @param key current key code (ignored)
2998 * @param value value in the hash map ('struct ValidationEntry')
2999 * @return GNUNET_YES if we should continue to
3000 * iterate (mismatch), GNUNET_NO if not (entry matched)
3003 check_address_exists (void *cls,
3004 const GNUNET_HashCode * key,
3007 struct CheckAddressExistsClosure *caec = cls;
3008 struct ValidationEntry *ve = value;
3010 if ( (0 == strcmp (caec->tname,
3011 ve->transport_name)) &&
3012 (caec->addrlen == ve->addrlen) &&
3013 (0 == memcmp (caec->addr,
3017 caec->exists = GNUNET_YES;
3020 if ( (ve->session != NULL) &&
3021 (caec->session == ve->session) )
3023 caec->exists = GNUNET_YES;
3031 neighbour_timeout_task (void *cls,
3032 const struct GNUNET_SCHEDULER_TaskContext *tc)
3034 struct NeighbourMapEntry *n = cls;
3037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3038 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3040 GNUNET_STATISTICS_update (stats,
3041 gettext_noop ("# disconnects due to timeout"),
3044 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3045 disconnect_neighbour (n, GNUNET_NO);
3050 * Schedule the job that will cause us to send a PING to the
3051 * foreign address to evaluate its validity and latency.
3053 * @param fal address to PING
3056 schedule_next_ping (struct ForeignAddressList *fal);
3060 * Add the given address to the list of foreign addresses
3061 * available for the given peer (check for duplicates).
3063 * @param cls the respective 'struct NeighbourMapEntry' to update
3064 * @param tname name of the transport
3065 * @param expiration expiration time
3066 * @param addr the address
3067 * @param addrlen length of the address
3068 * @return GNUNET_OK (always)
3071 add_to_foreign_address_list (void *cls,
3073 struct GNUNET_TIME_Absolute expiration,
3077 struct NeighbourMapEntry *n = cls;
3078 struct ForeignAddressList *fal;
3081 GNUNET_STATISTICS_update (stats,
3082 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3086 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3089 #if DEBUG_TRANSPORT_HELLO
3090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3091 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3092 a2s (tname, addr, addrlen),
3094 GNUNET_i2s (&n->id),
3095 expiration.abs_value);
3097 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3100 GNUNET_STATISTICS_update (stats,
3101 gettext_noop ("# previously validated addresses lacking transport"),
3107 fal->expires = GNUNET_TIME_absolute_max (expiration,
3109 schedule_next_ping (fal);
3115 fal->expires = GNUNET_TIME_absolute_max (expiration,
3121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3122 "Failed to add new address for `%4s'\n",
3123 GNUNET_i2s (&n->id));
3127 if (fal->validated == GNUNET_NO)
3129 fal->validated = GNUNET_YES;
3130 GNUNET_STATISTICS_update (stats,
3131 gettext_noop ("# peer addresses considered valid"),
3135 if (try == GNUNET_YES)
3138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3139 "Have new addresses, will try to trigger transmissions.\n");
3141 try_transmission_to_peer (n);
3148 * Add addresses in validated HELLO "h" to the set of addresses
3149 * we have for this peer.
3151 * @param cls closure ('struct NeighbourMapEntry*')
3152 * @param peer id of the peer, NULL for last call
3153 * @param h hello message for the peer (can be NULL)
3154 * @param err_msg NULL if successful, otherwise contains error message
3157 add_hello_for_peer (void *cls,
3158 const struct GNUNET_PeerIdentity *peer,
3159 const struct GNUNET_HELLO_Message *h,
3160 const char *err_msg)
3162 struct NeighbourMapEntry *n = cls;
3164 if (err_msg != NULL)
3167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3168 _("Error in communication with PEERINFO service: %s\n"),
3175 GNUNET_STATISTICS_update (stats,
3176 gettext_noop ("# outstanding peerinfo iterate requests"),
3183 return; /* no HELLO available */
3185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3186 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3190 if (GNUNET_YES != n->public_key_valid)
3192 GNUNET_HELLO_get_key (h, &n->publicKey);
3193 n->public_key_valid = GNUNET_YES;
3195 GNUNET_HELLO_iterate_addresses (h,
3197 &add_to_foreign_address_list,
3203 * Create a fresh entry in our neighbour list for the given peer.
3204 * Will try to transmit our current HELLO to the new neighbour.
3205 * Do not call this function directly, use 'setup_peer_check_blacklist.
3207 * @param peer the peer for which we create the entry
3208 * @param do_hello should we schedule transmitting a HELLO
3209 * @return the new neighbour list entry
3211 static struct NeighbourMapEntry *
3212 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3215 struct NeighbourMapEntry *n;
3216 struct TransportPlugin *tp;
3217 struct ReadyList *rl;
3219 GNUNET_assert (0 != memcmp (peer,
3221 sizeof (struct GNUNET_PeerIdentity)));
3223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3224 "Setting up state for neighbour `%4s'\n",
3227 GNUNET_STATISTICS_update (stats,
3228 gettext_noop ("# active neighbours"),
3231 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3234 GNUNET_TIME_relative_to_absolute
3235 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3236 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3237 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3238 MAX_BANDWIDTH_CARRY_S);
3242 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3244 rl = GNUNET_malloc (sizeof (struct ReadyList));
3246 rl->next = n->plugins;
3249 rl->addresses = NULL;
3253 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3255 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3256 &neighbour_timeout_task, n);
3257 GNUNET_CONTAINER_multihashmap_put (neighbours,
3260 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3263 GNUNET_STATISTICS_update (stats,
3264 gettext_noop ("# peerinfo new neighbor iterate requests"),
3267 GNUNET_STATISTICS_update (stats,
3268 gettext_noop ("# outstanding peerinfo iterate requests"),
3271 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3272 GNUNET_TIME_UNIT_FOREVER_REL,
3273 &add_hello_for_peer, n);
3275 GNUNET_STATISTICS_update (stats,
3276 gettext_noop ("# HELLO's sent to new neighbors"),
3279 if (NULL != our_hello)
3280 transmit_to_peer (NULL, NULL, 0,
3281 HELLO_ADDRESS_EXPIRATION,
3282 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3290 * Function called after we have checked if communicating
3291 * with a given peer is acceptable.
3293 * @param cls closure
3294 * @param n NULL if communication is not acceptable
3296 typedef void (*SetupContinuation)(void *cls,
3297 struct NeighbourMapEntry *n);
3301 * Information kept for each client registered to perform
3307 * This is a linked list.
3309 struct Blacklisters *next;
3312 * This is a linked list.
3314 struct Blacklisters *prev;
3317 * Client responsible for this entry.
3319 struct GNUNET_SERVER_Client *client;
3322 * Blacklist check that we're currently performing.
3324 struct BlacklistCheck *bc;
3330 * Head of DLL of blacklisting clients.
3332 static struct Blacklisters *bl_head;
3335 * Tail of DLL of blacklisting clients.
3337 static struct Blacklisters *bl_tail;
3341 * Context we use when performing a blacklist check.
3343 struct BlacklistCheck
3347 * This is a linked list.
3349 struct BlacklistCheck *next;
3352 * This is a linked list.
3354 struct BlacklistCheck *prev;
3357 * Peer being checked.
3359 struct GNUNET_PeerIdentity peer;
3362 * Option for setup neighbour afterwards.
3367 * Continuation to call with the result.
3369 SetupContinuation cont;
3377 * Current transmission request handle for this client, or NULL if no
3378 * request is pending.
3380 struct GNUNET_CONNECTION_TransmitHandle *th;
3383 * Our current position in the blacklisters list.
3385 struct Blacklisters *bl_pos;
3388 * Current task performing the check.
3390 GNUNET_SCHEDULER_TaskIdentifier task;
3395 * Head of DLL of active blacklisting queries.
3397 static struct BlacklistCheck *bc_head;
3400 * Tail of DLL of active blacklisting queries.
3402 static struct BlacklistCheck *bc_tail;
3406 * Perform next action in the blacklist check.
3408 * @param cls the 'struct BlacklistCheck*'
3412 do_blacklist_check (void *cls,
3413 const struct GNUNET_SCHEDULER_TaskContext *tc);
3416 * Transmit blacklist query to the client.
3418 * @param cls the 'struct BlacklistCheck'
3419 * @param size number of bytes allowed
3420 * @param buf where to copy the message
3421 * @return number of bytes copied to buf
3424 transmit_blacklist_message (void *cls,
3428 struct BlacklistCheck *bc = cls;
3429 struct Blacklisters *bl;
3430 struct BlacklistMessage bm;
3435 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3436 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3439 "Failed to send blacklist test for peer `%s' to client\n",
3440 GNUNET_i2s (&bc->peer));
3444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3445 "Sending blacklist test for peer `%s' to client\n",
3446 GNUNET_i2s (&bc->peer));
3449 bm.header.size = htons (sizeof (struct BlacklistMessage));
3450 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3451 bm.is_allowed = htonl (0);
3453 memcpy (buf, &bm, sizeof (bm));
3454 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3460 * Perform next action in the blacklist check.
3462 * @param cls the 'struct BlacklistCheck*'
3466 do_blacklist_check (void *cls,
3467 const struct GNUNET_SCHEDULER_TaskContext *tc)
3469 struct BlacklistCheck *bc = cls;
3470 struct Blacklisters *bl;
3472 bc->task = GNUNET_SCHEDULER_NO_TASK;
3477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3478 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3479 GNUNET_i2s (&bc->peer));
3481 bc->cont (bc->cont_cls,
3482 setup_new_neighbour (&bc->peer, bc->do_hello));
3489 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3490 sizeof (struct BlacklistMessage),
3491 GNUNET_TIME_UNIT_FOREVER_REL,
3492 &transmit_blacklist_message,
3499 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3500 * does not yet exist, check the blacklist. If the blacklist says creating
3501 * one is acceptable, create one and call the continuation; otherwise
3502 * call the continuation with NULL.
3504 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3505 * @param do_hello should we also schedule sending our HELLO to the peer
3506 * if this is a new record
3507 * @param cont function to call with the 'struct NeigbhbourList*'
3508 * @param cont_cls closure for cont
3511 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3513 SetupContinuation cont,
3516 struct NeighbourMapEntry *n;
3517 struct BlacklistCheck *bc;
3519 n = find_neighbour(peer);
3523 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3524 "Neighbour record exists for peer `%s'\n",
3531 if (bl_head == NULL)
3534 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3536 setup_new_neighbour(peer, do_hello);
3539 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3540 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3542 bc->do_hello = do_hello;
3544 bc->cont_cls = cont_cls;
3545 bc->bl_pos = bl_head;
3546 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3552 * Function called with the result of querying a new blacklister about
3553 * it being allowed (or not) to continue to talk to an existing neighbour.
3555 * @param cls the original 'struct NeighbourMapEntry'
3556 * @param n NULL if we need to disconnect
3559 confirm_or_drop_neighbour (void *cls,
3560 struct NeighbourMapEntry *n)
3562 struct NeighbourMapEntry * orig = cls;
3567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3568 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3569 "confirm_or_drop_neighboUr");
3571 GNUNET_STATISTICS_update (stats,
3572 gettext_noop ("# disconnects due to blacklist"),
3575 disconnect_neighbour (orig, GNUNET_NO);
3580 struct TestConnectionContext
3584 struct Blacklisters *bl;
3589 test_connection_ok (void *cls,
3590 const GNUNET_HashCode *key,
3593 struct TestConnectionContext *tcc = cls;
3594 struct NeighbourMapEntry *n = value;
3595 struct BlacklistCheck *bc;
3598 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3599 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3601 bc->do_hello = GNUNET_NO;
3602 bc->cont = &confirm_or_drop_neighbour;
3604 bc->bl_pos = tcc->bl;
3605 if (GNUNET_YES == tcc->first)
3607 /* all would wait for the same client, no need to
3608 create more than just the first task right now */
3609 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3611 tcc->first = GNUNET_NO;
3618 * Handle a request to start a blacklist.
3620 * @param cls closure (always NULL)
3621 * @param client identification of the client
3622 * @param message the actual message
3625 handle_blacklist_init (void *cls,
3626 struct GNUNET_SERVER_Client *client,
3627 const struct GNUNET_MessageHeader *message)
3629 struct Blacklisters *bl;
3630 struct TestConnectionContext tcc;
3635 if (bl->client == client)
3638 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3643 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3644 bl->client = client;
3645 GNUNET_SERVER_client_keep (client);
3646 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3647 /* confirm that all existing connections are OK! */
3649 tcc.first = GNUNET_YES;
3650 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
3651 &test_connection_ok,
3657 * Handle a request to blacklist a peer.
3659 * @param cls closure (always NULL)
3660 * @param client identification of the client
3661 * @param message the actual message
3664 handle_blacklist_reply (void *cls,
3665 struct GNUNET_SERVER_Client *client,
3666 const struct GNUNET_MessageHeader *message)
3668 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3669 struct Blacklisters *bl;
3670 struct BlacklistCheck *bc;
3673 while ( (bl != NULL) &&
3674 (bl->client != client) )
3679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3680 "Blacklist client disconnected\n");
3682 /* FIXME: other error handling here!? */
3683 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3688 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3692 "Blacklist check failed, peer not allowed\n");
3694 bc->cont (bc->cont_cls, NULL);
3695 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3702 "Blacklist check succeeded, continuing with checks\n");
3704 bc->bl_pos = bc->bl_pos->next;
3705 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3708 /* check if any other bc's are waiting for this blacklister */
3712 if ( (bc->bl_pos == bl) &&
3713 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3714 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3722 * Send periodic PING messages to a given foreign address.
3724 * @param cls our 'struct PeriodicValidationContext*'
3725 * @param tc task context
3728 send_periodic_ping (void *cls,
3729 const struct GNUNET_SCHEDULER_TaskContext *tc)
3731 struct ForeignAddressList *peer_address = cls;
3732 struct TransportPlugin *tp;
3733 struct ValidationEntry *va;
3734 struct NeighbourMapEntry *neighbour;
3735 struct TransportPingMessage ping;
3736 struct CheckAddressExistsClosure caec;
3738 uint16_t hello_size;
3742 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3743 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3745 GNUNET_assert (peer_address != NULL);
3746 tp = peer_address->ready_list->plugin;
3747 neighbour = peer_address->ready_list->neighbour;
3748 if (GNUNET_YES != neighbour->public_key_valid)
3750 /* no public key yet, try again later */
3751 schedule_next_ping (peer_address);
3754 caec.addr = peer_address->addr;
3755 caec.addrlen = peer_address->addrlen;
3756 caec.tname = tp->short_name;
3757 caec.session = peer_address->session;
3758 caec.exists = GNUNET_NO;
3760 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3761 &check_address_exists,
3763 if (caec.exists == GNUNET_YES)
3765 /* During validation attempts we will likely trigger the other
3766 peer trying to validate our address which in turn will cause
3767 it to send us its HELLO, so we expect to hit this case rather
3768 frequently. Only print something if we are very verbose. */
3769 #if DEBUG_TRANSPORT > 1
3770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3771 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3772 (peer_address->addr != NULL)
3773 ? a2s (tp->short_name,
3775 peer_address->addrlen)
3778 GNUNET_i2s (&neighbour->id));
3780 schedule_next_ping (peer_address);
3783 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3784 va->transport_name = GNUNET_strdup (tp->short_name);
3785 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3787 va->send_time = GNUNET_TIME_absolute_get();
3788 va->session = peer_address->session;
3789 if (peer_address->addr != NULL)
3791 va->addr = (const void*) &va[1];
3792 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3793 va->addrlen = peer_address->addrlen;
3795 memcpy(&va->publicKey,
3796 &neighbour->publicKey,
3797 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3799 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3800 &timeout_hello_validation,
3802 GNUNET_CONTAINER_multihashmap_put (validation_map,
3803 &neighbour->id.hashPubKey,
3805 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3807 if (peer_address->validated != GNUNET_YES)
3808 hello_size = GNUNET_HELLO_size(our_hello);
3812 tsize = sizeof(struct TransportPingMessage) + hello_size;
3814 if (peer_address->addr != NULL)
3816 slen = strlen (tp->short_name) + 1;
3817 tsize += slen + peer_address->addrlen;
3821 slen = 0; /* make gcc happy */
3823 message_buf = GNUNET_malloc(tsize);
3824 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3825 ping.challenge = htonl(va->challenge);
3826 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3827 if (peer_address->validated != GNUNET_YES)
3829 memcpy(message_buf, our_hello, hello_size);
3832 if (peer_address->addr != NULL)
3834 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3835 peer_address->addrlen +
3837 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3840 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3842 peer_address->addrlen);
3846 ping.header.size = htons(sizeof(struct TransportPingMessage));
3849 memcpy(&message_buf[hello_size],
3851 sizeof(struct TransportPingMessage));
3853 #if DEBUG_TRANSPORT_REVALIDATION
3854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3855 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3856 (peer_address->addr != NULL)
3857 ? a2s (peer_address->plugin->short_name,
3859 peer_address->addrlen)
3862 GNUNET_i2s (&neighbour->id),
3863 "HELLO", hello_size,
3866 if (peer_address->validated != GNUNET_YES)
3867 GNUNET_STATISTICS_update (stats,
3868 gettext_noop ("# PING with HELLO messages sent"),
3872 GNUNET_STATISTICS_update (stats,
3873 gettext_noop ("# PING without HELLO messages sent"),
3876 GNUNET_STATISTICS_update (stats,
3877 gettext_noop ("# PING messages sent for re-validation"),
3880 transmit_to_peer (NULL, peer_address,
3881 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3882 HELLO_VERIFICATION_TIMEOUT,
3884 GNUNET_YES, neighbour);
3885 GNUNET_free (message_buf);
3886 schedule_next_ping (peer_address);
3891 * Schedule the job that will cause us to send a PING to the
3892 * foreign address to evaluate its validity and latency.
3894 * @param fal address to PING
3897 schedule_next_ping (struct ForeignAddressList *fal)
3899 struct GNUNET_TIME_Relative delay;
3901 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3903 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3904 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3906 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3907 delay.rel_value /= 2; /* do before expiration */
3908 delay = GNUNET_TIME_relative_min (delay,
3909 LATENCY_EVALUATION_MAX_DELAY);
3910 if (GNUNET_YES != fal->estimated)
3912 delay = GNUNET_TIME_UNIT_ZERO;
3913 fal->estimated = GNUNET_YES;
3916 if (GNUNET_YES == fal->connected)
3918 delay = GNUNET_TIME_relative_min (delay,
3919 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3921 /* FIXME: also adjust delay based on how close the last
3922 observed latency is to the latency of the best alternative */
3923 /* bound how fast we can go */
3924 delay = GNUNET_TIME_relative_max (delay,
3925 GNUNET_TIME_UNIT_SECONDS);
3926 /* randomize a bit (to avoid doing all at the same time) */
3927 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3929 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3930 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3931 &send_periodic_ping,
3939 * Function that will be called if we receive some payload
3940 * from another peer.
3942 * @param message the payload
3943 * @param n peer who claimed to be the sender
3946 handle_payload_message (const struct GNUNET_MessageHeader *message,
3947 struct NeighbourMapEntry *n)
3949 struct InboundMessage *im;
3950 struct TransportClient *cpos;
3953 msize = ntohs (message->size);
3954 if (n->received_pong == GNUNET_NO)
3957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3958 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3959 ntohs (message->type),
3960 ntohs (message->size),
3961 GNUNET_i2s (&n->id));
3963 GNUNET_free_non_null (n->pre_connect_message_buffer);
3964 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3965 memcpy (n->pre_connect_message_buffer, message, msize);
3970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3971 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3972 ntohs (message->type),
3973 ntohs (message->size),
3974 GNUNET_i2s (&n->id));
3976 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3979 n->quota_violation_count++;
3981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3982 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3983 n->in_tracker.available_bytes_per_s__,
3984 n->quota_violation_count);
3986 /* Discount 32k per violation */
3987 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3992 if (n->quota_violation_count > 0)
3994 /* try to add 32k back */
3995 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3997 n->quota_violation_count--;
4000 GNUNET_STATISTICS_update (stats,
4001 gettext_noop ("# payload received from other peers"),
4004 /* transmit message to all clients */
4005 uint32_t ats_count = 2;
4006 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
4007 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4010 im = GNUNET_malloc (size);
4011 im->header.size = htons (size);
4012 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4014 im->ats_count = htonl(ats_count);
4015 /* Setting ATS data */
4016 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4017 (&(im->ats))[0].value = htonl (n->distance);
4018 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4019 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4020 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4021 (&(im->ats))[ats_count].value = htonl (0);
4023 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
4025 while (cpos != NULL)
4027 transmit_to_client (cpos, &im->header, GNUNET_YES);
4035 * Iterator over hash map entries. Checks if the given validation
4036 * entry is for the same challenge as what is given in the PONG.
4038 * @param cls the 'struct TransportPongMessage*'
4039 * @param key peer identity
4040 * @param value value in the hash map ('struct ValidationEntry')
4041 * @return GNUNET_YES if we should continue to
4042 * iterate (mismatch), GNUNET_NO if not (entry matched)
4045 check_pending_validation (void *cls,
4046 const GNUNET_HashCode * key,
4049 const struct TransportPongMessage *pong = cls;
4050 struct ValidationEntry *ve = value;
4051 struct AddValidatedAddressContext avac;
4052 unsigned int challenge = ntohl(pong->challenge);
4053 struct GNUNET_HELLO_Message *hello;
4054 struct GNUNET_PeerIdentity target;
4055 struct NeighbourMapEntry *n;
4056 struct ForeignAddressList *fal;
4057 struct OwnAddressList *oal;
4058 struct TransportPlugin *tp;
4059 struct GNUNET_MessageHeader *prem;
4065 ps = ntohs (pong->header.size);
4066 if (ps < sizeof (struct TransportPongMessage))
4068 GNUNET_break_op (0);
4071 addr = (const char*) &pong[1];
4072 slen = strlen (ve->transport_name) + 1;
4073 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4074 (ve->challenge != challenge) ||
4075 (addr[slen-1] != '\0') ||
4076 (0 != strcmp (addr, ve->transport_name)) ||
4077 (ntohl (pong->purpose.size)
4078 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4080 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4081 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4086 alen = ps - sizeof (struct TransportPongMessage) - slen;
4087 switch (ntohl (pong->purpose.purpose))
4089 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4090 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4091 (0 != memcmp (&addr[slen],
4095 return GNUNET_YES; /* different entry, keep trying! */
4097 if (0 != memcmp (&pong->pid,
4099 sizeof (struct GNUNET_PeerIdentity)))
4101 GNUNET_break_op (0);
4105 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4110 GNUNET_break_op (0);
4115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4116 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4118 a2s (ve->transport_name,
4119 (const struct sockaddr *) ve->addr,
4121 ve->transport_name);
4124 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4125 if (0 != memcmp (&pong->pid,
4127 sizeof (struct GNUNET_PeerIdentity)))
4131 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4134 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4135 GNUNET_i2s (&my_identity),
4141 if (ve->addrlen != 0)
4143 /* must have been for a different validation entry */
4146 tp = find_transport (ve->transport_name);
4152 oal = tp->addresses;
4155 if ( (oal->addrlen == alen) &&
4156 (0 == memcmp (&oal[1],
4164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4165 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4166 GNUNET_i2s (&pong->pid),
4167 a2s (ve->transport_name,
4170 /* FIXME: since the sender of the PONG currently uses the
4171 wrong address (see FIMXE there!), we cannot run a
4172 proper check here... */
4178 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4183 GNUNET_break_op (0);
4188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4189 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4191 a2s (ve->transport_name,
4194 ve->transport_name);
4198 GNUNET_break_op (0);
4201 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4203 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4204 _("Received expired signature. Check system time.\n"));
4207 GNUNET_STATISTICS_update (stats,
4208 gettext_noop ("# address validation successes"),
4211 /* create the updated HELLO */
4212 GNUNET_CRYPTO_hash (&ve->publicKey,
4213 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4214 &target.hashPubKey);
4215 if (ve->addr != NULL)
4217 avac.done = GNUNET_NO;
4219 hello = GNUNET_HELLO_create (&ve->publicKey,
4220 &add_validated_address,
4222 GNUNET_PEERINFO_add_peer (peerinfo,
4224 GNUNET_free (hello);
4226 n = find_neighbour (&target);
4229 n->publicKey = ve->publicKey;
4230 n->public_key_valid = GNUNET_YES;
4231 fal = add_peer_address (n,
4236 GNUNET_assert (fal != NULL);
4237 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4238 fal->validated = GNUNET_YES;
4239 mark_address_connected (fal);
4240 GNUNET_STATISTICS_update (stats,
4241 gettext_noop ("# peer addresses considered valid"),
4244 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4245 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4247 schedule_next_ping (fal);
4248 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4249 n->latency = fal->latency;
4251 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4253 n->distance = fal->distance;
4254 if (GNUNET_NO == n->received_pong)
4256 n->received_pong = GNUNET_YES;
4257 notify_clients_connect (&target, n->latency, n->distance);
4258 if (NULL != (prem = n->pre_connect_message_buffer))
4260 n->pre_connect_message_buffer = NULL;
4261 handle_payload_message (prem, n);
4265 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4267 GNUNET_SCHEDULER_cancel (n->retry_task);
4268 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4269 try_transmission_to_peer (n);
4273 /* clean up validation entry */
4274 GNUNET_assert (GNUNET_YES ==
4275 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4278 abort_validation (NULL, NULL, ve);
4284 * Function that will be called if we receive a validation
4285 * of an address challenge that we transmitted to another
4286 * peer. Note that the validation should only be considered
4287 * acceptable if the challenge matches AND if the sender
4288 * address is at least a plausible address for this peer
4289 * (otherwise we may be seeing a MiM attack).
4291 * @param cls closure
4292 * @param message the pong message
4293 * @param peer who responded to our challenge
4294 * @param sender_address string describing our sender address (as observed
4295 * by the other peer in binary format)
4296 * @param sender_address_len number of bytes in 'sender_address'
4299 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4300 const struct GNUNET_PeerIdentity *peer,
4301 const char *sender_address,
4302 size_t sender_address_len)
4304 if (0 == memcmp (peer,
4306 sizeof (struct GNUNET_PeerIdentity)))
4308 /* PONG send to self, ignore */
4309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4310 "Receiving `%s' message from myself\n",
4314 #if DEBUG_TRANSPORT > 1
4315 /* we get tons of these that just get discarded, only log
4316 if we are quite verbose */
4317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4318 "Receiving `%s' message from `%4s'.\n", "PONG",
4321 GNUNET_STATISTICS_update (stats,
4322 gettext_noop ("# PONG messages received"),
4325 if (GNUNET_SYSERR !=
4326 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4328 &check_pending_validation,
4331 /* This is *expected* to happen a lot since we send
4332 PONGs to *all* known addresses of the sender of
4333 the PING, so most likely we get multiple PONGs
4334 per PING, and all but the first PONG will end up
4335 here. So really we should not print anything here
4336 unless we want to be very, very verbose... */
4337 #if DEBUG_TRANSPORT > 2
4338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4339 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4351 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4353 * @param cls the 'struct ValidationEntry*'
4354 * @param neighbour neighbour to validate, NULL if validation failed
4357 transmit_hello_and_ping (void *cls,
4358 struct NeighbourMapEntry *neighbour)
4360 struct ValidationEntry *va = cls;
4361 struct ForeignAddressList *peer_address;
4362 struct TransportPingMessage ping;
4363 uint16_t hello_size;
4366 struct GNUNET_PeerIdentity id;
4369 GNUNET_CRYPTO_hash (&va->publicKey,
4370 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4372 if (neighbour == NULL)
4374 /* FIXME: stats... */
4375 GNUNET_break (GNUNET_OK ==
4376 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4379 abort_validation (NULL, NULL, va);
4382 neighbour->publicKey = va->publicKey;
4383 neighbour->public_key_valid = GNUNET_YES;
4384 peer_address = add_peer_address (neighbour,
4385 va->transport_name, NULL,
4386 (const void*) &va[1],
4388 if (peer_address == NULL)
4390 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4391 "Failed to add peer `%4s' for plugin `%s'\n",
4392 GNUNET_i2s (&neighbour->id),
4393 va->transport_name);
4394 GNUNET_break (GNUNET_OK ==
4395 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4398 abort_validation (NULL, NULL, va);
4401 if (NULL == our_hello)
4402 refresh_hello_task (NULL, NULL);
4403 hello_size = GNUNET_HELLO_size(our_hello);
4404 slen = strlen(va->transport_name) + 1;
4405 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4406 message_buf = GNUNET_malloc(tsize);
4407 ping.challenge = htonl(va->challenge);
4408 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4409 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4410 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4411 memcpy(message_buf, our_hello, hello_size);
4412 memcpy(&message_buf[hello_size],
4414 sizeof(struct TransportPingMessage));
4415 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4418 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4423 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4426 : a2s (va->transport_name,
4427 (const void*) &va[1], va->addrlen),
4429 GNUNET_i2s (&neighbour->id),
4430 "HELLO", hello_size,
4431 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4434 GNUNET_STATISTICS_update (stats,
4435 gettext_noop ("# PING messages sent for initial validation"),
4438 transmit_to_peer (NULL, peer_address,
4439 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4440 HELLO_VERIFICATION_TIMEOUT,
4442 GNUNET_YES, neighbour);
4443 GNUNET_free (message_buf);
4448 * Check if the given address is already being validated; if not,
4449 * append the given address to the list of entries that are being be
4450 * validated and initiate validation.
4452 * @param cls closure ('struct CheckHelloValidatedContext *')
4453 * @param tname name of the transport
4454 * @param expiration expiration time
4455 * @param addr the address
4456 * @param addrlen length of the address
4457 * @return GNUNET_OK (always)
4460 run_validation (void *cls,
4462 struct GNUNET_TIME_Absolute expiration,
4466 struct CheckHelloValidatedContext *chvc = cls;
4467 struct GNUNET_PeerIdentity id;
4468 struct TransportPlugin *tp;
4469 struct ValidationEntry *va;
4470 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4471 struct CheckAddressExistsClosure caec;
4472 struct OwnAddressList *oal;
4474 GNUNET_assert (addr != NULL);
4476 GNUNET_STATISTICS_update (stats,
4477 gettext_noop ("# peer addresses scheduled for validation"),
4480 tp = find_transport (tname);
4483 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4484 GNUNET_ERROR_TYPE_BULK,
4486 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4488 GNUNET_STATISTICS_update (stats,
4489 gettext_noop ("# peer addresses not validated (plugin not available)"),
4494 /* check if this is one of our own addresses */
4495 oal = tp->addresses;
4498 if ( (oal->addrlen == addrlen) &&
4499 (0 == memcmp (&oal[1],
4503 /* not plausible, this address is equivalent to our own address! */
4504 GNUNET_STATISTICS_update (stats,
4505 gettext_noop ("# peer addresses not validated (loopback)"),
4512 GNUNET_HELLO_get_key (chvc->hello, &pk);
4513 GNUNET_CRYPTO_hash (&pk,
4515 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4518 if (is_blacklisted(&id, tp))
4521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4522 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4530 caec.addrlen = addrlen;
4531 caec.session = NULL;
4533 caec.exists = GNUNET_NO;
4534 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4535 &check_address_exists,
4537 if (caec.exists == GNUNET_YES)
4539 /* During validation attempts we will likely trigger the other
4540 peer trying to validate our address which in turn will cause
4541 it to send us its HELLO, so we expect to hit this case rather
4542 frequently. Only print something if we are very verbose. */
4543 #if DEBUG_TRANSPORT > 1
4544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4545 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4546 a2s (tname, addr, addrlen),
4550 GNUNET_STATISTICS_update (stats,
4551 gettext_noop ("# peer addresses not validated (in progress)"),
4556 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4559 va->transport_name = GNUNET_strdup (tname);
4560 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4562 va->send_time = GNUNET_TIME_absolute_get();
4563 va->addr = (const void*) &va[1];
4564 memcpy (&va[1], addr, addrlen);
4565 va->addrlen = addrlen;
4566 GNUNET_HELLO_get_key (chvc->hello,
4568 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4569 &timeout_hello_validation,
4571 GNUNET_CONTAINER_multihashmap_put (validation_map,
4574 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4575 setup_peer_check_blacklist (&id, GNUNET_NO,
4576 &transmit_hello_and_ping,
4583 * Check if addresses in validated hello "h" overlap with
4584 * those in "chvc->hello" and validate the rest.
4586 * @param cls closure
4587 * @param peer id of the peer, NULL for last call
4588 * @param h hello message for the peer (can be NULL)
4589 * @param err_msg NULL if successful, otherwise contains error message
4592 check_hello_validated (void *cls,
4593 const struct GNUNET_PeerIdentity *peer,
4594 const struct GNUNET_HELLO_Message *h,
4595 const char *err_msg)
4597 struct CheckHelloValidatedContext *chvc = cls;
4598 struct GNUNET_HELLO_Message *plain_hello;
4599 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4600 struct GNUNET_PeerIdentity target;
4601 struct NeighbourMapEntry *n;
4603 if (err_msg != NULL)
4606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4607 _("Error in communication with PEERINFO service: %s\n"),
4615 GNUNET_STATISTICS_update (stats,
4616 gettext_noop ("# outstanding peerinfo iterate requests"),
4620 if (GNUNET_NO == chvc->hello_known)
4622 /* notify PEERINFO about the peer now, so that we at least
4623 have the public key if some other component needs it */
4624 GNUNET_HELLO_get_key (chvc->hello, &pk);
4625 GNUNET_CRYPTO_hash (&pk,
4626 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4627 &target.hashPubKey);
4628 plain_hello = GNUNET_HELLO_create (&pk,
4631 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4632 GNUNET_free (plain_hello);
4633 #if DEBUG_TRANSPORT_HELLO
4634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4635 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4637 GNUNET_i2s (&target));
4639 GNUNET_STATISTICS_update (stats,
4640 gettext_noop ("# new HELLOs requiring full validation"),
4643 GNUNET_HELLO_iterate_addresses (chvc->hello,
4650 GNUNET_STATISTICS_update (stats,
4651 gettext_noop ("# duplicate HELLO (peer known)"),
4656 if (chvc->ve_count == 0)
4658 GNUNET_CONTAINER_DLL_remove (chvc_head,
4667 #if DEBUG_TRANSPORT_HELLO
4668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4669 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4673 chvc->hello_known = GNUNET_YES;
4674 n = find_neighbour (peer);
4677 #if DEBUG_TRANSPORT_HELLO
4678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4679 "Calling hello_iterate_addresses for %s!\n",
4682 GNUNET_HELLO_iterate_addresses (h,
4684 &add_to_foreign_address_list,
4686 try_transmission_to_peer (n);
4690 #if DEBUG_TRANSPORT_HELLO
4691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4692 "No existing neighbor record for %s!\n",
4695 GNUNET_STATISTICS_update (stats,
4696 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4700 GNUNET_STATISTICS_update (stats,
4701 gettext_noop ("# HELLO validations (update case)"),
4704 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4706 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4713 * Process HELLO-message.
4715 * @param plugin transport involved, may be NULL
4716 * @param message the actual message
4717 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4720 process_hello (struct TransportPlugin *plugin,
4721 const struct GNUNET_MessageHeader *message)
4724 struct GNUNET_PeerIdentity target;
4725 const struct GNUNET_HELLO_Message *hello;
4726 struct CheckHelloValidatedContext *chvc;
4727 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4728 struct NeighbourMapEntry *n;
4729 #if DEBUG_TRANSPORT_HELLO > 2
4733 hsize = ntohs (message->size);
4734 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4735 (hsize < sizeof (struct GNUNET_MessageHeader)))
4738 return GNUNET_SYSERR;
4740 GNUNET_STATISTICS_update (stats,
4741 gettext_noop ("# HELLOs received for validation"),
4745 hello = (const struct GNUNET_HELLO_Message *) message;
4746 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4748 #if DEBUG_TRANSPORT_HELLO
4749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4750 "Unable to get public key from `%s' for `%4s'!\n",
4752 GNUNET_i2s (&target));
4754 GNUNET_break_op (0);
4755 return GNUNET_SYSERR;
4757 GNUNET_CRYPTO_hash (&publicKey,
4758 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4759 &target.hashPubKey);
4761 #if DEBUG_TRANSPORT_HELLO
4762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4763 "Received `%s' message for `%4s'\n",
4765 GNUNET_i2s (&target));
4767 if (0 == memcmp (&my_identity,
4769 sizeof (struct GNUNET_PeerIdentity)))
4771 GNUNET_STATISTICS_update (stats,
4772 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4777 n = find_neighbour (&target);
4779 (! n->public_key_valid) )
4781 GNUNET_HELLO_get_key (hello, &n->publicKey);
4782 n->public_key_valid = GNUNET_YES;
4785 /* check if load is too high before doing expensive stuff */
4786 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4788 GNUNET_STATISTICS_update (stats,
4789 gettext_noop ("# HELLOs ignored due to high load"),
4792 #if DEBUG_TRANSPORT_HELLO
4793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4794 "Ignoring `%s' for `%4s', load too high.\n",
4796 GNUNET_i2s (&target));
4803 while (NULL != chvc)
4805 if (GNUNET_HELLO_equals (hello,
4807 GNUNET_TIME_absolute_get ()).abs_value > 0)
4809 #if DEBUG_TRANSPORT_HELLO > 2
4810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4811 "Received duplicate `%s' message for `%4s'; ignored\n",
4813 GNUNET_i2s (&target));
4815 return GNUNET_OK; /* validation already pending */
4817 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4818 GNUNET_break (0 != memcmp (hello, chvc->hello,
4819 GNUNET_HELLO_size(hello)));
4824 struct NeighbourMapEntry *temp_neighbor = find_neighbour(&target);
4825 if ((NULL != temp_neighbor))
4827 fprintf(stderr, "Already know peer, ignoring hello\n");
4832 #if DEBUG_TRANSPORT_HELLO > 2
4836 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4838 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4841 GNUNET_i2s (&target),
4843 GNUNET_HELLO_size(hello));
4844 GNUNET_free (my_id);
4848 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4850 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4851 memcpy (&chvc[1], hello, hsize);
4852 GNUNET_CONTAINER_DLL_insert (chvc_head,
4855 /* finally, check if HELLO was previously validated
4856 (continuation will then schedule actual validation) */
4857 GNUNET_STATISTICS_update (stats,
4858 gettext_noop ("# peerinfo process hello iterate requests"),
4861 GNUNET_STATISTICS_update (stats,
4862 gettext_noop ("# outstanding peerinfo iterate requests"),
4865 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4867 HELLO_VERIFICATION_TIMEOUT,
4868 &check_hello_validated, chvc);
4874 * The peer specified by the given neighbour has timed-out or a plugin
4875 * has disconnected. We may either need to do nothing (other plugins
4876 * still up), or trigger a full disconnect and clean up. This
4877 * function updates our state and does the necessary notifications.
4878 * Also notifies our clients that the neighbour is now officially
4881 * @param n the neighbour list entry for the peer
4882 * @param check GNUNET_YES to check if ALL addresses for this peer
4883 * are gone, GNUNET_NO to force a disconnect of the peer
4884 * regardless of whether other addresses exist.
4887 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4889 struct ReadyList *rpos;
4890 struct MessageQueue *mq;
4891 struct ForeignAddressList *peer_addresses;
4892 struct ForeignAddressList *peer_pos;
4894 if (GNUNET_YES == n->in_disconnect)
4896 if (GNUNET_YES == check)
4899 while (NULL != rpos)
4901 peer_addresses = rpos->addresses;
4902 while (peer_addresses != NULL)
4904 /* Do not disconnect if: an address is connected or an inbound address exists */
4905 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4909 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4910 GNUNET_i2s (&n->id),
4911 a2s (peer_addresses->ready_list->plugin->short_name,
4912 peer_addresses->addr,
4913 peer_addresses->addrlen));
4915 return; /* still connected */
4917 peer_addresses = peer_addresses->next;
4923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4924 "Disconnecting from `%4s'\n",
4925 GNUNET_i2s (&n->id));
4927 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4929 /* notify all clients about disconnect */
4930 if (GNUNET_YES == n->received_pong)
4932 n->received_pong = GNUNET_NO;
4933 notify_clients_disconnect (&n->id);
4936 ats_modify_problem_state(ats, ATS_MODIFIED);
4938 /* clean up all plugins, cancel connections and pending transmissions */
4939 while (NULL != (rpos = n->plugins))
4941 n->plugins = rpos->next;
4942 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4943 while (rpos->addresses != NULL)
4945 peer_pos = rpos->addresses;
4946 rpos->addresses = peer_pos->next;
4947 if (peer_pos->connected == GNUNET_YES)
4949 GNUNET_STATISTICS_update (stats,
4950 gettext_noop ("# connected addresses"),
4953 peer_pos->connected = GNUNET_NO;
4955 if (GNUNET_YES == peer_pos->validated)
4956 GNUNET_STATISTICS_update (stats,
4957 gettext_noop ("# peer addresses considered valid"),
4960 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4962 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4963 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4965 GNUNET_free (peer_pos->ressources);
4966 peer_pos->ressources = NULL;
4967 GNUNET_free (peer_pos->quality);
4968 peer_pos->ressources = NULL;
4969 GNUNET_free (peer_pos);
4974 /* free all messages on the queue */
4975 while (NULL != (mq = n->messages_head))
4977 GNUNET_STATISTICS_update (stats,
4978 gettext_noop ("# bytes in message queue for other peers"),
4979 - (int64_t) mq->message_buf_size,
4981 GNUNET_STATISTICS_update (stats,
4982 gettext_noop ("# bytes discarded due to disconnect"),
4983 mq->message_buf_size,
4985 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4988 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4990 sizeof(struct GNUNET_PeerIdentity)));
4994 while (NULL != (mq = n->cont_head))
4997 GNUNET_CONTAINER_DLL_remove (n->cont_head,
5000 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
5002 sizeof(struct GNUNET_PeerIdentity)));
5006 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
5008 GNUNET_SCHEDULER_cancel (n->timeout_task);
5009 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
5011 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
5013 GNUNET_SCHEDULER_cancel (n->retry_task);
5014 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
5016 if (n->piter != NULL)
5018 GNUNET_PEERINFO_iterate_cancel (n->piter);
5019 GNUNET_STATISTICS_update (stats,
5020 gettext_noop ("# outstanding peerinfo iterate requests"),
5026 GNUNET_assert (GNUNET_OK ==
5027 GNUNET_CONTAINER_multihashmap_remove (neighbours,
5030 /* finally, free n itself */
5031 GNUNET_STATISTICS_update (stats,
5032 gettext_noop ("# active neighbours"),
5035 GNUNET_free_non_null (n->pre_connect_message_buffer);
5041 * We have received a PING message from someone. Need to send a PONG message
5042 * in response to the peer by any means necessary.
5045 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5046 const struct GNUNET_PeerIdentity *peer,
5047 struct Session *session,
5048 const char *sender_address,
5049 uint16_t sender_address_len)
5051 struct TransportPlugin *plugin = cls;
5052 struct SessionHeader *session_header = (struct SessionHeader*) session;
5053 struct TransportPingMessage *ping;
5054 struct TransportPongMessage *pong;
5055 struct NeighbourMapEntry *n;
5056 struct ReadyList *rl;
5057 struct ForeignAddressList *fal;
5058 struct OwnAddressList *oal;
5064 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5066 GNUNET_break_op (0);
5067 return GNUNET_SYSERR;
5070 ping = (struct TransportPingMessage *) message;
5071 if (0 != memcmp (&ping->target,
5072 plugin->env.my_identity,
5073 sizeof (struct GNUNET_PeerIdentity)))
5076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5077 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5079 (sender_address != NULL)
5080 ? a2s (plugin->short_name,
5081 (const struct sockaddr *)sender_address,
5084 GNUNET_i2s (&ping->target));
5086 return GNUNET_SYSERR;
5089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5090 "Processing `%s' from `%s'\n",
5092 (sender_address != NULL)
5093 ? a2s (plugin->short_name,
5094 (const struct sockaddr *)sender_address,
5098 GNUNET_STATISTICS_update (stats,
5099 gettext_noop ("# PING messages received"),
5102 addr = (const char*) &ping[1];
5103 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5104 slen = strlen (plugin->short_name) + 1;
5107 /* peer wants to confirm that we have an outbound connection to him */
5108 if (session == NULL)
5110 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5111 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5113 return GNUNET_SYSERR;
5115 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5116 1) it is NULL when we need to have a real value
5117 2) it is documented to be the address of the sender (source-IP), where
5118 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5122 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5123 a2s (plugin->short_name,
5125 sender_address_len),
5128 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5129 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5130 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5131 pong->purpose.size =
5132 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5134 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5135 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5136 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5137 pong->challenge = ping->challenge;
5138 pong->addrlen = htonl(sender_address_len + slen);
5141 sizeof(struct GNUNET_PeerIdentity));
5145 if ((sender_address!=NULL) && (sender_address_len > 0))
5146 memcpy (&((char*)&pong[1])[slen],
5148 sender_address_len);
5149 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5151 /* create / update cached sig */
5153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5154 "Creating PONG signature to indicate active connection.\n");
5156 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5157 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5158 GNUNET_assert (GNUNET_OK ==
5159 GNUNET_CRYPTO_rsa_sign (my_private_key,
5161 &session_header->pong_signature));
5165 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5167 memcpy (&pong->signature,
5168 &session_header->pong_signature,
5169 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5175 /* peer wants to confirm that this is one of our addresses */
5179 plugin->api->check_address (plugin->api->cls,
5183 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5184 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5185 a2s (plugin->short_name,
5190 oal = plugin->addresses;
5193 if ( (oal->addrlen == alen) &&
5200 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5201 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5202 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5203 pong->purpose.size =
5204 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5206 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5207 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5208 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5209 pong->challenge = ping->challenge;
5210 pong->addrlen = htonl(alen + slen);
5213 sizeof(struct GNUNET_PeerIdentity));
5214 memcpy (&pong[1], plugin->short_name, slen);
5215 memcpy (&((char*)&pong[1])[slen], addr, alen);
5216 if ( (oal != NULL) &&
5217 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5219 /* create / update cached sig */
5221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5222 "Creating PONG signature to indicate ownership.\n");
5224 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5225 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5226 GNUNET_assert (GNUNET_OK ==
5227 GNUNET_CRYPTO_rsa_sign (my_private_key,
5229 &oal->pong_signature));
5230 memcpy (&pong->signature,
5231 &oal->pong_signature,
5232 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5234 else if (oal == NULL)
5236 /* not using cache (typically DV-only) */
5237 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5238 GNUNET_assert (GNUNET_OK ==
5239 GNUNET_CRYPTO_rsa_sign (my_private_key,
5245 /* can used cached version */
5246 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5247 memcpy (&pong->signature,
5248 &oal->pong_signature,
5249 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5252 n = find_neighbour(peer);
5253 GNUNET_assert (n != NULL);
5254 did_pong = GNUNET_NO;
5255 /* first try reliable response transmission */
5259 fal = rl->addresses;
5262 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5265 ntohs (pong->header.size),
5266 TRANSPORT_PONG_PRIORITY,
5267 HELLO_VERIFICATION_TIMEOUT,
5274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5275 "Transmitted PONG to `%s' via reliable mechanism\n",
5278 GNUNET_STATISTICS_update (stats,
5279 gettext_noop ("# PONGs unicast via reliable transport"),
5285 did_pong = GNUNET_YES;
5290 /* no reliable method found, do multicast */
5291 GNUNET_STATISTICS_update (stats,
5292 gettext_noop ("# PONGs multicast to all available addresses"),
5298 fal = rl->addresses;
5301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5302 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5304 a2s (rl->plugin->short_name,
5307 rl->plugin->short_name);
5308 transmit_to_peer(NULL, fal,
5309 TRANSPORT_PONG_PRIORITY,
5310 HELLO_VERIFICATION_TIMEOUT,
5312 ntohs(pong->header.size),
5315 did_pong = GNUNET_YES;
5321 if (GNUNET_YES != did_pong)
5322 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5323 _("Could not send PONG to `%s': no address available\n"),
5330 * Function called by the plugin for each received message. Update
5331 * data volumes, possibly notify plugins about reducing the rate at
5332 * which they read from the socket and generally forward to our
5335 * @param cls the "struct TransportPlugin *" we gave to the plugin
5336 * @param peer (claimed) identity of the other peer
5337 * @param message the message, NULL if we only care about
5338 * learning about the delay until we should receive again
5339 * @param ats_data information for automatic transport selection
5340 * @param ats_count number of elements in ats not including 0-terminator
5341 * @param session identifier used for this session (can be NULL)
5342 * @param sender_address binary address of the sender (if observed)
5343 * @param sender_address_len number of bytes in sender_address
5344 * @return how long in ms the plugin should wait until receiving more data
5345 * (plugins that do not support this, can ignore the return value)
5347 static struct GNUNET_TIME_Relative
5348 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5349 const struct GNUNET_MessageHeader *message,
5350 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5352 struct Session *session,
5353 const char *sender_address,
5354 uint16_t sender_address_len)
5356 struct TransportPlugin *plugin = cls;
5357 struct ReadyList *service_context;
5358 struct ForeignAddressList *peer_address;
5360 struct NeighbourMapEntry *n;
5361 struct GNUNET_TIME_Relative ret;
5365 if (0 == memcmp (peer,
5367 sizeof (struct GNUNET_PeerIdentity)))
5369 /* refuse to receive from myself */
5371 return GNUNET_TIME_UNIT_FOREVER_REL;
5373 if (is_blacklisted (peer, plugin))
5374 return GNUNET_TIME_UNIT_FOREVER_REL;
5375 n = find_neighbour (peer);
5377 n = setup_new_neighbour (peer, GNUNET_YES);
5378 service_context = n->plugins;
5379 while ((service_context != NULL) && (plugin != service_context->plugin))
5380 service_context = service_context->next;
5381 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5382 peer_address = NULL;
5385 for (c=0; c<ats_count; c++)
5386 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5387 distance = ntohl(ats_data[c].value);
5390 if (message != NULL)
5392 if ( (session != NULL) ||
5393 (sender_address != NULL) )
5394 peer_address = add_peer_address (n,
5398 sender_address_len);
5399 if (peer_address != NULL)
5401 update_addr_ats(peer_address, ats_data, ats_count);
5402 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5404 peer_address->distance = distance;
5405 if (GNUNET_YES == peer_address->validated)
5407 mark_address_connected (peer_address);
5408 schedule_next_ping (peer_address);
5413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5414 "New address is unvalidated, trying to validate it now\n");
5416 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5418 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5419 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5421 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5424 peer_address->timeout
5425 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5427 /* update traffic received amount ... */
5428 msize = ntohs (message->size);
5430 GNUNET_STATISTICS_update (stats,
5431 gettext_noop ("# bytes received from other peers"),
5434 n->distance = distance;
5436 GNUNET_TIME_relative_to_absolute
5437 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5438 GNUNET_SCHEDULER_cancel (n->timeout_task);
5440 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5441 &neighbour_timeout_task, n);
5442 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5444 /* dropping message due to frequent inbound volume violations! */
5445 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5446 GNUNET_ERROR_TYPE_BULK,
5448 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5449 n->in_tracker.available_bytes_per_s__,
5450 n->quota_violation_count);
5451 GNUNET_STATISTICS_update (stats,
5452 gettext_noop ("# bandwidth quota violations by other peers"),
5455 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5457 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5458 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5461 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5462 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5463 /* Force ressource and quality update */
5464 if ((value == 4) && (ats != NULL))
5465 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5466 /* Force cost update */
5467 if ((value == 3) && (ats != NULL))
5468 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5469 /* Force quality update */
5470 if ((value == 2) && (ats != NULL))
5471 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5472 /* Force full rebuild */
5473 if ((value == 1) && (ats != NULL))
5474 ats_modify_problem_state(ats, ATS_MODIFIED);
5479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5480 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5481 ntohs (message->type),
5482 ntohs (message->size),
5485 switch (ntohs (message->type))
5487 case GNUNET_MESSAGE_TYPE_HELLO:
5488 GNUNET_STATISTICS_update (stats,
5489 gettext_noop ("# HELLO messages received from other peers"),
5492 process_hello (plugin, message);
5494 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5495 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5496 if (GNUNET_YES != n->received_pong)
5497 transmit_plain_ping (n);
5499 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5500 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5502 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5505 handle_payload_message (message, n);
5509 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5510 if (ret.rel_value > 0)
5513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5514 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5515 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5516 (unsigned int) n->in_tracker.available_bytes_per_s__,
5517 (unsigned long long) ret.rel_value);
5519 GNUNET_STATISTICS_update (stats,
5520 gettext_noop ("# ms throttling suggested"),
5521 (int64_t) ret.rel_value,
5529 notify_client_about_neighbour (void *cls,
5530 const GNUNET_HashCode *key,
5533 struct TransportClient *c = cls;
5534 struct NeighbourMapEntry *n = value;
5535 struct ConnectInfoMessage * cim;
5539 if (GNUNET_YES != n->received_pong)
5543 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5544 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5545 cim = GNUNET_malloc (size);
5546 cim->header.size = htons (size);
5547 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5548 cim->ats_count = htonl(ats_count);
5549 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5550 (&(cim->ats))[2].value = htonl (0);
5551 if (GNUNET_YES == n->received_pong)
5553 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5554 (&cim->ats)[0].value = htonl (n->distance);
5555 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5556 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5558 transmit_to_client (c, &cim->header, GNUNET_NO);
5566 * Handle START-message. This is the first message sent to us
5567 * by any client which causes us to add it to our list.
5569 * @param cls closure (always NULL)
5570 * @param client identification of the client
5571 * @param message the actual message
5574 handle_start (void *cls,
5575 struct GNUNET_SERVER_Client *client,
5576 const struct GNUNET_MessageHeader *message)
5578 const struct StartMessage *start;
5579 struct TransportClient *c;
5581 start = (const struct StartMessage*) message;
5583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5584 "Received `%s' request from client\n", "START");
5589 if (c->client == client)
5591 /* client already on our list! */
5593 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5598 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5599 (0 != memcmp (&start->self,
5601 sizeof (struct GNUNET_PeerIdentity))) )
5603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5604 _("Rejecting control connection from peer `%s', which is not me!\n"),
5605 GNUNET_i2s (&start->self));
5606 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5609 c = GNUNET_malloc (sizeof (struct TransportClient));
5613 if (our_hello != NULL)
5616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5617 "Sending our own `%s' to new client\n", "HELLO");
5619 transmit_to_client (c,
5620 (const struct GNUNET_MessageHeader *) our_hello,
5622 /* tell new client about all existing connections */
5623 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5624 ¬ify_client_about_neighbour,
5629 #if DEBUG_TRANSPORT_HELLO
5630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5631 "No HELLO created yet, will transmit HELLO to client later!\n");
5635 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5640 * Handle HELLO-message.
5642 * @param cls closure (always NULL)
5643 * @param client identification of the client
5644 * @param message the actual message
5647 handle_hello (void *cls,
5648 struct GNUNET_SERVER_Client *client,
5649 const struct GNUNET_MessageHeader *message)
5653 GNUNET_STATISTICS_update (stats,
5654 gettext_noop ("# HELLOs received from clients"),
5657 ret = process_hello (NULL, message);
5658 GNUNET_SERVER_receive_done (client, ret);
5663 * Closure for 'transmit_client_message'; followed by
5664 * 'msize' bytes of the actual message.
5666 struct TransmitClientMessageContext
5669 * Client on whom's behalf we are sending.
5671 struct GNUNET_SERVER_Client *client;
5674 * Timeout for the transmission.
5676 struct GNUNET_TIME_Absolute timeout;
5684 * Size of the message in bytes.
5691 * Schedule transmission of a message we got from a client to a peer.
5693 * @param cls the 'struct TransmitClientMessageContext*'
5694 * @param n destination, or NULL on error (in that case, drop the message)
5697 transmit_client_message (void *cls,
5698 struct NeighbourMapEntry *n)
5700 struct TransmitClientMessageContext *tcmc = cls;
5701 struct TransportClient *tc;
5704 while ((tc != NULL) && (tc->client != tcmc->client))
5709 transmit_to_peer (tc, NULL, tcmc->priority,
5710 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5712 tcmc->msize, GNUNET_NO, n);
5714 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5715 GNUNET_SERVER_client_drop (tcmc->client);
5721 * Handle SEND-message.
5723 * @param cls closure (always NULL)
5724 * @param client identification of the client
5725 * @param message the actual message
5728 handle_send (void *cls,
5729 struct GNUNET_SERVER_Client *client,
5730 const struct GNUNET_MessageHeader *message)
5732 const struct OutboundMessage *obm;
5733 const struct GNUNET_MessageHeader *obmm;
5734 struct TransmitClientMessageContext *tcmc;
5738 size = ntohs (message->size);
5740 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5743 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5746 GNUNET_STATISTICS_update (stats,
5747 gettext_noop ("# payload received for other peers"),
5750 obm = (const struct OutboundMessage *) message;
5751 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5752 msize = size - sizeof (struct OutboundMessage);
5754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5755 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5756 "SEND", GNUNET_i2s (&obm->peer),
5760 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5761 tcmc->client = client;
5762 tcmc->priority = ntohl (obm->priority);
5763 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5764 tcmc->msize = msize;
5765 /* FIXME: this memcpy can be up to 7% of our total runtime */
5766 memcpy (&tcmc[1], obmm, msize);
5767 GNUNET_SERVER_client_keep (client);
5768 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5769 &transmit_client_message,
5775 * Handle request connect message
5777 * @param cls closure (always NULL)
5778 * @param client identification of the client
5779 * @param message the actual message
5782 handle_request_connect (void *cls,
5783 struct GNUNET_SERVER_Client *client,
5784 const struct GNUNET_MessageHeader *message)
5786 const struct TransportRequestConnectMessage *trcm =
5787 (const struct TransportRequestConnectMessage *) message;
5789 GNUNET_STATISTICS_update (stats,
5790 gettext_noop ("# REQUEST CONNECT messages received"),
5794 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5795 "Received a request connect message for peer `%s'\n",
5796 GNUNET_i2s(&trcm->peer));
5798 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5800 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5805 * Handle SET_QUOTA-message.
5807 * @param cls closure (always NULL)
5808 * @param client identification of the client
5809 * @param message the actual message
5812 handle_set_quota (void *cls,
5813 struct GNUNET_SERVER_Client *client,
5814 const struct GNUNET_MessageHeader *message)
5816 const struct QuotaSetMessage *qsm =
5817 (const struct QuotaSetMessage *) message;
5818 struct NeighbourMapEntry *n;
5820 GNUNET_STATISTICS_update (stats,
5821 gettext_noop ("# SET QUOTA messages received"),
5824 n = find_neighbour (&qsm->peer);
5827 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5828 GNUNET_STATISTICS_update (stats,
5829 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5836 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5838 (unsigned int) ntohl (qsm->quota.value__),
5839 (unsigned int) n->in_tracker.available_bytes_per_s__,
5840 GNUNET_i2s (&qsm->peer));
5842 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5844 if (0 == ntohl (qsm->quota.value__))
5847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5848 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5851 GNUNET_STATISTICS_update (stats,
5852 gettext_noop ("# disconnects due to quota of 0"),
5855 disconnect_neighbour (n, GNUNET_NO);
5857 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5862 * Take the given address and append it to the set of results sent back to
5865 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5866 * @param address the resolved name, NULL to indicate the last response
5869 transmit_address_to_client (void *cls, const char *address)
5871 struct GNUNET_SERVER_TransmitContext *tc = cls;
5874 if (NULL != address)
5876 slen = strlen (address) + 1;
5877 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5878 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5882 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5883 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5884 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5890 * Handle AddressLookup-message.
5892 * @param cls closure (always NULL)
5893 * @param client identification of the client
5894 * @param message the actual message
5897 handle_address_lookup (void *cls,
5898 struct GNUNET_SERVER_Client *client,
5899 const struct GNUNET_MessageHeader *message)
5901 const struct AddressLookupMessage *alum;
5902 struct TransportPlugin *lsPlugin;
5903 const char *nameTransport;
5904 const char *address;
5906 struct GNUNET_SERVER_TransmitContext *tc;
5907 struct GNUNET_TIME_Relative rtimeout;
5910 size = ntohs (message->size);
5911 if (size < sizeof (struct AddressLookupMessage))
5913 GNUNET_break_op (0);
5914 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5917 alum = (const struct AddressLookupMessage *) message;
5918 uint32_t addressLen = ntohl (alum->addrlen);
5919 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5921 GNUNET_break_op (0);
5922 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5925 address = (const char *) &alum[1];
5926 nameTransport = (const char *) &address[addressLen];
5928 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5930 GNUNET_break_op (0);
5931 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5934 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5935 numeric = ntohl (alum->numeric_only);
5936 lsPlugin = find_transport (nameTransport);
5937 if (NULL == lsPlugin)
5939 tc = GNUNET_SERVER_transmit_context_create (client);
5940 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5941 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5942 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5945 GNUNET_SERVER_disable_receive_done_warning (client);
5946 tc = GNUNET_SERVER_transmit_context_create (client);
5947 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5949 address, addressLen,
5952 &transmit_address_to_client, tc);
5956 * Handle PeerAddressLookupMessage.
5958 * @param cls closure (always NULL)
5959 * @param client identification of the client
5960 * @param message the actual message
5963 handle_peer_address_lookup (void *cls,
5964 struct GNUNET_SERVER_Client *client,
5965 const struct GNUNET_MessageHeader *message)
5967 const struct PeerAddressLookupMessage *peer_address_lookup;
5968 struct NeighbourMapEntry *neighbor_iterator;
5969 struct ReadyList *ready_iterator;
5970 struct ForeignAddressList *foreign_address_iterator;
5971 struct TransportPlugin *transport_plugin;
5974 struct GNUNET_SERVER_TransmitContext *tc;
5975 struct GNUNET_TIME_Relative rtimeout;
5978 size = ntohs (message->size);
5979 if (size < sizeof (struct PeerAddressLookupMessage))
5981 GNUNET_break_op (0);
5982 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5985 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5987 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5989 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5991 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5992 if (neighbor_iterator == NULL)
5995 tc = GNUNET_SERVER_transmit_context_create (client);
5996 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5997 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5998 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
6002 ready_iterator = neighbor_iterator->plugins;
6003 GNUNET_SERVER_disable_receive_done_warning (client);
6004 tc = GNUNET_SERVER_transmit_context_create (client);
6005 while(ready_iterator != NULL)
6007 foreign_address_iterator = ready_iterator->addresses;
6008 while (foreign_address_iterator != NULL)
6010 transport_plugin = foreign_address_iterator->ready_list->plugin;
6011 if (foreign_address_iterator->addr != NULL)
6013 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
6014 a2s (transport_plugin->short_name,
6015 foreign_address_iterator->addr,
6016 foreign_address_iterator->addrlen),
6017 (foreign_address_iterator->connected
6018 == GNUNET_YES) ? "CONNECTED"
6020 (foreign_address_iterator->validated
6021 == GNUNET_YES) ? "VALIDATED"
6023 transmit_address_to_client(tc, addr_buf);
6024 GNUNET_free (addr_buf);
6026 else if (foreign_address_iterator->addrlen == 0)
6028 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
6029 (foreign_address_iterator->connected
6030 == GNUNET_YES) ? "CONNECTED"
6032 (foreign_address_iterator->validated
6033 == GNUNET_YES) ? "VALIDATED"
6035 transmit_address_to_client (tc, addr_buf);
6036 GNUNET_free (addr_buf);
6039 foreign_address_iterator = foreign_address_iterator->next;
6041 ready_iterator = ready_iterator->next;
6043 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6044 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6045 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6051 output_addresses (void *cls,
6052 const GNUNET_HashCode *key,
6055 struct GNUNET_SERVER_TransmitContext *tc = cls;
6056 struct NeighbourMapEntry *neighbor_iterator = value;
6057 struct ForeignAddressList *foreign_address_iterator;
6058 struct TransportPlugin *transport_plugin;
6059 struct ReadyList *ready_iterator;
6062 ready_iterator = neighbor_iterator->plugins;
6063 while (ready_iterator != NULL)
6065 foreign_address_iterator = ready_iterator->addresses;
6066 while (foreign_address_iterator != NULL)
6068 transport_plugin = foreign_address_iterator->ready_list->plugin;
6069 if (foreign_address_iterator->addr != NULL)
6071 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6072 GNUNET_i2s(&neighbor_iterator->id),
6073 a2s (transport_plugin->short_name,
6074 foreign_address_iterator->addr,
6075 foreign_address_iterator->addrlen),
6076 (foreign_address_iterator->connected
6077 == GNUNET_YES) ? "CONNECTED"
6079 (foreign_address_iterator->validated
6080 == GNUNET_YES) ? "VALIDATED"
6082 transmit_address_to_client (tc, addr_buf);
6083 GNUNET_free (addr_buf);
6085 else if (foreign_address_iterator->addrlen == 0)
6087 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6088 GNUNET_i2s (&neighbor_iterator->id),
6090 (foreign_address_iterator->connected
6091 == GNUNET_YES) ? "CONNECTED"
6093 (foreign_address_iterator->validated
6094 == GNUNET_YES) ? "VALIDATED"
6096 transmit_address_to_client (tc, addr_buf);
6097 GNUNET_free (addr_buf);
6100 foreign_address_iterator = foreign_address_iterator->next;
6102 ready_iterator = ready_iterator->next;
6109 * Handle AddressIterateMessage
6111 * @param cls closure (always NULL)
6112 * @param client identification of the client
6113 * @param message the actual message
6116 handle_address_iterate (void *cls,
6117 struct GNUNET_SERVER_Client *client,
6118 const struct GNUNET_MessageHeader *message)
6120 struct GNUNET_SERVER_TransmitContext *tc;
6123 size = ntohs (message->size);
6124 if (size < sizeof (struct AddressIterateMessage))
6126 GNUNET_break_op (0);
6127 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6130 GNUNET_SERVER_disable_receive_done_warning (client);
6131 tc = GNUNET_SERVER_transmit_context_create (client);
6132 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6135 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6136 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6137 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6141 static const struct GNUNET_MessageHeader *
6144 return (const struct GNUNET_MessageHeader*) our_hello;
6149 * Setup the environment for this plugin.
6152 create_environment (struct TransportPlugin *plug)
6154 plug->env.cfg = cfg;
6155 plug->env.my_identity = &my_identity;
6156 plug->env.get_our_hello = &do_get_our_hello;
6157 plug->env.cls = plug;
6158 plug->env.receive = &plugin_env_receive;
6159 plug->env.notify_address = &plugin_env_notify_address;
6160 plug->env.session_end = &plugin_env_session_end;
6161 plug->env.max_connections = max_connect_per_transport;
6162 plug->env.stats = stats;
6167 * Start the specified transport (load the plugin).
6170 start_transport (struct GNUNET_SERVER_Handle *server,
6173 struct TransportPlugin *plug;
6176 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6177 _("Loading `%s' transport plugin\n"), name);
6178 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6179 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6180 create_environment (plug);
6181 plug->short_name = GNUNET_strdup (name);
6182 plug->lib_name = libname;
6183 plug->next = plugins;
6185 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6186 if (plug->api == NULL)
6188 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6189 _("Failed to load transport plugin for `%s'\n"), name);
6190 GNUNET_free (plug->short_name);
6191 plugins = plug->next;
6192 GNUNET_free (libname);
6199 null_mq_client_pointers (void *cls,
6200 const GNUNET_HashCode *key,
6203 struct TransportClient *pos = cls;
6204 struct NeighbourMapEntry *n = value;
6205 struct MessageQueue *mq;
6207 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6209 if (mq->client == pos)
6210 mq->client = NULL; /* do not use anymore! */
6217 * Called whenever a client is disconnected. Frees our
6218 * resources associated with that client.
6220 * @param cls closure
6221 * @param client identification of the client
6224 client_disconnect_notification (void *cls,
6225 struct GNUNET_SERVER_Client *client)
6227 struct TransportClient *pos;
6228 struct TransportClient *prev;
6229 struct ClientMessageQueueEntry *mqe;
6230 struct Blacklisters *bl;
6231 struct BlacklistCheck *bc;
6236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6237 "Client disconnected, cleaning up.\n");
6239 /* clean up blacklister */
6243 if (bl->client == client)
6248 if (bc->bl_pos == bl)
6250 bc->bl_pos = bl->next;
6253 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6256 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6257 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6263 GNUNET_CONTAINER_DLL_remove (bl_head,
6266 GNUNET_SERVER_client_drop (bl->client);
6272 /* clean up 'normal' clients */
6275 while ((pos != NULL) && (pos->client != client))
6282 while (NULL != (mqe = pos->message_queue_head))
6284 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6285 pos->message_queue_tail,
6287 pos->message_count--;
6290 if (NULL != neighbours)
6291 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6292 &null_mq_client_pointers,
6295 clients = pos->next;
6297 prev->next = pos->next;
6298 if (GNUNET_YES == pos->tcs_pending)
6303 if (pos->th != NULL)
6305 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6308 GNUNET_break (0 == pos->message_count);
6314 disconnect_all_neighbours (void *cls,
6315 const GNUNET_HashCode *key,
6318 struct NeighbourMapEntry *n = value;
6321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6322 "Disconnecting peer `%4s', %s\n",
6326 disconnect_neighbour (n, GNUNET_NO);
6332 * Function called when the service shuts down. Unloads our plugins
6333 * and cancels pending validations.
6335 * @param cls closure, unused
6336 * @param tc task context (unused)
6339 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6341 struct TransportPlugin *plug;
6342 struct OwnAddressList *al;
6343 struct CheckHelloValidatedContext *chvc;
6345 shutdown_in_progress = GNUNET_YES;
6346 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6347 &disconnect_all_neighbours,
6350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6351 "Transport service is unloading plugins...\n");
6353 while (NULL != (plug = plugins))
6355 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6357 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6358 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6360 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6361 GNUNET_free (plug->lib_name);
6362 GNUNET_free (plug->short_name);
6363 while (NULL != (al = plug->addresses))
6365 plug->addresses = al->next;
6368 plugins = plug->next;
6371 if (my_private_key != NULL)
6372 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6373 GNUNET_free_non_null (our_hello);
6375 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6378 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6379 validation_map = NULL;
6382 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6384 GNUNET_SCHEDULER_cancel(ats_task);
6385 ats_task = GNUNET_SCHEDULER_NO_TASK;
6392 /* free 'chvc' data structure */
6393 while (NULL != (chvc = chvc_head))
6395 chvc_head = chvc->next;
6396 if (chvc->piter != NULL)
6398 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6399 GNUNET_STATISTICS_update (stats,
6400 gettext_noop ("# outstanding peerinfo iterate requests"),
6407 GNUNET_assert (chvc->ve_count == 0);
6414 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6417 if (peerinfo != NULL)
6419 GNUNET_PEERINFO_disconnect (peerinfo);
6422 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6424 GNUNET_SCHEDULER_cancel (hello_task);
6425 hello_task = GNUNET_SCHEDULER_NO_TASK;
6427 /* Can we assume those are gone by now, or do we need to clean up
6429 GNUNET_break (bl_head == NULL);
6430 GNUNET_break (bc_head == NULL);
6431 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6436 void ats_result_cb ()
6438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6439 "ATS Result callback\n");
6444 struct AtsBuildContext
6446 struct ATS_mechanism * mechanisms;
6447 struct ATS_peer *peers;
6454 find_and_count_addresses (void *cls,
6455 const GNUNET_HashCode *key,
6458 struct AtsBuildContext *abc = cls;
6459 struct NeighbourMapEntry *next = value;
6460 int found_addresses = GNUNET_NO;
6462 struct ReadyList *r_next = next->plugins;
6463 while (r_next != NULL)
6465 struct ForeignAddressList * a_next = r_next->addresses;
6466 while (a_next != NULL)
6469 found_addresses = GNUNET_YES;
6470 a_next = a_next->next;
6472 r_next = r_next->next;
6474 if (found_addresses)
6481 setup_ats_problem (void *cls,
6482 const GNUNET_HashCode *key,
6485 struct AtsBuildContext *abc = cls;
6486 struct NeighbourMapEntry *next = value;
6488 int found_addresses = GNUNET_NO;
6489 struct ReadyList *r_next = next->plugins;
6490 while (r_next != NULL)
6492 struct ForeignAddressList * a_next = r_next->addresses;
6493 while (a_next != NULL)
6495 if (found_addresses == GNUNET_NO)
6497 abc->peers[abc->c_peers].peer = next->id;
6498 abc->peers[abc->c_peers].m_head = NULL;
6499 abc->peers[abc->c_peers].m_tail = NULL;
6500 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6502 abc->mechanisms[abc->c_mechs].addr = a_next;
6503 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6504 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6505 abc->mechanisms[abc->c_mechs].next = NULL;
6506 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6507 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6508 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6509 GNUNET_CONTAINER_DLL_insert_tail(abc->peers[abc->c_peers].m_head,
6510 abc->peers[abc->c_peers].m_tail,
6511 &abc->mechanisms[abc->c_mechs]);
6512 found_addresses = GNUNET_YES;
6514 a_next = a_next->next;
6516 r_next = r_next->next;
6518 if (found_addresses == GNUNET_YES)
6525 create_ats_information ( struct ATS_peer **p,
6527 struct ATS_mechanism ** m,
6530 struct AtsBuildContext abc;
6533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6534 "ATS requires clean address information\n");
6538 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6539 &find_and_count_addresses,
6542 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6543 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6546 if ( (abc.c_peers == 0) && (abc.c_mechs == 0) )
6555 abc.mechanisms = GNUNET_malloc((1+abc.c_mechs) * sizeof (struct ATS_mechanism));
6556 abc.peers = GNUNET_malloc((1+abc.c_peers) * sizeof (struct ATS_peer));
6559 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6564 (*c_m) = abc.c_mechs;
6565 (*c_p) = abc.c_peers;
6567 (*m) = abc.mechanisms;
6572 schedule_ats (void *cls,
6573 const struct GNUNET_SCHEDULER_TaskContext *tc)
6575 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6579 ats_task = GNUNET_SCHEDULER_NO_TASK;
6580 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6583 if (shutdown_in_progress == GNUNET_YES)
6586 struct GNUNET_TIME_Relative delta =
6587 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6588 if (delta.rel_value < ats_minimum_interval.rel_value)
6591 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6592 "Minimum time between cycles not reached\n");
6598 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6601 ats_calculate_bandwidth_distribution (ats);
6603 last_ats_execution = GNUNET_TIME_absolute_get();
6605 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6606 &schedule_ats, ats);
6611 struct ForeignAddressList * get_preferred_ats_address (
6612 struct NeighbourMapEntry *n)
6614 // TODO get ATS prefered address
6615 return find_ready_address(n);
6619 * Initiate transport service.
6621 * @param cls closure
6622 * @param server the initialized server
6623 * @param c configuration to use
6627 struct GNUNET_SERVER_Handle *server,
6628 const struct GNUNET_CONFIGURATION_Handle *c)
6630 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6631 {&handle_start, NULL,
6632 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6633 {&handle_hello, NULL,
6634 GNUNET_MESSAGE_TYPE_HELLO, 0},
6635 {&handle_send, NULL,
6636 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6637 {&handle_request_connect, NULL,
6638 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6639 {&handle_set_quota, NULL,
6640 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6641 {&handle_address_lookup, NULL,
6642 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6644 {&handle_peer_address_lookup, NULL,
6645 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6647 {&handle_address_iterate, NULL,
6648 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6650 {&handle_blacklist_init, NULL,
6651 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6652 {&handle_blacklist_reply, NULL,
6653 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6659 unsigned long long tneigh;
6662 shutdown_in_progress = GNUNET_NO;
6664 stats = GNUNET_STATISTICS_create ("transport", cfg);
6665 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6666 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6667 /* parse configuration */
6669 GNUNET_CONFIGURATION_get_value_number (c,
6674 GNUNET_CONFIGURATION_get_value_filename (c,
6676 "HOSTKEY", &keyfile)))
6678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6680 ("Transport service is lacking key configuration settings. Exiting.\n"));
6681 GNUNET_SCHEDULER_shutdown ();
6684 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6687 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6688 validation_map = NULL;
6689 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6694 max_connect_per_transport = (uint32_t) tneigh;
6695 peerinfo = GNUNET_PEERINFO_connect (cfg);
6696 if (peerinfo == NULL)
6698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6699 _("Could not access PEERINFO service. Exiting.\n"));
6700 GNUNET_SCHEDULER_shutdown ();
6703 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6706 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6707 validation_map = NULL;
6708 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6710 GNUNET_free (keyfile);
6713 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6714 GNUNET_free (keyfile);
6715 if (my_private_key == NULL)
6717 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6719 ("Transport service could not access hostkey. Exiting.\n"));
6720 GNUNET_SCHEDULER_shutdown ();
6723 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6726 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6727 validation_map = NULL;
6728 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6732 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6733 GNUNET_CRYPTO_hash (&my_public_key,
6734 sizeof (my_public_key), &my_identity.hashPubKey);
6735 /* setup notification */
6736 GNUNET_SERVER_disconnect_notify (server,
6737 &client_disconnect_notification, NULL);
6738 /* load plugins... */
6741 GNUNET_CONFIGURATION_get_value_string (c,
6742 "TRANSPORT", "PLUGINS", &plugs))
6744 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6745 _("Starting transport plugins `%s'\n"), plugs);
6746 pos = strtok (plugs, " ");
6749 start_transport (server, pos);
6751 pos = strtok (NULL, " ");
6753 GNUNET_free (plugs);
6755 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6756 &shutdown_task, NULL);
6760 /* Initializing ATS */
6763 unsigned long long value;
6768 int v_b_min = 64000;
6772 ats_minimum_interval = ATS_MIN_INTERVAL;
6773 ats_regular_interval = ATS_EXEC_INTERVAL;
6775 /* loading cost ressources */
6776 for (co=0; co<available_ressources; co++)
6778 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6779 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6781 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6787 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6788 "Found ressource cost: [%s] = %llu\n",
6791 ressources[co].c_max = value;
6794 GNUNET_free (section);
6795 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6796 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6798 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6805 "Found ressource cost: [%s] = %llu\n",
6808 ressources[co].c_min = value;
6811 GNUNET_free (section);
6814 ats = ats_init (D, U, R, v_b_min, v_n_min,
6815 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6816 &create_ats_information,
6818 ats_set_logging_options (ats,
6821 GNUNET_break (GNUNET_OK ==
6822 GNUNET_CONFIGURATION_get_value_time (cfg,
6824 "ATS_EXEC_INTERVAL",
6825 &ats_regular_interval));
6826 GNUNET_break (GNUNET_OK ==
6827 GNUNET_CONFIGURATION_get_value_time (cfg,
6830 &ats_minimum_interval));
6832 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6837 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6838 _("Transport service ready.\n"));
6840 /* If we have a blacklist file, read from it */
6841 read_blacklist_file(cfg);
6842 /* process client requests */
6843 GNUNET_SERVER_add_handlers (server, handlers);
6848 * The main function for the transport service.
6850 * @param argc number of arguments from the command line
6851 * @param argv command line arguments
6852 * @return 0 ok, 1 on error
6855 main (int argc, char *const *argv)
6857 a2s (NULL, NULL, 0); /* make compiler happy */
6858 return (GNUNET_OK ==
6859 GNUNET_SERVICE_run (argc,
6862 GNUNET_SERVICE_OPTION_NONE,
6863 &run, NULL)) ? 0 : 1;
6866 /* end of gnunet-service-transport.c */