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 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1451 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1453 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1456 client->message_count,
1458 GNUNET_STATISTICS_update (stats,
1459 gettext_noop ("# messages dropped due to slow client"),
1464 msize = ntohs (msg->size);
1465 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1466 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1467 memcpy (&q[1], msg, msize);
1468 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1469 client->message_queue_tail,
1471 client->message_count++;
1472 if (client->th == NULL)
1474 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1476 GNUNET_TIME_UNIT_FOREVER_REL,
1477 &transmit_to_client_callback,
1479 GNUNET_assert (client->th != NULL);
1485 * Transmit a 'SEND_OK' notification to the given client for the
1488 * @param client who to notify
1489 * @param n neighbour to notify about, can be NULL (on failure)
1490 * @param target target of the transmission
1491 * @param result status code for the transmission request
1494 transmit_send_ok (struct TransportClient *client,
1495 struct NeighbourMapEntry *n,
1496 const struct GNUNET_PeerIdentity *target,
1499 struct SendOkMessage send_ok_msg;
1501 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1502 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1503 send_ok_msg.success = htonl (result);
1505 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1507 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1508 send_ok_msg.peer = *target;
1509 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1514 * Mark the given FAL entry as 'connected' (and hence preferred for
1515 * sending); also mark all others for the same peer as 'not connected'
1516 * (since only one can be preferred).
1518 * @param fal address to set to 'connected'
1521 mark_address_connected (struct ForeignAddressList *fal);
1526 * We should re-try transmitting to the given peer,
1527 * hopefully we've learned something in the meantime.
1530 retry_transmission_task (void *cls,
1531 const struct GNUNET_SCHEDULER_TaskContext *tc)
1533 struct NeighbourMapEntry *n = cls;
1535 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1536 try_transmission_to_peer (n);
1541 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1542 * upon "completion" of a send request. This tells the API
1543 * that it is now legal to send another message to the given
1546 * @param cls closure, identifies the entry on the
1547 * message queue that was transmitted and the
1548 * client responsible for queuing the message
1549 * @param target the peer receiving the message
1550 * @param result GNUNET_OK on success, if the transmission
1551 * failed, we should not tell the client to transmit
1555 transmit_send_continuation (void *cls,
1556 const struct GNUNET_PeerIdentity *target,
1559 struct MessageQueue *mq = cls;
1560 struct NeighbourMapEntry *n;
1562 GNUNET_STATISTICS_update (stats,
1563 gettext_noop ("# bytes pending with plugins"),
1564 - (int64_t) mq->message_buf_size,
1566 if (result == GNUNET_OK)
1568 GNUNET_STATISTICS_update (stats,
1569 gettext_noop ("# bytes successfully transmitted by plugins"),
1570 mq->message_buf_size,
1575 GNUNET_STATISTICS_update (stats,
1576 gettext_noop ("# bytes with transmission failure by plugins"),
1577 mq->message_buf_size,
1580 if (mq->specific_address != NULL)
1582 if (result == GNUNET_OK)
1584 mq->specific_address->timeout =
1585 GNUNET_TIME_relative_to_absolute
1586 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1587 if (mq->specific_address->validated == GNUNET_YES)
1588 mark_address_connected (mq->specific_address);
1592 if (mq->specific_address->connected == GNUNET_YES)
1595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1596 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1597 a2s (mq->specific_address->ready_list->plugin->short_name,
1598 mq->specific_address->addr,
1599 mq->specific_address->addrlen));
1601 GNUNET_STATISTICS_update (stats,
1602 gettext_noop ("# connected addresses"),
1605 mq->specific_address->connected = GNUNET_NO;
1608 if (! mq->internal_msg)
1609 mq->specific_address->in_transmit = GNUNET_NO;
1611 n = find_neighbour (&mq->neighbour_id);
1612 if (mq->client != NULL)
1613 transmit_send_ok (mq->client, n, target, result);
1614 GNUNET_assert (n != NULL);
1615 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1619 if (result == GNUNET_OK)
1620 try_transmission_to_peer (n);
1621 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1622 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1628 * Check the ready list for the given neighbour and if a plugin is
1629 * ready for transmission (and if we have a message), do so!
1631 * @param neighbour target peer for which to transmit
1634 try_transmission_to_peer (struct NeighbourMapEntry *n)
1636 struct ReadyList *rl;
1637 struct MessageQueue *mq;
1638 struct GNUNET_TIME_Relative timeout;
1642 if (n->messages_head == NULL)
1645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1646 "Transmission queue for `%4s' is empty\n",
1647 GNUNET_i2s (&n->id));
1649 return; /* nothing to do */
1652 mq = n->messages_head;
1653 force_address = GNUNET_YES;
1654 if (mq->specific_address == NULL)
1657 mq->specific_address = get_preferred_ats_address(n);
1658 GNUNET_STATISTICS_update (stats,
1659 gettext_noop ("# transport selected peer address freely"),
1662 force_address = GNUNET_NO;
1664 if (mq->specific_address == NULL)
1666 GNUNET_STATISTICS_update (stats,
1667 gettext_noop ("# transport failed to selected peer address"),
1670 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1671 if (timeout.rel_value == 0)
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "No destination address available to transmit message of size %u to peer `%4s'\n",
1676 mq->message_buf_size,
1677 GNUNET_i2s (&mq->neighbour_id));
1679 GNUNET_STATISTICS_update (stats,
1680 gettext_noop ("# bytes in message queue for other peers"),
1681 - (int64_t) mq->message_buf_size,
1683 GNUNET_STATISTICS_update (stats,
1684 gettext_noop ("# bytes discarded (no destination address available)"),
1685 mq->message_buf_size,
1687 if (mq->client != NULL)
1688 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1689 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1693 return; /* nobody ready */
1695 GNUNET_STATISTICS_update (stats,
1696 gettext_noop ("# message delivery deferred (no address)"),
1699 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1700 GNUNET_SCHEDULER_cancel (n->retry_task);
1701 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1702 &retry_transmission_task,
1705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1706 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1707 mq->message_buf_size,
1708 GNUNET_i2s (&mq->neighbour_id),
1711 /* FIXME: might want to trigger peerinfo lookup here
1712 (unless that's already pending...) */
1715 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1718 if (mq->specific_address->connected == GNUNET_NO)
1719 mq->specific_address->connect_attempts++;
1720 rl = mq->specific_address->ready_list;
1721 mq->plugin = rl->plugin;
1722 if (!mq->internal_msg)
1723 mq->specific_address->in_transmit = GNUNET_YES;
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1727 mq->message_buf_size,
1728 GNUNET_i2s (&n->id),
1729 (mq->specific_address->addr != NULL)
1730 ? a2s (mq->plugin->short_name,
1731 mq->specific_address->addr,
1732 mq->specific_address->addrlen)
1734 rl->plugin->short_name);
1736 GNUNET_STATISTICS_update (stats,
1737 gettext_noop ("# bytes in message queue for other peers"),
1738 - (int64_t) mq->message_buf_size,
1740 GNUNET_STATISTICS_update (stats,
1741 gettext_noop ("# bytes pending with plugins"),
1742 mq->message_buf_size,
1745 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1749 ret = rl->plugin->api->send (rl->plugin->api->cls,
1752 mq->message_buf_size,
1754 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1755 mq->specific_address->session,
1756 mq->specific_address->addr,
1757 mq->specific_address->addrlen,
1759 &transmit_send_continuation, mq);
1762 /* failure, but 'send' would not call continuation in this case,
1763 so we need to do it here! */
1764 transmit_send_continuation (mq,
1772 * Send the specified message to the specified peer.
1774 * @param client source of the transmission request (can be NULL)
1775 * @param peer_address ForeignAddressList where we should send this message
1776 * @param priority how important is the message
1777 * @param timeout how long do we have to transmit?
1778 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1779 * @param message_buf_size total size of all messages in message_buf
1780 * @param is_internal is this an internal message; these are pre-pended and
1781 * also do not count for plugins being "ready" to transmit
1782 * @param neighbour handle to the neighbour for transmission
1785 transmit_to_peer (struct TransportClient *client,
1786 struct ForeignAddressList *peer_address,
1787 unsigned int priority,
1788 struct GNUNET_TIME_Relative timeout,
1789 const char *message_buf,
1790 size_t message_buf_size,
1791 int is_internal, struct NeighbourMapEntry *neighbour)
1793 struct MessageQueue *mq;
1798 /* check for duplicate submission */
1799 mq = neighbour->messages_head;
1802 if (mq->client == client)
1804 /* client transmitted to same peer twice
1805 before getting SEND_OK! */
1813 GNUNET_STATISTICS_update (stats,
1814 gettext_noop ("# bytes in message queue for other peers"),
1817 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1818 mq->specific_address = peer_address;
1819 mq->client = client;
1820 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1821 memcpy (&mq[1], message_buf, message_buf_size);
1822 mq->message_buf = (const char*) &mq[1];
1823 mq->message_buf_size = message_buf_size;
1824 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1825 mq->internal_msg = is_internal;
1826 mq->priority = priority;
1827 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1829 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1830 neighbour->messages_tail,
1833 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1834 neighbour->messages_tail,
1835 neighbour->messages_tail,
1837 try_transmission_to_peer (neighbour);
1842 * Send a plain PING (without address or our HELLO) to the given
1843 * foreign address to try to establish a connection (and validate
1844 * that the other peer is really who he claimed he is).
1846 * @param n neighbour to PING
1849 transmit_plain_ping (struct NeighbourMapEntry *n)
1851 struct ValidationEntry *ve;
1852 struct TransportPingMessage ping;
1853 struct ReadyList *rl;
1854 struct TransportPlugin *plugin;
1855 struct ForeignAddressList *fal;
1857 if (! n->public_key_valid)
1859 /* This should not happen since the other peer
1860 should send us a HELLO prior to sending his
1862 GNUNET_break_op (0);
1863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1864 "Could not transmit plain PING to `%s': public key not known\n",
1865 GNUNET_i2s (&n->id));
1868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1869 "Looking for addresses to transmit plain PING to `%s'\n",
1870 GNUNET_i2s (&n->id));
1871 for (rl = n->plugins; rl != NULL; rl = rl->next)
1873 plugin = rl->plugin;
1874 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1876 if (! fal->connected)
1878 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1879 ve->transport_name = GNUNET_strdup (plugin->short_name);
1880 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1882 ve->send_time = GNUNET_TIME_absolute_get();
1883 ve->session = fal->session;
1884 memcpy(&ve->publicKey,
1886 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1887 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1888 &timeout_hello_validation,
1890 GNUNET_CONTAINER_multihashmap_put (validation_map,
1893 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1894 ping.header.size = htons(sizeof(struct TransportPingMessage));
1895 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1896 ping.challenge = htonl(ve->challenge);
1897 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1898 GNUNET_STATISTICS_update (stats,
1899 gettext_noop ("# PING without HELLO messages sent"),
1902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1903 "Transmitting plain PING to `%s'\n",
1904 GNUNET_i2s (&n->id));
1905 transmit_to_peer (NULL,
1907 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1908 HELLO_VERIFICATION_TIMEOUT,
1909 (const char*) &ping, sizeof (ping),
1917 * Mark the given FAL entry as 'connected' (and hence preferred for
1918 * sending); also mark all others for the same peer as 'not connected'
1919 * (since only one can be preferred).
1921 * @param fal address to set to 'connected'
1924 mark_address_connected(struct ForeignAddressList *fal)
1926 struct ForeignAddressList *pos;
1927 struct ForeignAddressList *inbound;
1928 struct ForeignAddressList *outbound;
1930 GNUNET_assert (GNUNET_YES == fal->validated);
1931 if (fal->connected == GNUNET_YES)
1932 return; /* nothing to do */
1936 pos = fal->ready_list->addresses;
1939 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1940 if ( (GNUNET_YES == pos->connected) &&
1941 (0 == pos->addrlen) &&
1942 (0 == fal->addrlen) )
1944 if ( (0 == pos->addrlen) &&
1945 (GNUNET_YES == pos->connected) )
1950 pos = fal->ready_list->addresses;
1953 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1954 if ( (GNUNET_YES == pos->connected) &&
1955 (0 < pos->addrlen) &&
1956 (0 < fal->addrlen) )
1958 if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
1964 if (inbound != NULL)
1965 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1966 if (outbound != NULL)
1967 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1970 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1971 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1972 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1973 &my_identity.hashPubKey, &null_hash)))
1976 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1980 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1981 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1982 &my_identity.hashPubKey, &null_hash))))
1985 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
1990 pos = fal->ready_list->addresses;
1993 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1997 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1998 a2s (pos->ready_list->plugin->short_name, pos->addr,
2003 "Peer: %s, setting %s connection to disconnected.\n",
2004 GNUNET_i2s(&my_identity),
2005 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2007 pos->connected = GNUNET_NO;
2008 GNUNET_STATISTICS_update (stats,
2009 gettext_noop ("# connected addresses"), -1,
2014 GNUNET_assert (GNUNET_NO == fal->connected);
2015 fal->connected = GNUNET_YES;
2016 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2022 * Find an address in any of the available transports for
2023 * the given neighbour that would be good for message
2024 * transmission. This is essentially the transport selection
2027 * @param neighbour for whom to select an address
2028 * @return selected address, NULL if we have none
2030 struct ForeignAddressList *
2031 find_ready_address(struct NeighbourMapEntry *neighbour)
2033 struct ReadyList *head = neighbour->plugins;
2034 struct ForeignAddressList *addresses;
2035 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2036 struct ForeignAddressList *best_address;
2038 /* Hack to prefer unix domain sockets */
2039 struct ForeignAddressList *unix_address = NULL;
2041 best_address = NULL;
2042 while (head != NULL)
2044 addresses = head->addresses;
2045 while (addresses != NULL)
2047 if ( (addresses->timeout.abs_value < now.abs_value) &&
2048 (addresses->connected == GNUNET_YES) )
2051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052 "Marking long-time inactive connection to `%4s' as down.\n",
2053 GNUNET_i2s (&neighbour->id));
2055 GNUNET_STATISTICS_update (stats,
2056 gettext_noop ("# connected addresses"),
2059 addresses->connected = GNUNET_NO;
2061 addresses = addresses->next;
2064 addresses = head->addresses;
2065 while (addresses != NULL)
2068 if (addresses->addr != NULL)
2069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2070 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2071 a2s (head->plugin->short_name,
2073 addresses->addrlen),
2074 GNUNET_i2s (&neighbour->id),
2075 addresses->connected,
2076 addresses->in_transmit,
2077 addresses->validated,
2078 addresses->connect_attempts,
2079 (unsigned long long) addresses->timeout.abs_value,
2080 (unsigned int) addresses->distance);
2082 if (0==strcmp(head->plugin->short_name,"unix"))
2084 if ( (unix_address == NULL) ||
2085 ( (unix_address != NULL) &&
2086 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2087 unix_address = addresses;
2089 if ( ( (best_address == NULL) ||
2090 (addresses->connected == GNUNET_YES) ||
2091 (best_address->connected == GNUNET_NO) ) &&
2092 (addresses->in_transmit == GNUNET_NO) &&
2093 ( (best_address == NULL) ||
2094 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2095 best_address = addresses;
2096 /* FIXME: also give lower-latency addresses that are not
2097 connected a chance some times... */
2098 addresses = addresses->next;
2100 if (unix_address != NULL)
2104 if (unix_address != NULL)
2106 best_address = unix_address;
2108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2109 "Found UNIX address, forced this address\n");
2112 if (best_address != NULL)
2115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2116 "Best address found (`%s') has latency of %llu ms.\n",
2117 (best_address->addrlen > 0)
2118 ? a2s (best_address->ready_list->plugin->short_name,
2120 best_address->addrlen)
2122 best_address->latency.rel_value);
2127 GNUNET_STATISTICS_update (stats,
2128 gettext_noop ("# transmission attempts failed (no address)"),
2133 return best_address;
2140 struct GeneratorContext
2142 struct TransportPlugin *plug_pos;
2143 struct OwnAddressList *addr_pos;
2144 struct GNUNET_TIME_Absolute expiration;
2152 address_generator (void *cls, size_t max, void *buf)
2154 struct GeneratorContext *gc = cls;
2157 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2159 gc->plug_pos = gc->plug_pos->next;
2160 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2162 if (NULL == gc->plug_pos)
2167 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2170 gc->addr_pos->addrlen, buf, max);
2171 gc->addr_pos = gc->addr_pos->next;
2178 transmit_our_hello_if_pong (void *cls,
2179 const GNUNET_HashCode *key,
2182 struct NeighbourMapEntry *npos = value;
2184 if (GNUNET_YES != npos->received_pong)
2187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2188 "Transmitting updated `%s' to neighbour `%4s'\n",
2189 "HELLO", GNUNET_i2s (&npos->id));
2191 GNUNET_STATISTICS_update (stats,
2192 gettext_noop ("# transmitted my HELLO to other peers"),
2195 transmit_to_peer (NULL, NULL, 0,
2196 HELLO_ADDRESS_EXPIRATION,
2197 (const char *) our_hello,
2198 GNUNET_HELLO_size(our_hello),
2205 * Construct our HELLO message from all of the addresses of
2206 * all of the transports.
2209 * @param tc scheduler context
2212 refresh_hello_task (void *cls,
2213 const struct GNUNET_SCHEDULER_TaskContext *tc)
2215 struct GNUNET_HELLO_Message *hello;
2216 struct TransportClient *cpos;
2217 struct GeneratorContext gc;
2219 hello_task = GNUNET_SCHEDULER_NO_TASK;
2220 gc.plug_pos = plugins;
2221 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2222 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2223 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2226 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2228 GNUNET_STATISTICS_update (stats,
2229 gettext_noop ("# refreshed my HELLO"),
2233 while (cpos != NULL)
2235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2236 "Transmitting my HELLO to client!\n");
2237 transmit_to_client (cpos,
2238 (const struct GNUNET_MessageHeader *) hello,
2243 GNUNET_free_non_null (our_hello);
2245 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2246 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2247 &transmit_our_hello_if_pong,
2253 * Schedule task to refresh hello (unless such a
2254 * task exists already).
2259 #if DEBUG_TRANSPORT_HELLO
2260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2261 "refresh_hello() called!\n");
2263 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2266 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2272 * Iterator over hash map entries that NULLs the session of validation
2273 * entries that match the given session.
2275 * @param cls closure (the 'struct Session*' to match against)
2276 * @param key current key code (peer ID, not used)
2277 * @param value value in the hash map ('struct ValidationEntry*')
2278 * @return GNUNET_YES (we should continue to iterate)
2281 remove_session_validations (void *cls,
2282 const GNUNET_HashCode * key,
2285 struct Session *session = cls;
2286 struct ValidationEntry *ve = value;
2288 if (session == ve->session)
2295 * We've been disconnected from the other peer (for some
2296 * connection-oriented transport). Either quickly
2297 * re-establish the connection or signal the disconnect
2300 * Only signal CORE level disconnect if ALL addresses
2301 * for the peer are exhausted.
2303 * @param p overall plugin context
2304 * @param nl neighbour that was disconnected
2307 try_fast_reconnect (struct TransportPlugin *p,
2308 struct NeighbourMapEntry *nl)
2310 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2312 "try_fast_reconnect not implemented!\n");
2313 /* Note: the idea here is to hide problems with transports (or
2314 switching between plugins) from the core to eliminate the need to
2315 re-negotiate session keys and the like; OTOH, we should tell core
2316 quickly (much faster than timeout) `if a connection was lost and
2317 could not be re-established (i.e. other peer went down or is
2318 unable / refuses to communicate);
2320 So we should consider:
2321 1) ideally: our own willingness / need to connect
2322 2) prior failures to connect to this peer (by plugin)
2323 3) ideally: reasons why other peer terminated (as far as knowable)
2325 Most importantly, it must be POSSIBLE for another peer to terminate
2326 a connection for a while (without us instantly re-establishing it).
2327 Similarly, if another peer is gone we should quickly notify CORE.
2328 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2329 on the other end), we should reconnect in such a way that BOTH CORE
2330 services never even notice.
2331 Furthermore, the same mechanism (or small variation) could be used
2332 to switch to a better-performing plugin (ATS).
2334 Finally, this needs to be tested throughly... */
2337 * GNUNET_NO in the call below makes transport disconnect the peer,
2338 * even if only a single address (out of say, six) went away. This
2339 * function must be careful to ONLY disconnect if the peer is gone,
2340 * not just a specific address.
2342 * More specifically, half the places it was used had it WRONG.
2345 /* No reconnect, signal disconnect instead! */
2348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2349 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2350 "try_fast_reconnect");
2352 GNUNET_STATISTICS_update (stats,
2353 gettext_noop ("# disconnects due to try_fast_reconnect"),
2357 disconnect_neighbour (nl, GNUNET_YES);
2363 * Function that will be called whenever the plugin internally
2364 * cleans up a session pointer and hence the service needs to
2365 * discard all of those sessions as well. Plugins that do not
2366 * use sessions can simply omit calling this function and always
2367 * use NULL wherever a session pointer is needed.
2369 * @param cls closure
2370 * @param peer which peer was the session for
2371 * @param session which session is being destoyed
2374 plugin_env_session_end (void *cls,
2375 const struct GNUNET_PeerIdentity *peer,
2376 struct Session *session)
2378 struct TransportPlugin *p = cls;
2379 struct NeighbourMapEntry *nl;
2380 struct ReadyList *rl;
2381 struct ForeignAddressList *pos;
2382 struct ForeignAddressList *prev;
2385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2386 "Session ended with peer `%4s', %s\n",
2388 "plugin_env_session_end");
2390 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2391 &remove_session_validations,
2393 nl = find_neighbour (peer);
2397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2398 "No neighbour record found for peer `%4s'\n",
2401 return; /* was never marked as connected */
2406 if (rl->plugin == p)
2413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2414 "Plugin was associated with peer `%4s'\n",
2417 GNUNET_STATISTICS_update (stats,
2418 gettext_noop ("# disconnects due to session end"),
2421 disconnect_neighbour (nl, GNUNET_YES);
2425 pos = rl->addresses;
2426 while ( (pos != NULL) &&
2427 (pos->session != session) )
2435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2436 "Session was never marked as ready for peer `%4s'\n",
2440 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2442 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2443 if (validations_pending ==GNUNET_YES)
2446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2447 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2452 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2453 GNUNET_STATISTICS_update (stats,
2454 gettext_noop ("# disconnects due to unready session"),
2458 disconnect_neighbour (nl, GNUNET_YES);
2459 return; /* was never marked as connected */
2461 pos->session = NULL;
2462 if (GNUNET_YES == pos->connected)
2464 pos->connected = GNUNET_NO;
2465 GNUNET_STATISTICS_update (stats,
2466 gettext_noop ("# connected addresses"),
2470 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2472 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2473 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2476 if (pos->addrlen != 0)
2478 if (nl->received_pong != GNUNET_NO)
2480 GNUNET_STATISTICS_update (stats,
2481 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2484 if (GNUNET_YES == pos->connected)
2485 try_fast_reconnect (p, nl);
2489 GNUNET_STATISTICS_update (stats,
2490 gettext_noop ("# disconnects due to missing pong"),
2493 /* FIXME this is never true?! See: line 2416*/
2494 if (GNUNET_YES == pos->connected)
2495 disconnect_neighbour (nl, GNUNET_YES);
2500 /* was inbound connection, free 'pos' */
2502 rl->addresses = pos->next;
2504 prev->next = pos->next;
2505 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2507 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2508 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2510 GNUNET_free_non_null (pos->ressources);
2511 GNUNET_free_non_null (pos->quality);
2513 ats_modify_problem_state (ats, ATS_MODIFIED);
2515 if (GNUNET_YES != pos->connected)
2517 /* nothing else to do, connection was never up... */
2521 pos->connected = GNUNET_NO;
2522 GNUNET_STATISTICS_update (stats,
2523 gettext_noop ("# connected addresses"),
2528 if (nl->received_pong == GNUNET_NO)
2530 GNUNET_STATISTICS_update (stats,
2531 gettext_noop ("# disconnects due to NO pong"),
2534 disconnect_neighbour (nl, GNUNET_YES);
2535 return; /* nothing to do, never connected... */
2537 /* check if we have any validated addresses left */
2538 pos = rl->addresses;
2541 if (GNUNET_YES == pos->validated)
2543 GNUNET_STATISTICS_update (stats,
2544 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2547 try_fast_reconnect (p, nl);
2552 /* no valid addresses left, signal disconnect! */
2555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2556 "Disconnecting peer `%4s', %s\n",
2558 "plugin_env_session_end");
2560 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2561 * it means there aren't any left for this PLUGIN/PEER combination! So
2562 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2563 * when it isn't necessary. Using GNUNET_YES at least checks to see
2564 * if there are any addresses that work first, so as not to overdo it.
2567 GNUNET_STATISTICS_update (stats,
2568 gettext_noop ("# disconnects due to plugin_env_session_end"),
2571 disconnect_neighbour (nl, GNUNET_YES);
2576 * Function that must be called by each plugin to notify the
2577 * transport service about the addresses under which the transport
2578 * provided by the plugin can be reached.
2580 * @param cls closure
2581 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2582 * @param addr one of the addresses of the host, NULL for the last address
2583 * the specific address format depends on the transport
2584 * @param addrlen length of the address
2587 plugin_env_notify_address (void *cls,
2592 struct TransportPlugin *p = cls;
2593 struct OwnAddressList *al;
2594 struct OwnAddressList *prev;
2596 GNUNET_assert (p->api != NULL);
2598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599 (add_remove == GNUNET_YES)
2600 ? "Adding `%s':%s to the set of our addresses\n"
2601 : "Removing `%s':%s from the set of our addresses\n",
2606 GNUNET_assert (addr != NULL);
2607 if (GNUNET_NO == add_remove)
2613 if ( (addrlen == al->addrlen) &&
2614 (0 == memcmp (addr, &al[1], addrlen)) )
2617 p->addresses = al->next;
2619 prev->next = al->next;
2630 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2631 al->next = p->addresses;
2633 al->addrlen = addrlen;
2634 memcpy (&al[1], addr, addrlen);
2640 * Notify all of our clients about a peer connecting.
2643 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2644 struct GNUNET_TIME_Relative latency,
2647 struct ConnectInfoMessage * cim;
2648 struct TransportClient *cpos;
2652 if (0 == memcmp (peer,
2654 sizeof (struct GNUNET_PeerIdentity)))
2660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2661 "Notifying clients about connection with `%s'\n",
2664 GNUNET_STATISTICS_update (stats,
2665 gettext_noop ("# peers connected"),
2670 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2671 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2672 cim = GNUNET_malloc (size);
2673 cim->header.size = htons (size);
2674 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2675 cim->ats_count = htonl(2);
2676 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2677 (&cim->ats)[0].value = htonl (distance);
2678 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2679 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2680 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2681 (&cim->ats)[2].value = htonl (0);
2682 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2684 /* notify ats about connecting peer */
2685 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2688 ats_modify_problem_state(ats, ATS_MODIFIED);
2689 ats_calculate_bandwidth_distribution (ats);
2693 while (cpos != NULL)
2695 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2703 * Notify all of our clients about a peer disconnecting.
2706 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2708 struct DisconnectInfoMessage dim;
2709 struct TransportClient *cpos;
2711 if (0 == memcmp (peer,
2713 sizeof (struct GNUNET_PeerIdentity)))
2719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2720 "Notifying clients about lost connection to `%s'\n",
2723 GNUNET_STATISTICS_update (stats,
2724 gettext_noop ("# peers connected"),
2727 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2728 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2729 dim.reserved = htonl (0);
2730 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2732 /* notify ats about connecting peer */
2733 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2736 ats_modify_problem_state(ats, ATS_MODIFIED);
2737 ats_calculate_bandwidth_distribution (ats);
2742 while (cpos != NULL)
2744 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2751 * Find a ForeignAddressList entry for the given neighbour
2752 * that matches the given address and transport.
2754 * @param neighbour which peer we care about
2755 * @param tname name of the transport plugin
2756 * @param session session to look for, NULL for 'any'; otherwise
2757 * can be used for the service to "learn" this session ID
2759 * @param addr binary address
2760 * @param addrlen length of addr
2761 * @return NULL if no such entry exists
2763 static struct ForeignAddressList *
2764 find_peer_address(struct NeighbourMapEntry *neighbour,
2766 struct Session *session,
2770 struct ReadyList *head;
2771 struct ForeignAddressList *pos;
2773 head = neighbour->plugins;
2774 while (head != NULL)
2776 if (0 == strcmp (tname, head->plugin->short_name))
2782 pos = head->addresses;
2783 while ( (pos != NULL) &&
2784 ( (pos->addrlen != addrlen) ||
2785 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2787 if ( (session != NULL) &&
2788 (pos->session == session) )
2792 if ( (session != NULL) && (pos != NULL) )
2793 pos->session = session; /* learn it! */
2799 * Get the peer address struct for the given neighbour and
2800 * address. If it doesn't yet exist, create it.
2802 * @param neighbour which peer we care about
2803 * @param tname name of the transport plugin
2804 * @param session session of the plugin, or NULL for none
2805 * @param addr binary address
2806 * @param addrlen length of addr
2807 * @return NULL if we do not have a transport plugin for 'tname'
2809 static struct ForeignAddressList *
2810 add_peer_address (struct NeighbourMapEntry *neighbour,
2812 struct Session *session,
2816 struct ReadyList *head;
2817 struct ForeignAddressList *ret;
2820 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2823 head = neighbour->plugins;
2825 while (head != NULL)
2827 if (0 == strcmp (tname, head->plugin->short_name))
2833 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2834 ret->session = session;
2835 if ((addrlen > 0) && (addr != NULL))
2837 ret->addr = (const char*) &ret[1];
2838 memcpy (&ret[1], addr, addrlen);
2845 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2846 for (c=0; c<available_ressources; c++)
2848 struct ATS_ressource_entry *r = ret->ressources;
2850 r[c].atis_index = ressources[c].atis_index;
2851 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2853 r[c].c = ressources[c].c_unix;
2855 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2857 r[c].c = ressources[c].c_udp;
2859 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2861 r[c].c = ressources[c].c_tcp;
2863 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2865 r[c].c = ressources[c].c_http;
2867 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2869 r[c].c = ressources[c].c_https;
2871 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2873 r[c].c = ressources[c].c_wlan;
2877 r[c].c = ressources[c].c_default;
2878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2879 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2880 GNUNET_i2s(&neighbour->id),
2881 neighbour->plugins->plugin->short_name);
2885 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2886 ret->addrlen = addrlen;
2887 ret->expires = GNUNET_TIME_relative_to_absolute
2888 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2889 ret->latency = GNUNET_TIME_relative_get_forever();
2891 ret->timeout = GNUNET_TIME_relative_to_absolute
2892 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2893 ret->ready_list = head;
2894 ret->next = head->addresses;
2895 head->addresses = ret;
2901 * Closure for 'add_validated_address'.
2903 struct AddValidatedAddressContext
2906 * Entry that has been validated.
2908 const struct ValidationEntry *ve;
2911 * Flag set after we have added the address so
2912 * that we terminate the iteration next time.
2919 * Callback function used to fill a buffer of max bytes with a list of
2920 * addresses in the format used by HELLOs. Should use
2921 * "GNUNET_HELLO_add_address" as a helper function.
2923 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2924 * @param max maximum number of bytes that can be written to buf
2925 * @param buf where to write the address information
2926 * @return number of bytes written, 0 to signal the
2927 * end of the iteration.
2930 add_validated_address (void *cls,
2931 size_t max, void *buf)
2933 struct AddValidatedAddressContext *avac = cls;
2934 const struct ValidationEntry *ve = avac->ve;
2936 if (GNUNET_YES == avac->done)
2938 avac->done = GNUNET_YES;
2939 return GNUNET_HELLO_add_address (ve->transport_name,
2940 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2950 * Closure for 'check_address_exists'.
2952 struct CheckAddressExistsClosure
2955 * Address to check for.
2960 * Name of the transport.
2967 struct Session *session;
2970 * Set to GNUNET_YES if the address exists.
2983 * Iterator over hash map entries. Checks if the given
2984 * validation entry is for the same address as what is given
2987 * @param cls the 'struct CheckAddressExistsClosure*'
2988 * @param key current key code (ignored)
2989 * @param value value in the hash map ('struct ValidationEntry')
2990 * @return GNUNET_YES if we should continue to
2991 * iterate (mismatch), GNUNET_NO if not (entry matched)
2994 check_address_exists (void *cls,
2995 const GNUNET_HashCode * key,
2998 struct CheckAddressExistsClosure *caec = cls;
2999 struct ValidationEntry *ve = value;
3001 if ( (0 == strcmp (caec->tname,
3002 ve->transport_name)) &&
3003 (caec->addrlen == ve->addrlen) &&
3004 (0 == memcmp (caec->addr,
3008 caec->exists = GNUNET_YES;
3011 if ( (ve->session != NULL) &&
3012 (caec->session == ve->session) )
3014 caec->exists = GNUNET_YES;
3022 neighbour_timeout_task (void *cls,
3023 const struct GNUNET_SCHEDULER_TaskContext *tc)
3025 struct NeighbourMapEntry *n = cls;
3028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3029 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3031 GNUNET_STATISTICS_update (stats,
3032 gettext_noop ("# disconnects due to timeout"),
3035 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3036 disconnect_neighbour (n, GNUNET_NO);
3041 * Schedule the job that will cause us to send a PING to the
3042 * foreign address to evaluate its validity and latency.
3044 * @param fal address to PING
3047 schedule_next_ping (struct ForeignAddressList *fal);
3051 * Add the given address to the list of foreign addresses
3052 * available for the given peer (check for duplicates).
3054 * @param cls the respective 'struct NeighbourMapEntry' to update
3055 * @param tname name of the transport
3056 * @param expiration expiration time
3057 * @param addr the address
3058 * @param addrlen length of the address
3059 * @return GNUNET_OK (always)
3062 add_to_foreign_address_list (void *cls,
3064 struct GNUNET_TIME_Absolute expiration,
3068 struct NeighbourMapEntry *n = cls;
3069 struct ForeignAddressList *fal;
3072 GNUNET_STATISTICS_update (stats,
3073 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3077 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3080 #if DEBUG_TRANSPORT_HELLO
3081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3082 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3083 a2s (tname, addr, addrlen),
3085 GNUNET_i2s (&n->id),
3086 expiration.abs_value);
3088 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3091 GNUNET_STATISTICS_update (stats,
3092 gettext_noop ("# previously validated addresses lacking transport"),
3098 fal->expires = GNUNET_TIME_absolute_max (expiration,
3100 schedule_next_ping (fal);
3106 fal->expires = GNUNET_TIME_absolute_max (expiration,
3112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3113 "Failed to add new address for `%4s'\n",
3114 GNUNET_i2s (&n->id));
3118 if (fal->validated == GNUNET_NO)
3120 fal->validated = GNUNET_YES;
3121 GNUNET_STATISTICS_update (stats,
3122 gettext_noop ("# peer addresses considered valid"),
3126 if (try == GNUNET_YES)
3129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3130 "Have new addresses, will try to trigger transmissions.\n");
3132 try_transmission_to_peer (n);
3139 * Add addresses in validated HELLO "h" to the set of addresses
3140 * we have for this peer.
3142 * @param cls closure ('struct NeighbourMapEntry*')
3143 * @param peer id of the peer, NULL for last call
3144 * @param h hello message for the peer (can be NULL)
3145 * @param err_msg NULL if successful, otherwise contains error message
3148 add_hello_for_peer (void *cls,
3149 const struct GNUNET_PeerIdentity *peer,
3150 const struct GNUNET_HELLO_Message *h,
3151 const char *err_msg)
3153 struct NeighbourMapEntry *n = cls;
3155 if (err_msg != NULL)
3158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3159 _("Error in communication with PEERINFO service: %s\n"),
3166 GNUNET_STATISTICS_update (stats,
3167 gettext_noop ("# outstanding peerinfo iterate requests"),
3174 return; /* no HELLO available */
3176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3177 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3181 if (GNUNET_YES != n->public_key_valid)
3183 GNUNET_HELLO_get_key (h, &n->publicKey);
3184 n->public_key_valid = GNUNET_YES;
3186 GNUNET_HELLO_iterate_addresses (h,
3188 &add_to_foreign_address_list,
3194 * Create a fresh entry in our neighbour list for the given peer.
3195 * Will try to transmit our current HELLO to the new neighbour.
3196 * Do not call this function directly, use 'setup_peer_check_blacklist.
3198 * @param peer the peer for which we create the entry
3199 * @param do_hello should we schedule transmitting a HELLO
3200 * @return the new neighbour list entry
3202 static struct NeighbourMapEntry *
3203 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3206 struct NeighbourMapEntry *n;
3207 struct TransportPlugin *tp;
3208 struct ReadyList *rl;
3210 GNUNET_assert (0 != memcmp (peer,
3212 sizeof (struct GNUNET_PeerIdentity)));
3214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3215 "Setting up state for neighbour `%4s'\n",
3218 GNUNET_STATISTICS_update (stats,
3219 gettext_noop ("# active neighbours"),
3222 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3225 GNUNET_TIME_relative_to_absolute
3226 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3227 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3228 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3229 MAX_BANDWIDTH_CARRY_S);
3233 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3235 rl = GNUNET_malloc (sizeof (struct ReadyList));
3237 rl->next = n->plugins;
3240 rl->addresses = NULL;
3244 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3246 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3247 &neighbour_timeout_task, n);
3248 GNUNET_CONTAINER_multihashmap_put (neighbours,
3251 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3254 GNUNET_STATISTICS_update (stats,
3255 gettext_noop ("# peerinfo new neighbor iterate requests"),
3258 GNUNET_STATISTICS_update (stats,
3259 gettext_noop ("# outstanding peerinfo iterate requests"),
3262 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3263 GNUNET_TIME_UNIT_FOREVER_REL,
3264 &add_hello_for_peer, n);
3266 GNUNET_STATISTICS_update (stats,
3267 gettext_noop ("# HELLO's sent to new neighbors"),
3270 if (NULL != our_hello)
3271 transmit_to_peer (NULL, NULL, 0,
3272 HELLO_ADDRESS_EXPIRATION,
3273 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3281 * Function called after we have checked if communicating
3282 * with a given peer is acceptable.
3284 * @param cls closure
3285 * @param n NULL if communication is not acceptable
3287 typedef void (*SetupContinuation)(void *cls,
3288 struct NeighbourMapEntry *n);
3292 * Information kept for each client registered to perform
3298 * This is a linked list.
3300 struct Blacklisters *next;
3303 * This is a linked list.
3305 struct Blacklisters *prev;
3308 * Client responsible for this entry.
3310 struct GNUNET_SERVER_Client *client;
3313 * Blacklist check that we're currently performing.
3315 struct BlacklistCheck *bc;
3321 * Head of DLL of blacklisting clients.
3323 static struct Blacklisters *bl_head;
3326 * Tail of DLL of blacklisting clients.
3328 static struct Blacklisters *bl_tail;
3332 * Context we use when performing a blacklist check.
3334 struct BlacklistCheck
3338 * This is a linked list.
3340 struct BlacklistCheck *next;
3343 * This is a linked list.
3345 struct BlacklistCheck *prev;
3348 * Peer being checked.
3350 struct GNUNET_PeerIdentity peer;
3353 * Option for setup neighbour afterwards.
3358 * Continuation to call with the result.
3360 SetupContinuation cont;
3368 * Current transmission request handle for this client, or NULL if no
3369 * request is pending.
3371 struct GNUNET_CONNECTION_TransmitHandle *th;
3374 * Our current position in the blacklisters list.
3376 struct Blacklisters *bl_pos;
3379 * Current task performing the check.
3381 GNUNET_SCHEDULER_TaskIdentifier task;
3386 * Head of DLL of active blacklisting queries.
3388 static struct BlacklistCheck *bc_head;
3391 * Tail of DLL of active blacklisting queries.
3393 static struct BlacklistCheck *bc_tail;
3397 * Perform next action in the blacklist check.
3399 * @param cls the 'struct BlacklistCheck*'
3403 do_blacklist_check (void *cls,
3404 const struct GNUNET_SCHEDULER_TaskContext *tc);
3407 * Transmit blacklist query to the client.
3409 * @param cls the 'struct BlacklistCheck'
3410 * @param size number of bytes allowed
3411 * @param buf where to copy the message
3412 * @return number of bytes copied to buf
3415 transmit_blacklist_message (void *cls,
3419 struct BlacklistCheck *bc = cls;
3420 struct Blacklisters *bl;
3421 struct BlacklistMessage bm;
3426 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3427 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3429 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3430 "Failed to send blacklist test for peer `%s' to client\n",
3431 GNUNET_i2s (&bc->peer));
3435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3436 "Sending blacklist test for peer `%s' to client\n",
3437 GNUNET_i2s (&bc->peer));
3440 bm.header.size = htons (sizeof (struct BlacklistMessage));
3441 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3442 bm.is_allowed = htonl (0);
3444 memcpy (buf, &bm, sizeof (bm));
3445 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3451 * Perform next action in the blacklist check.
3453 * @param cls the 'struct BlacklistCheck*'
3457 do_blacklist_check (void *cls,
3458 const struct GNUNET_SCHEDULER_TaskContext *tc)
3460 struct BlacklistCheck *bc = cls;
3461 struct Blacklisters *bl;
3463 bc->task = GNUNET_SCHEDULER_NO_TASK;
3468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3469 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3470 GNUNET_i2s (&bc->peer));
3472 bc->cont (bc->cont_cls,
3473 setup_new_neighbour (&bc->peer, bc->do_hello));
3480 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3481 sizeof (struct BlacklistMessage),
3482 GNUNET_TIME_UNIT_FOREVER_REL,
3483 &transmit_blacklist_message,
3490 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3491 * does not yet exist, check the blacklist. If the blacklist says creating
3492 * one is acceptable, create one and call the continuation; otherwise
3493 * call the continuation with NULL.
3495 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3496 * @param do_hello should we also schedule sending our HELLO to the peer
3497 * if this is a new record
3498 * @param cont function to call with the 'struct NeigbhbourList*'
3499 * @param cont_cls closure for cont
3502 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3504 SetupContinuation cont,
3507 struct NeighbourMapEntry *n;
3508 struct BlacklistCheck *bc;
3510 n = find_neighbour(peer);
3514 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3515 "Neighbour record exists for peer `%s'\n",
3522 if (bl_head == NULL)
3525 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3527 setup_new_neighbour(peer, do_hello);
3530 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3531 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3533 bc->do_hello = do_hello;
3535 bc->cont_cls = cont_cls;
3536 bc->bl_pos = bl_head;
3537 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3543 * Function called with the result of querying a new blacklister about
3544 * it being allowed (or not) to continue to talk to an existing neighbour.
3546 * @param cls the original 'struct NeighbourMapEntry'
3547 * @param n NULL if we need to disconnect
3550 confirm_or_drop_neighbour (void *cls,
3551 struct NeighbourMapEntry *n)
3553 struct NeighbourMapEntry * orig = cls;
3558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3559 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3560 "confirm_or_drop_neighboUr");
3562 GNUNET_STATISTICS_update (stats,
3563 gettext_noop ("# disconnects due to blacklist"),
3566 disconnect_neighbour (orig, GNUNET_NO);
3571 struct TestConnectionContext
3575 struct Blacklisters *bl;
3580 test_connection_ok (void *cls,
3581 const GNUNET_HashCode *key,
3584 struct TestConnectionContext *tcc = cls;
3585 struct NeighbourMapEntry *n = value;
3586 struct BlacklistCheck *bc;
3589 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3590 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3592 bc->do_hello = GNUNET_NO;
3593 bc->cont = &confirm_or_drop_neighbour;
3595 bc->bl_pos = tcc->bl;
3596 if (GNUNET_YES == tcc->first)
3598 /* all would wait for the same client, no need to
3599 create more than just the first task right now */
3600 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3602 tcc->first = GNUNET_NO;
3609 * Handle a request to start a blacklist.
3611 * @param cls closure (always NULL)
3612 * @param client identification of the client
3613 * @param message the actual message
3616 handle_blacklist_init (void *cls,
3617 struct GNUNET_SERVER_Client *client,
3618 const struct GNUNET_MessageHeader *message)
3620 struct Blacklisters *bl;
3621 struct TestConnectionContext tcc;
3626 if (bl->client == client)
3629 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3634 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3635 bl->client = client;
3636 GNUNET_SERVER_client_keep (client);
3637 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3638 /* confirm that all existing connections are OK! */
3640 tcc.first = GNUNET_YES;
3641 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
3642 &test_connection_ok,
3648 * Handle a request to blacklist a peer.
3650 * @param cls closure (always NULL)
3651 * @param client identification of the client
3652 * @param message the actual message
3655 handle_blacklist_reply (void *cls,
3656 struct GNUNET_SERVER_Client *client,
3657 const struct GNUNET_MessageHeader *message)
3659 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3660 struct Blacklisters *bl;
3661 struct BlacklistCheck *bc;
3664 while ( (bl != NULL) &&
3665 (bl->client != client) )
3670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3671 "Blacklist client disconnected\n");
3673 /* FIXME: other error handling here!? */
3674 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3679 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3683 "Blacklist check failed, peer not allowed\n");
3685 bc->cont (bc->cont_cls, NULL);
3686 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3693 "Blacklist check succeeded, continuing with checks\n");
3695 bc->bl_pos = bc->bl_pos->next;
3696 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3699 /* check if any other bc's are waiting for this blacklister */
3703 if ( (bc->bl_pos == bl) &&
3704 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3705 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3713 * Send periodic PING messages to a given foreign address.
3715 * @param cls our 'struct PeriodicValidationContext*'
3716 * @param tc task context
3719 send_periodic_ping (void *cls,
3720 const struct GNUNET_SCHEDULER_TaskContext *tc)
3722 struct ForeignAddressList *peer_address = cls;
3723 struct TransportPlugin *tp;
3724 struct ValidationEntry *va;
3725 struct NeighbourMapEntry *neighbour;
3726 struct TransportPingMessage ping;
3727 struct CheckAddressExistsClosure caec;
3729 uint16_t hello_size;
3733 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3734 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3736 GNUNET_assert (peer_address != NULL);
3737 tp = peer_address->ready_list->plugin;
3738 neighbour = peer_address->ready_list->neighbour;
3739 if (GNUNET_YES != neighbour->public_key_valid)
3741 /* no public key yet, try again later */
3742 schedule_next_ping (peer_address);
3745 caec.addr = peer_address->addr;
3746 caec.addrlen = peer_address->addrlen;
3747 caec.tname = tp->short_name;
3748 caec.session = peer_address->session;
3749 caec.exists = GNUNET_NO;
3751 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3752 &check_address_exists,
3754 if (caec.exists == GNUNET_YES)
3756 /* During validation attempts we will likely trigger the other
3757 peer trying to validate our address which in turn will cause
3758 it to send us its HELLO, so we expect to hit this case rather
3759 frequently. Only print something if we are very verbose. */
3760 #if DEBUG_TRANSPORT > 1
3761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3762 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3763 (peer_address->addr != NULL)
3764 ? a2s (tp->short_name,
3766 peer_address->addrlen)
3769 GNUNET_i2s (&neighbour->id));
3771 schedule_next_ping (peer_address);
3774 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3775 va->transport_name = GNUNET_strdup (tp->short_name);
3776 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3778 va->send_time = GNUNET_TIME_absolute_get();
3779 va->session = peer_address->session;
3780 if (peer_address->addr != NULL)
3782 va->addr = (const void*) &va[1];
3783 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3784 va->addrlen = peer_address->addrlen;
3786 memcpy(&va->publicKey,
3787 &neighbour->publicKey,
3788 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3790 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3791 &timeout_hello_validation,
3793 GNUNET_CONTAINER_multihashmap_put (validation_map,
3794 &neighbour->id.hashPubKey,
3796 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3798 if (peer_address->validated != GNUNET_YES)
3799 hello_size = GNUNET_HELLO_size(our_hello);
3803 tsize = sizeof(struct TransportPingMessage) + hello_size;
3805 if (peer_address->addr != NULL)
3807 slen = strlen (tp->short_name) + 1;
3808 tsize += slen + peer_address->addrlen;
3812 slen = 0; /* make gcc happy */
3814 message_buf = GNUNET_malloc(tsize);
3815 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3816 ping.challenge = htonl(va->challenge);
3817 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3818 if (peer_address->validated != GNUNET_YES)
3820 memcpy(message_buf, our_hello, hello_size);
3823 if (peer_address->addr != NULL)
3825 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3826 peer_address->addrlen +
3828 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3831 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3833 peer_address->addrlen);
3837 ping.header.size = htons(sizeof(struct TransportPingMessage));
3840 memcpy(&message_buf[hello_size],
3842 sizeof(struct TransportPingMessage));
3844 #if DEBUG_TRANSPORT_REVALIDATION
3845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3846 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3847 (peer_address->addr != NULL)
3848 ? a2s (peer_address->plugin->short_name,
3850 peer_address->addrlen)
3853 GNUNET_i2s (&neighbour->id),
3854 "HELLO", hello_size,
3857 if (peer_address->validated != GNUNET_YES)
3858 GNUNET_STATISTICS_update (stats,
3859 gettext_noop ("# PING with HELLO messages sent"),
3863 GNUNET_STATISTICS_update (stats,
3864 gettext_noop ("# PING without HELLO messages sent"),
3867 GNUNET_STATISTICS_update (stats,
3868 gettext_noop ("# PING messages sent for re-validation"),
3871 transmit_to_peer (NULL, peer_address,
3872 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3873 HELLO_VERIFICATION_TIMEOUT,
3875 GNUNET_YES, neighbour);
3876 GNUNET_free (message_buf);
3877 schedule_next_ping (peer_address);
3882 * Schedule the job that will cause us to send a PING to the
3883 * foreign address to evaluate its validity and latency.
3885 * @param fal address to PING
3888 schedule_next_ping (struct ForeignAddressList *fal)
3890 struct GNUNET_TIME_Relative delay;
3892 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3894 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3895 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3897 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3898 delay.rel_value /= 2; /* do before expiration */
3899 delay = GNUNET_TIME_relative_min (delay,
3900 LATENCY_EVALUATION_MAX_DELAY);
3901 if (GNUNET_YES != fal->estimated)
3903 delay = GNUNET_TIME_UNIT_ZERO;
3904 fal->estimated = GNUNET_YES;
3907 if (GNUNET_YES == fal->connected)
3909 delay = GNUNET_TIME_relative_min (delay,
3910 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3912 /* FIXME: also adjust delay based on how close the last
3913 observed latency is to the latency of the best alternative */
3914 /* bound how fast we can go */
3915 delay = GNUNET_TIME_relative_max (delay,
3916 GNUNET_TIME_UNIT_SECONDS);
3917 /* randomize a bit (to avoid doing all at the same time) */
3918 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3920 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3921 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3922 &send_periodic_ping,
3930 * Function that will be called if we receive some payload
3931 * from another peer.
3933 * @param message the payload
3934 * @param n peer who claimed to be the sender
3937 handle_payload_message (const struct GNUNET_MessageHeader *message,
3938 struct NeighbourMapEntry *n)
3940 struct InboundMessage *im;
3941 struct TransportClient *cpos;
3944 msize = ntohs (message->size);
3945 if (n->received_pong == GNUNET_NO)
3948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3949 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3950 ntohs (message->type),
3951 ntohs (message->size),
3952 GNUNET_i2s (&n->id));
3954 GNUNET_free_non_null (n->pre_connect_message_buffer);
3955 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3956 memcpy (n->pre_connect_message_buffer, message, msize);
3961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3962 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3963 ntohs (message->type),
3964 ntohs (message->size),
3965 GNUNET_i2s (&n->id));
3967 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3970 n->quota_violation_count++;
3972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3973 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3974 n->in_tracker.available_bytes_per_s__,
3975 n->quota_violation_count);
3977 /* Discount 32k per violation */
3978 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3983 if (n->quota_violation_count > 0)
3985 /* try to add 32k back */
3986 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3988 n->quota_violation_count--;
3991 GNUNET_STATISTICS_update (stats,
3992 gettext_noop ("# payload received from other peers"),
3995 /* transmit message to all clients */
3996 uint32_t ats_count = 2;
3997 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3998 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4001 im = GNUNET_malloc (size);
4002 im->header.size = htons (size);
4003 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4005 im->ats_count = htonl(ats_count);
4006 /* Setting ATS data */
4007 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4008 (&(im->ats))[0].value = htonl (n->distance);
4009 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4010 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4011 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4012 (&(im->ats))[ats_count].value = htonl (0);
4014 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
4016 while (cpos != NULL)
4018 transmit_to_client (cpos, &im->header, GNUNET_YES);
4026 * Iterator over hash map entries. Checks if the given validation
4027 * entry is for the same challenge as what is given in the PONG.
4029 * @param cls the 'struct TransportPongMessage*'
4030 * @param key peer identity
4031 * @param value value in the hash map ('struct ValidationEntry')
4032 * @return GNUNET_YES if we should continue to
4033 * iterate (mismatch), GNUNET_NO if not (entry matched)
4036 check_pending_validation (void *cls,
4037 const GNUNET_HashCode * key,
4040 const struct TransportPongMessage *pong = cls;
4041 struct ValidationEntry *ve = value;
4042 struct AddValidatedAddressContext avac;
4043 unsigned int challenge = ntohl(pong->challenge);
4044 struct GNUNET_HELLO_Message *hello;
4045 struct GNUNET_PeerIdentity target;
4046 struct NeighbourMapEntry *n;
4047 struct ForeignAddressList *fal;
4048 struct OwnAddressList *oal;
4049 struct TransportPlugin *tp;
4050 struct GNUNET_MessageHeader *prem;
4056 ps = ntohs (pong->header.size);
4057 if (ps < sizeof (struct TransportPongMessage))
4059 GNUNET_break_op (0);
4062 addr = (const char*) &pong[1];
4063 slen = strlen (ve->transport_name) + 1;
4064 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4065 (ve->challenge != challenge) ||
4066 (addr[slen-1] != '\0') ||
4067 (0 != strcmp (addr, ve->transport_name)) ||
4068 (ntohl (pong->purpose.size)
4069 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4071 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4072 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4077 alen = ps - sizeof (struct TransportPongMessage) - slen;
4078 switch (ntohl (pong->purpose.purpose))
4080 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4081 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4082 (0 != memcmp (&addr[slen],
4086 return GNUNET_YES; /* different entry, keep trying! */
4088 if (0 != memcmp (&pong->pid,
4090 sizeof (struct GNUNET_PeerIdentity)))
4092 GNUNET_break_op (0);
4096 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4101 GNUNET_break_op (0);
4106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4107 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4109 a2s (ve->transport_name,
4110 (const struct sockaddr *) ve->addr,
4112 ve->transport_name);
4115 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4116 if (0 != memcmp (&pong->pid,
4118 sizeof (struct GNUNET_PeerIdentity)))
4122 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4125 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4126 GNUNET_i2s (&my_identity),
4132 if (ve->addrlen != 0)
4134 /* must have been for a different validation entry */
4137 tp = find_transport (ve->transport_name);
4143 oal = tp->addresses;
4146 if ( (oal->addrlen == alen) &&
4147 (0 == memcmp (&oal[1],
4155 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4156 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4157 GNUNET_i2s (&pong->pid),
4158 a2s (ve->transport_name,
4161 /* FIXME: since the sender of the PONG currently uses the
4162 wrong address (see FIMXE there!), we cannot run a
4163 proper check here... */
4169 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4174 GNUNET_break_op (0);
4179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4180 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4182 a2s (ve->transport_name,
4185 ve->transport_name);
4189 GNUNET_break_op (0);
4192 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4194 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4195 _("Received expired signature. Check system time.\n"));
4198 GNUNET_STATISTICS_update (stats,
4199 gettext_noop ("# address validation successes"),
4202 /* create the updated HELLO */
4203 GNUNET_CRYPTO_hash (&ve->publicKey,
4204 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4205 &target.hashPubKey);
4206 if (ve->addr != NULL)
4208 avac.done = GNUNET_NO;
4210 hello = GNUNET_HELLO_create (&ve->publicKey,
4211 &add_validated_address,
4213 GNUNET_PEERINFO_add_peer (peerinfo,
4215 GNUNET_free (hello);
4217 n = find_neighbour (&target);
4220 n->publicKey = ve->publicKey;
4221 n->public_key_valid = GNUNET_YES;
4222 fal = add_peer_address (n,
4227 GNUNET_assert (fal != NULL);
4228 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4229 fal->validated = GNUNET_YES;
4230 mark_address_connected (fal);
4231 GNUNET_STATISTICS_update (stats,
4232 gettext_noop ("# peer addresses considered valid"),
4235 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4236 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4238 schedule_next_ping (fal);
4239 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4240 n->latency = fal->latency;
4242 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4244 n->distance = fal->distance;
4245 if (GNUNET_NO == n->received_pong)
4247 n->received_pong = GNUNET_YES;
4248 notify_clients_connect (&target, n->latency, n->distance);
4249 if (NULL != (prem = n->pre_connect_message_buffer))
4251 n->pre_connect_message_buffer = NULL;
4252 handle_payload_message (prem, n);
4256 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4258 GNUNET_SCHEDULER_cancel (n->retry_task);
4259 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4260 try_transmission_to_peer (n);
4264 /* clean up validation entry */
4265 GNUNET_assert (GNUNET_YES ==
4266 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4269 abort_validation (NULL, NULL, ve);
4275 * Function that will be called if we receive a validation
4276 * of an address challenge that we transmitted to another
4277 * peer. Note that the validation should only be considered
4278 * acceptable if the challenge matches AND if the sender
4279 * address is at least a plausible address for this peer
4280 * (otherwise we may be seeing a MiM attack).
4282 * @param cls closure
4283 * @param message the pong message
4284 * @param peer who responded to our challenge
4285 * @param sender_address string describing our sender address (as observed
4286 * by the other peer in binary format)
4287 * @param sender_address_len number of bytes in 'sender_address'
4290 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4291 const struct GNUNET_PeerIdentity *peer,
4292 const char *sender_address,
4293 size_t sender_address_len)
4295 if (0 == memcmp (peer,
4297 sizeof (struct GNUNET_PeerIdentity)))
4299 /* PONG send to self, ignore */
4300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4301 "Receiving `%s' message from myself\n",
4305 #if DEBUG_TRANSPORT > 1
4306 /* we get tons of these that just get discarded, only log
4307 if we are quite verbose */
4308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4309 "Receiving `%s' message from `%4s'.\n", "PONG",
4312 GNUNET_STATISTICS_update (stats,
4313 gettext_noop ("# PONG messages received"),
4316 if (GNUNET_SYSERR !=
4317 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4319 &check_pending_validation,
4322 /* This is *expected* to happen a lot since we send
4323 PONGs to *all* known addresses of the sender of
4324 the PING, so most likely we get multiple PONGs
4325 per PING, and all but the first PONG will end up
4326 here. So really we should not print anything here
4327 unless we want to be very, very verbose... */
4328 #if DEBUG_TRANSPORT > 2
4329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4330 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4342 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4344 * @param cls the 'struct ValidationEntry*'
4345 * @param neighbour neighbour to validate, NULL if validation failed
4348 transmit_hello_and_ping (void *cls,
4349 struct NeighbourMapEntry *neighbour)
4351 struct ValidationEntry *va = cls;
4352 struct ForeignAddressList *peer_address;
4353 struct TransportPingMessage ping;
4354 uint16_t hello_size;
4357 struct GNUNET_PeerIdentity id;
4360 GNUNET_CRYPTO_hash (&va->publicKey,
4361 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4363 if (neighbour == NULL)
4365 /* FIXME: stats... */
4366 GNUNET_break (GNUNET_OK ==
4367 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4370 abort_validation (NULL, NULL, va);
4373 neighbour->publicKey = va->publicKey;
4374 neighbour->public_key_valid = GNUNET_YES;
4375 peer_address = add_peer_address (neighbour,
4376 va->transport_name, NULL,
4377 (const void*) &va[1],
4379 if (peer_address == NULL)
4381 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4382 "Failed to add peer `%4s' for plugin `%s'\n",
4383 GNUNET_i2s (&neighbour->id),
4384 va->transport_name);
4385 GNUNET_break (GNUNET_OK ==
4386 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4389 abort_validation (NULL, NULL, va);
4392 if (NULL == our_hello)
4393 refresh_hello_task (NULL, NULL);
4394 hello_size = GNUNET_HELLO_size(our_hello);
4395 slen = strlen(va->transport_name) + 1;
4396 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4397 message_buf = GNUNET_malloc(tsize);
4398 ping.challenge = htonl(va->challenge);
4399 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4400 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4401 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4402 memcpy(message_buf, our_hello, hello_size);
4403 memcpy(&message_buf[hello_size],
4405 sizeof(struct TransportPingMessage));
4406 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4409 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4414 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4417 : a2s (va->transport_name,
4418 (const void*) &va[1], va->addrlen),
4420 GNUNET_i2s (&neighbour->id),
4421 "HELLO", hello_size,
4422 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4425 GNUNET_STATISTICS_update (stats,
4426 gettext_noop ("# PING messages sent for initial validation"),
4429 transmit_to_peer (NULL, peer_address,
4430 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4431 HELLO_VERIFICATION_TIMEOUT,
4433 GNUNET_YES, neighbour);
4434 GNUNET_free (message_buf);
4439 * Check if the given address is already being validated; if not,
4440 * append the given address to the list of entries that are being be
4441 * validated and initiate validation.
4443 * @param cls closure ('struct CheckHelloValidatedContext *')
4444 * @param tname name of the transport
4445 * @param expiration expiration time
4446 * @param addr the address
4447 * @param addrlen length of the address
4448 * @return GNUNET_OK (always)
4451 run_validation (void *cls,
4453 struct GNUNET_TIME_Absolute expiration,
4457 struct CheckHelloValidatedContext *chvc = cls;
4458 struct GNUNET_PeerIdentity id;
4459 struct TransportPlugin *tp;
4460 struct ValidationEntry *va;
4461 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4462 struct CheckAddressExistsClosure caec;
4463 struct OwnAddressList *oal;
4465 GNUNET_assert (addr != NULL);
4467 GNUNET_STATISTICS_update (stats,
4468 gettext_noop ("# peer addresses scheduled for validation"),
4471 tp = find_transport (tname);
4474 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4475 GNUNET_ERROR_TYPE_BULK,
4477 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4479 GNUNET_STATISTICS_update (stats,
4480 gettext_noop ("# peer addresses not validated (plugin not available)"),
4485 /* check if this is one of our own addresses */
4486 oal = tp->addresses;
4489 if ( (oal->addrlen == addrlen) &&
4490 (0 == memcmp (&oal[1],
4494 /* not plausible, this address is equivalent to our own address! */
4495 GNUNET_STATISTICS_update (stats,
4496 gettext_noop ("# peer addresses not validated (loopback)"),
4503 GNUNET_HELLO_get_key (chvc->hello, &pk);
4504 GNUNET_CRYPTO_hash (&pk,
4506 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4509 if (is_blacklisted(&id, tp))
4512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4513 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4521 caec.addrlen = addrlen;
4522 caec.session = NULL;
4524 caec.exists = GNUNET_NO;
4525 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4526 &check_address_exists,
4528 if (caec.exists == GNUNET_YES)
4530 /* During validation attempts we will likely trigger the other
4531 peer trying to validate our address which in turn will cause
4532 it to send us its HELLO, so we expect to hit this case rather
4533 frequently. Only print something if we are very verbose. */
4534 #if DEBUG_TRANSPORT > 1
4535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4536 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4537 a2s (tname, addr, addrlen),
4541 GNUNET_STATISTICS_update (stats,
4542 gettext_noop ("# peer addresses not validated (in progress)"),
4547 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4550 va->transport_name = GNUNET_strdup (tname);
4551 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4553 va->send_time = GNUNET_TIME_absolute_get();
4554 va->addr = (const void*) &va[1];
4555 memcpy (&va[1], addr, addrlen);
4556 va->addrlen = addrlen;
4557 GNUNET_HELLO_get_key (chvc->hello,
4559 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4560 &timeout_hello_validation,
4562 GNUNET_CONTAINER_multihashmap_put (validation_map,
4565 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4566 setup_peer_check_blacklist (&id, GNUNET_NO,
4567 &transmit_hello_and_ping,
4574 * Check if addresses in validated hello "h" overlap with
4575 * those in "chvc->hello" and validate the rest.
4577 * @param cls closure
4578 * @param peer id of the peer, NULL for last call
4579 * @param h hello message for the peer (can be NULL)
4580 * @param err_msg NULL if successful, otherwise contains error message
4583 check_hello_validated (void *cls,
4584 const struct GNUNET_PeerIdentity *peer,
4585 const struct GNUNET_HELLO_Message *h,
4586 const char *err_msg)
4588 struct CheckHelloValidatedContext *chvc = cls;
4589 struct GNUNET_HELLO_Message *plain_hello;
4590 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4591 struct GNUNET_PeerIdentity target;
4592 struct NeighbourMapEntry *n;
4594 if (err_msg != NULL)
4597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4598 _("Error in communication with PEERINFO service: %s\n"),
4606 GNUNET_STATISTICS_update (stats,
4607 gettext_noop ("# outstanding peerinfo iterate requests"),
4611 if (GNUNET_NO == chvc->hello_known)
4613 /* notify PEERINFO about the peer now, so that we at least
4614 have the public key if some other component needs it */
4615 GNUNET_HELLO_get_key (chvc->hello, &pk);
4616 GNUNET_CRYPTO_hash (&pk,
4617 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4618 &target.hashPubKey);
4619 plain_hello = GNUNET_HELLO_create (&pk,
4622 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4623 GNUNET_free (plain_hello);
4624 #if DEBUG_TRANSPORT_HELLO
4625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4626 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4628 GNUNET_i2s (&target));
4630 GNUNET_STATISTICS_update (stats,
4631 gettext_noop ("# new HELLOs requiring full validation"),
4634 GNUNET_HELLO_iterate_addresses (chvc->hello,
4641 GNUNET_STATISTICS_update (stats,
4642 gettext_noop ("# duplicate HELLO (peer known)"),
4647 if (chvc->ve_count == 0)
4649 GNUNET_CONTAINER_DLL_remove (chvc_head,
4658 #if DEBUG_TRANSPORT_HELLO
4659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4660 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4664 chvc->hello_known = GNUNET_YES;
4665 n = find_neighbour (peer);
4668 #if DEBUG_TRANSPORT_HELLO
4669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4670 "Calling hello_iterate_addresses for %s!\n",
4673 GNUNET_HELLO_iterate_addresses (h,
4675 &add_to_foreign_address_list,
4677 try_transmission_to_peer (n);
4681 #if DEBUG_TRANSPORT_HELLO
4682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4683 "No existing neighbor record for %s!\n",
4686 GNUNET_STATISTICS_update (stats,
4687 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4691 GNUNET_STATISTICS_update (stats,
4692 gettext_noop ("# HELLO validations (update case)"),
4695 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4697 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4704 * Process HELLO-message.
4706 * @param plugin transport involved, may be NULL
4707 * @param message the actual message
4708 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4711 process_hello (struct TransportPlugin *plugin,
4712 const struct GNUNET_MessageHeader *message)
4715 struct GNUNET_PeerIdentity target;
4716 const struct GNUNET_HELLO_Message *hello;
4717 struct CheckHelloValidatedContext *chvc;
4718 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4719 struct NeighbourMapEntry *n;
4720 #if DEBUG_TRANSPORT_HELLO > 2
4724 hsize = ntohs (message->size);
4725 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4726 (hsize < sizeof (struct GNUNET_MessageHeader)))
4729 return GNUNET_SYSERR;
4731 GNUNET_STATISTICS_update (stats,
4732 gettext_noop ("# HELLOs received for validation"),
4736 hello = (const struct GNUNET_HELLO_Message *) message;
4737 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4739 #if DEBUG_TRANSPORT_HELLO
4740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4741 "Unable to get public key from `%s' for `%4s'!\n",
4743 GNUNET_i2s (&target));
4745 GNUNET_break_op (0);
4746 return GNUNET_SYSERR;
4748 GNUNET_CRYPTO_hash (&publicKey,
4749 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4750 &target.hashPubKey);
4752 #if DEBUG_TRANSPORT_HELLO
4753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4754 "Received `%s' message for `%4s'\n",
4756 GNUNET_i2s (&target));
4758 if (0 == memcmp (&my_identity,
4760 sizeof (struct GNUNET_PeerIdentity)))
4762 GNUNET_STATISTICS_update (stats,
4763 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4768 n = find_neighbour (&target);
4770 (! n->public_key_valid) )
4772 GNUNET_HELLO_get_key (hello, &n->publicKey);
4773 n->public_key_valid = GNUNET_YES;
4776 /* check if load is too high before doing expensive stuff */
4777 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4779 GNUNET_STATISTICS_update (stats,
4780 gettext_noop ("# HELLOs ignored due to high load"),
4783 #if DEBUG_TRANSPORT_HELLO
4784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4785 "Ignoring `%s' for `%4s', load too high.\n",
4787 GNUNET_i2s (&target));
4794 while (NULL != chvc)
4796 if (GNUNET_HELLO_equals (hello,
4798 GNUNET_TIME_absolute_get ()).abs_value > 0)
4800 #if DEBUG_TRANSPORT_HELLO > 2
4801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4802 "Received duplicate `%s' message for `%4s'; ignored\n",
4804 GNUNET_i2s (&target));
4806 return GNUNET_OK; /* validation already pending */
4808 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4809 GNUNET_break (0 != memcmp (hello, chvc->hello,
4810 GNUNET_HELLO_size(hello)));
4815 struct NeighbourMapEntry *temp_neighbor = find_neighbour(&target);
4816 if ((NULL != temp_neighbor))
4818 fprintf(stderr, "Already know peer, ignoring hello\n");
4823 #if DEBUG_TRANSPORT_HELLO > 2
4827 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4829 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4832 GNUNET_i2s (&target),
4834 GNUNET_HELLO_size(hello));
4835 GNUNET_free (my_id);
4839 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4841 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4842 memcpy (&chvc[1], hello, hsize);
4843 GNUNET_CONTAINER_DLL_insert (chvc_head,
4846 /* finally, check if HELLO was previously validated
4847 (continuation will then schedule actual validation) */
4848 GNUNET_STATISTICS_update (stats,
4849 gettext_noop ("# peerinfo process hello iterate requests"),
4852 GNUNET_STATISTICS_update (stats,
4853 gettext_noop ("# outstanding peerinfo iterate requests"),
4856 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4858 HELLO_VERIFICATION_TIMEOUT,
4859 &check_hello_validated, chvc);
4865 * The peer specified by the given neighbour has timed-out or a plugin
4866 * has disconnected. We may either need to do nothing (other plugins
4867 * still up), or trigger a full disconnect and clean up. This
4868 * function updates our state and does the necessary notifications.
4869 * Also notifies our clients that the neighbour is now officially
4872 * @param n the neighbour list entry for the peer
4873 * @param check GNUNET_YES to check if ALL addresses for this peer
4874 * are gone, GNUNET_NO to force a disconnect of the peer
4875 * regardless of whether other addresses exist.
4878 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4880 struct ReadyList *rpos;
4881 struct MessageQueue *mq;
4882 struct ForeignAddressList *peer_addresses;
4883 struct ForeignAddressList *peer_pos;
4885 if (GNUNET_YES == n->in_disconnect)
4887 if (GNUNET_YES == check)
4890 while (NULL != rpos)
4892 peer_addresses = rpos->addresses;
4893 while (peer_addresses != NULL)
4895 /* Do not disconnect if: an address is connected or an inbound address exists */
4896 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4900 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4901 GNUNET_i2s (&n->id),
4902 a2s (peer_addresses->ready_list->plugin->short_name,
4903 peer_addresses->addr,
4904 peer_addresses->addrlen));
4906 return; /* still connected */
4908 peer_addresses = peer_addresses->next;
4914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4915 "Disconnecting from `%4s'\n",
4916 GNUNET_i2s (&n->id));
4918 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4920 /* notify all clients about disconnect */
4921 if (GNUNET_YES == n->received_pong)
4923 n->received_pong = GNUNET_NO;
4924 notify_clients_disconnect (&n->id);
4927 ats_modify_problem_state(ats, ATS_MODIFIED);
4929 /* clean up all plugins, cancel connections and pending transmissions */
4930 while (NULL != (rpos = n->plugins))
4932 n->plugins = rpos->next;
4933 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4934 while (rpos->addresses != NULL)
4936 peer_pos = rpos->addresses;
4937 rpos->addresses = peer_pos->next;
4938 if (peer_pos->connected == GNUNET_YES)
4940 GNUNET_STATISTICS_update (stats,
4941 gettext_noop ("# connected addresses"),
4944 peer_pos->connected = GNUNET_NO;
4946 if (GNUNET_YES == peer_pos->validated)
4947 GNUNET_STATISTICS_update (stats,
4948 gettext_noop ("# peer addresses considered valid"),
4951 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4953 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4954 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4956 GNUNET_free (peer_pos->ressources);
4957 peer_pos->ressources = NULL;
4958 GNUNET_free (peer_pos->quality);
4959 peer_pos->ressources = NULL;
4960 GNUNET_free (peer_pos);
4965 /* free all messages on the queue */
4966 while (NULL != (mq = n->messages_head))
4968 GNUNET_STATISTICS_update (stats,
4969 gettext_noop ("# bytes in message queue for other peers"),
4970 - (int64_t) mq->message_buf_size,
4972 GNUNET_STATISTICS_update (stats,
4973 gettext_noop ("# bytes discarded due to disconnect"),
4974 mq->message_buf_size,
4976 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4979 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4981 sizeof(struct GNUNET_PeerIdentity)));
4985 while (NULL != (mq = n->cont_head))
4988 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4991 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4993 sizeof(struct GNUNET_PeerIdentity)));
4997 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4999 GNUNET_SCHEDULER_cancel (n->timeout_task);
5000 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
5002 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
5004 GNUNET_SCHEDULER_cancel (n->retry_task);
5005 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
5007 if (n->piter != NULL)
5009 GNUNET_PEERINFO_iterate_cancel (n->piter);
5010 GNUNET_STATISTICS_update (stats,
5011 gettext_noop ("# outstanding peerinfo iterate requests"),
5017 GNUNET_assert (GNUNET_OK ==
5018 GNUNET_CONTAINER_multihashmap_remove (neighbours,
5021 /* finally, free n itself */
5022 GNUNET_STATISTICS_update (stats,
5023 gettext_noop ("# active neighbours"),
5026 GNUNET_free_non_null (n->pre_connect_message_buffer);
5032 * We have received a PING message from someone. Need to send a PONG message
5033 * in response to the peer by any means necessary.
5036 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5037 const struct GNUNET_PeerIdentity *peer,
5038 struct Session *session,
5039 const char *sender_address,
5040 uint16_t sender_address_len)
5042 struct TransportPlugin *plugin = cls;
5043 struct SessionHeader *session_header = (struct SessionHeader*) session;
5044 struct TransportPingMessage *ping;
5045 struct TransportPongMessage *pong;
5046 struct NeighbourMapEntry *n;
5047 struct ReadyList *rl;
5048 struct ForeignAddressList *fal;
5049 struct OwnAddressList *oal;
5055 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5057 GNUNET_break_op (0);
5058 return GNUNET_SYSERR;
5061 ping = (struct TransportPingMessage *) message;
5062 if (0 != memcmp (&ping->target,
5063 plugin->env.my_identity,
5064 sizeof (struct GNUNET_PeerIdentity)))
5067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5068 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5070 (sender_address != NULL)
5071 ? a2s (plugin->short_name,
5072 (const struct sockaddr *)sender_address,
5075 GNUNET_i2s (&ping->target));
5077 return GNUNET_SYSERR;
5080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5081 "Processing `%s' from `%s'\n",
5083 (sender_address != NULL)
5084 ? a2s (plugin->short_name,
5085 (const struct sockaddr *)sender_address,
5089 GNUNET_STATISTICS_update (stats,
5090 gettext_noop ("# PING messages received"),
5093 addr = (const char*) &ping[1];
5094 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5095 slen = strlen (plugin->short_name) + 1;
5098 /* peer wants to confirm that we have an outbound connection to him */
5099 if (session == NULL)
5101 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5102 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5104 return GNUNET_SYSERR;
5106 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5107 1) it is NULL when we need to have a real value
5108 2) it is documented to be the address of the sender (source-IP), where
5109 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5113 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5114 a2s (plugin->short_name,
5116 sender_address_len),
5119 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5120 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5121 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5122 pong->purpose.size =
5123 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5125 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5126 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5127 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5128 pong->challenge = ping->challenge;
5129 pong->addrlen = htonl(sender_address_len + slen);
5132 sizeof(struct GNUNET_PeerIdentity));
5136 if ((sender_address!=NULL) && (sender_address_len > 0))
5137 memcpy (&((char*)&pong[1])[slen],
5139 sender_address_len);
5140 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5142 /* create / update cached sig */
5144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5145 "Creating PONG signature to indicate active connection.\n");
5147 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5148 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5149 GNUNET_assert (GNUNET_OK ==
5150 GNUNET_CRYPTO_rsa_sign (my_private_key,
5152 &session_header->pong_signature));
5156 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5158 memcpy (&pong->signature,
5159 &session_header->pong_signature,
5160 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5166 /* peer wants to confirm that this is one of our addresses */
5170 plugin->api->check_address (plugin->api->cls,
5174 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5175 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5176 a2s (plugin->short_name,
5181 oal = plugin->addresses;
5184 if ( (oal->addrlen == alen) &&
5191 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5192 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5193 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5194 pong->purpose.size =
5195 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5197 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5198 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5199 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5200 pong->challenge = ping->challenge;
5201 pong->addrlen = htonl(alen + slen);
5204 sizeof(struct GNUNET_PeerIdentity));
5205 memcpy (&pong[1], plugin->short_name, slen);
5206 memcpy (&((char*)&pong[1])[slen], addr, alen);
5207 if ( (oal != NULL) &&
5208 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5210 /* create / update cached sig */
5212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5213 "Creating PONG signature to indicate ownership.\n");
5215 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5216 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5217 GNUNET_assert (GNUNET_OK ==
5218 GNUNET_CRYPTO_rsa_sign (my_private_key,
5220 &oal->pong_signature));
5221 memcpy (&pong->signature,
5222 &oal->pong_signature,
5223 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5225 else if (oal == NULL)
5227 /* not using cache (typically DV-only) */
5228 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5229 GNUNET_assert (GNUNET_OK ==
5230 GNUNET_CRYPTO_rsa_sign (my_private_key,
5236 /* can used cached version */
5237 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5238 memcpy (&pong->signature,
5239 &oal->pong_signature,
5240 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5243 n = find_neighbour(peer);
5244 GNUNET_assert (n != NULL);
5245 did_pong = GNUNET_NO;
5246 /* first try reliable response transmission */
5250 fal = rl->addresses;
5253 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5256 ntohs (pong->header.size),
5257 TRANSPORT_PONG_PRIORITY,
5258 HELLO_VERIFICATION_TIMEOUT,
5265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5266 "Transmitted PONG to `%s' via reliable mechanism\n",
5269 GNUNET_STATISTICS_update (stats,
5270 gettext_noop ("# PONGs unicast via reliable transport"),
5276 did_pong = GNUNET_YES;
5281 /* no reliable method found, do multicast */
5282 GNUNET_STATISTICS_update (stats,
5283 gettext_noop ("# PONGs multicast to all available addresses"),
5289 fal = rl->addresses;
5292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5293 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5295 a2s (rl->plugin->short_name,
5298 rl->plugin->short_name);
5299 transmit_to_peer(NULL, fal,
5300 TRANSPORT_PONG_PRIORITY,
5301 HELLO_VERIFICATION_TIMEOUT,
5303 ntohs(pong->header.size),
5306 did_pong = GNUNET_YES;
5312 if (GNUNET_YES != did_pong)
5313 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5314 _("Could not send PONG to `%s': no address available\n"),
5321 * Function called by the plugin for each received message. Update
5322 * data volumes, possibly notify plugins about reducing the rate at
5323 * which they read from the socket and generally forward to our
5326 * @param cls the "struct TransportPlugin *" we gave to the plugin
5327 * @param peer (claimed) identity of the other peer
5328 * @param message the message, NULL if we only care about
5329 * learning about the delay until we should receive again
5330 * @param ats_data information for automatic transport selection
5331 * @param ats_count number of elements in ats not including 0-terminator
5332 * @param session identifier used for this session (can be NULL)
5333 * @param sender_address binary address of the sender (if observed)
5334 * @param sender_address_len number of bytes in sender_address
5335 * @return how long in ms the plugin should wait until receiving more data
5336 * (plugins that do not support this, can ignore the return value)
5338 static struct GNUNET_TIME_Relative
5339 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5340 const struct GNUNET_MessageHeader *message,
5341 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5343 struct Session *session,
5344 const char *sender_address,
5345 uint16_t sender_address_len)
5347 struct TransportPlugin *plugin = cls;
5348 struct ReadyList *service_context;
5349 struct ForeignAddressList *peer_address;
5351 struct NeighbourMapEntry *n;
5352 struct GNUNET_TIME_Relative ret;
5356 if (0 == memcmp (peer,
5358 sizeof (struct GNUNET_PeerIdentity)))
5360 /* refuse to receive from myself */
5362 return GNUNET_TIME_UNIT_FOREVER_REL;
5364 if (is_blacklisted (peer, plugin))
5365 return GNUNET_TIME_UNIT_FOREVER_REL;
5366 n = find_neighbour (peer);
5368 n = setup_new_neighbour (peer, GNUNET_YES);
5369 service_context = n->plugins;
5370 while ((service_context != NULL) && (plugin != service_context->plugin))
5371 service_context = service_context->next;
5372 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5373 peer_address = NULL;
5376 for (c=0; c<ats_count; c++)
5377 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5378 distance = ntohl(ats_data[c].value);
5381 if (message != NULL)
5383 if ( (session != NULL) ||
5384 (sender_address != NULL) )
5385 peer_address = add_peer_address (n,
5389 sender_address_len);
5390 if (peer_address != NULL)
5392 update_addr_ats(peer_address, ats_data, ats_count);
5393 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5395 peer_address->distance = distance;
5396 if (GNUNET_YES == peer_address->validated)
5398 mark_address_connected (peer_address);
5399 schedule_next_ping (peer_address);
5404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5405 "New address is unvalidated, trying to validate it now\n");
5407 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5409 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5410 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5412 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5415 peer_address->timeout
5416 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5418 /* update traffic received amount ... */
5419 msize = ntohs (message->size);
5421 GNUNET_STATISTICS_update (stats,
5422 gettext_noop ("# bytes received from other peers"),
5425 n->distance = distance;
5427 GNUNET_TIME_relative_to_absolute
5428 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5429 GNUNET_SCHEDULER_cancel (n->timeout_task);
5431 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5432 &neighbour_timeout_task, n);
5433 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5435 /* dropping message due to frequent inbound volume violations! */
5436 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5437 GNUNET_ERROR_TYPE_BULK,
5439 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5440 n->in_tracker.available_bytes_per_s__,
5441 n->quota_violation_count);
5442 GNUNET_STATISTICS_update (stats,
5443 gettext_noop ("# bandwidth quota violations by other peers"),
5446 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5448 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5449 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5452 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5453 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5454 /* Force ressource and quality update */
5455 if ((value == 4) && (ats != NULL))
5456 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5457 /* Force cost update */
5458 if ((value == 3) && (ats != NULL))
5459 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5460 /* Force quality update */
5461 if ((value == 2) && (ats != NULL))
5462 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5463 /* Force full rebuild */
5464 if ((value == 1) && (ats != NULL))
5465 ats_modify_problem_state(ats, ATS_MODIFIED);
5470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5471 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5472 ntohs (message->type),
5473 ntohs (message->size),
5476 switch (ntohs (message->type))
5478 case GNUNET_MESSAGE_TYPE_HELLO:
5479 GNUNET_STATISTICS_update (stats,
5480 gettext_noop ("# HELLO messages received from other peers"),
5483 process_hello (plugin, message);
5485 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5486 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5487 if (GNUNET_YES != n->received_pong)
5488 transmit_plain_ping (n);
5490 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5491 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5493 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5496 handle_payload_message (message, n);
5500 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5501 if (ret.rel_value > 0)
5504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5505 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5506 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5507 (unsigned int) n->in_tracker.available_bytes_per_s__,
5508 (unsigned long long) ret.rel_value);
5510 GNUNET_STATISTICS_update (stats,
5511 gettext_noop ("# ms throttling suggested"),
5512 (int64_t) ret.rel_value,
5520 notify_client_about_neighbour (void *cls,
5521 const GNUNET_HashCode *key,
5524 struct TransportClient *c = cls;
5525 struct NeighbourMapEntry *n = value;
5526 struct ConnectInfoMessage * cim;
5530 if (GNUNET_YES != n->received_pong)
5534 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5535 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5536 cim = GNUNET_malloc (size);
5537 cim->header.size = htons (size);
5538 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5539 cim->ats_count = htonl(ats_count);
5540 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5541 (&(cim->ats))[2].value = htonl (0);
5542 if (GNUNET_YES == n->received_pong)
5544 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5545 (&cim->ats)[0].value = htonl (n->distance);
5546 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5547 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5549 transmit_to_client (c, &cim->header, GNUNET_NO);
5557 * Handle START-message. This is the first message sent to us
5558 * by any client which causes us to add it to our list.
5560 * @param cls closure (always NULL)
5561 * @param client identification of the client
5562 * @param message the actual message
5565 handle_start (void *cls,
5566 struct GNUNET_SERVER_Client *client,
5567 const struct GNUNET_MessageHeader *message)
5569 const struct StartMessage *start;
5570 struct TransportClient *c;
5572 start = (const struct StartMessage*) message;
5574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5575 "Received `%s' request from client\n", "START");
5580 if (c->client == client)
5582 /* client already on our list! */
5584 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5589 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5590 (0 != memcmp (&start->self,
5592 sizeof (struct GNUNET_PeerIdentity))) )
5594 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5595 _("Rejecting control connection from peer `%s', which is not me!\n"),
5596 GNUNET_i2s (&start->self));
5597 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5600 c = GNUNET_malloc (sizeof (struct TransportClient));
5604 if (our_hello != NULL)
5607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5608 "Sending our own `%s' to new client\n", "HELLO");
5610 transmit_to_client (c,
5611 (const struct GNUNET_MessageHeader *) our_hello,
5613 /* tell new client about all existing connections */
5614 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5615 ¬ify_client_about_neighbour,
5620 #if DEBUG_TRANSPORT_HELLO
5621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5622 "No HELLO created yet, will transmit HELLO to client later!\n");
5626 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5631 * Handle HELLO-message.
5633 * @param cls closure (always NULL)
5634 * @param client identification of the client
5635 * @param message the actual message
5638 handle_hello (void *cls,
5639 struct GNUNET_SERVER_Client *client,
5640 const struct GNUNET_MessageHeader *message)
5644 GNUNET_STATISTICS_update (stats,
5645 gettext_noop ("# HELLOs received from clients"),
5648 ret = process_hello (NULL, message);
5649 GNUNET_SERVER_receive_done (client, ret);
5654 * Closure for 'transmit_client_message'; followed by
5655 * 'msize' bytes of the actual message.
5657 struct TransmitClientMessageContext
5660 * Client on whom's behalf we are sending.
5662 struct GNUNET_SERVER_Client *client;
5665 * Timeout for the transmission.
5667 struct GNUNET_TIME_Absolute timeout;
5675 * Size of the message in bytes.
5682 * Schedule transmission of a message we got from a client to a peer.
5684 * @param cls the 'struct TransmitClientMessageContext*'
5685 * @param n destination, or NULL on error (in that case, drop the message)
5688 transmit_client_message (void *cls,
5689 struct NeighbourMapEntry *n)
5691 struct TransmitClientMessageContext *tcmc = cls;
5692 struct TransportClient *tc;
5695 while ((tc != NULL) && (tc->client != tcmc->client))
5700 transmit_to_peer (tc, NULL, tcmc->priority,
5701 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5703 tcmc->msize, GNUNET_NO, n);
5705 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5706 GNUNET_SERVER_client_drop (tcmc->client);
5712 * Handle SEND-message.
5714 * @param cls closure (always NULL)
5715 * @param client identification of the client
5716 * @param message the actual message
5719 handle_send (void *cls,
5720 struct GNUNET_SERVER_Client *client,
5721 const struct GNUNET_MessageHeader *message)
5723 const struct OutboundMessage *obm;
5724 const struct GNUNET_MessageHeader *obmm;
5725 struct TransmitClientMessageContext *tcmc;
5729 size = ntohs (message->size);
5731 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5734 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5737 GNUNET_STATISTICS_update (stats,
5738 gettext_noop ("# payload received for other peers"),
5741 obm = (const struct OutboundMessage *) message;
5742 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5743 msize = size - sizeof (struct OutboundMessage);
5745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5746 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5747 "SEND", GNUNET_i2s (&obm->peer),
5751 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5752 tcmc->client = client;
5753 tcmc->priority = ntohl (obm->priority);
5754 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5755 tcmc->msize = msize;
5756 /* FIXME: this memcpy can be up to 7% of our total runtime */
5757 memcpy (&tcmc[1], obmm, msize);
5758 GNUNET_SERVER_client_keep (client);
5759 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5760 &transmit_client_message,
5766 * Handle request connect message
5768 * @param cls closure (always NULL)
5769 * @param client identification of the client
5770 * @param message the actual message
5773 handle_request_connect (void *cls,
5774 struct GNUNET_SERVER_Client *client,
5775 const struct GNUNET_MessageHeader *message)
5777 const struct TransportRequestConnectMessage *trcm =
5778 (const struct TransportRequestConnectMessage *) message;
5780 GNUNET_STATISTICS_update (stats,
5781 gettext_noop ("# REQUEST CONNECT messages received"),
5785 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5786 "Received a request connect message for peer `%s'\n",
5787 GNUNET_i2s(&trcm->peer));
5789 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5791 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5796 * Handle SET_QUOTA-message.
5798 * @param cls closure (always NULL)
5799 * @param client identification of the client
5800 * @param message the actual message
5803 handle_set_quota (void *cls,
5804 struct GNUNET_SERVER_Client *client,
5805 const struct GNUNET_MessageHeader *message)
5807 const struct QuotaSetMessage *qsm =
5808 (const struct QuotaSetMessage *) message;
5809 struct NeighbourMapEntry *n;
5811 GNUNET_STATISTICS_update (stats,
5812 gettext_noop ("# SET QUOTA messages received"),
5815 n = find_neighbour (&qsm->peer);
5818 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5819 GNUNET_STATISTICS_update (stats,
5820 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5827 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5829 (unsigned int) ntohl (qsm->quota.value__),
5830 (unsigned int) n->in_tracker.available_bytes_per_s__,
5831 GNUNET_i2s (&qsm->peer));
5833 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5835 if (0 == ntohl (qsm->quota.value__))
5838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5839 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5842 GNUNET_STATISTICS_update (stats,
5843 gettext_noop ("# disconnects due to quota of 0"),
5846 disconnect_neighbour (n, GNUNET_NO);
5848 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5853 * Take the given address and append it to the set of results sent back to
5856 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5857 * @param address the resolved name, NULL to indicate the last response
5860 transmit_address_to_client (void *cls, const char *address)
5862 struct GNUNET_SERVER_TransmitContext *tc = cls;
5865 if (NULL != address)
5867 slen = strlen (address) + 1;
5868 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5869 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5873 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5874 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5875 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5881 * Handle AddressLookup-message.
5883 * @param cls closure (always NULL)
5884 * @param client identification of the client
5885 * @param message the actual message
5888 handle_address_lookup (void *cls,
5889 struct GNUNET_SERVER_Client *client,
5890 const struct GNUNET_MessageHeader *message)
5892 const struct AddressLookupMessage *alum;
5893 struct TransportPlugin *lsPlugin;
5894 const char *nameTransport;
5895 const char *address;
5897 struct GNUNET_SERVER_TransmitContext *tc;
5898 struct GNUNET_TIME_Relative rtimeout;
5901 size = ntohs (message->size);
5902 if (size < sizeof (struct AddressLookupMessage))
5904 GNUNET_break_op (0);
5905 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5908 alum = (const struct AddressLookupMessage *) message;
5909 uint32_t addressLen = ntohl (alum->addrlen);
5910 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5912 GNUNET_break_op (0);
5913 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5916 address = (const char *) &alum[1];
5917 nameTransport = (const char *) &address[addressLen];
5919 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5921 GNUNET_break_op (0);
5922 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5925 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5926 numeric = ntohl (alum->numeric_only);
5927 lsPlugin = find_transport (nameTransport);
5928 if (NULL == lsPlugin)
5930 tc = GNUNET_SERVER_transmit_context_create (client);
5931 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5932 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5933 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5936 GNUNET_SERVER_disable_receive_done_warning (client);
5937 tc = GNUNET_SERVER_transmit_context_create (client);
5938 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5940 address, addressLen,
5943 &transmit_address_to_client, tc);
5947 * Handle PeerAddressLookupMessage.
5949 * @param cls closure (always NULL)
5950 * @param client identification of the client
5951 * @param message the actual message
5954 handle_peer_address_lookup (void *cls,
5955 struct GNUNET_SERVER_Client *client,
5956 const struct GNUNET_MessageHeader *message)
5958 const struct PeerAddressLookupMessage *peer_address_lookup;
5959 struct NeighbourMapEntry *neighbor_iterator;
5960 struct ReadyList *ready_iterator;
5961 struct ForeignAddressList *foreign_address_iterator;
5962 struct TransportPlugin *transport_plugin;
5965 struct GNUNET_SERVER_TransmitContext *tc;
5966 struct GNUNET_TIME_Relative rtimeout;
5969 size = ntohs (message->size);
5970 if (size < sizeof (struct PeerAddressLookupMessage))
5972 GNUNET_break_op (0);
5973 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5976 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5978 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5980 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5982 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5983 if (neighbor_iterator == NULL)
5986 tc = GNUNET_SERVER_transmit_context_create (client);
5987 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5988 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5989 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5993 ready_iterator = neighbor_iterator->plugins;
5994 GNUNET_SERVER_disable_receive_done_warning (client);
5995 tc = GNUNET_SERVER_transmit_context_create (client);
5996 while(ready_iterator != NULL)
5998 foreign_address_iterator = ready_iterator->addresses;
5999 while (foreign_address_iterator != NULL)
6001 transport_plugin = foreign_address_iterator->ready_list->plugin;
6002 if (foreign_address_iterator->addr != NULL)
6004 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
6005 a2s (transport_plugin->short_name,
6006 foreign_address_iterator->addr,
6007 foreign_address_iterator->addrlen),
6008 (foreign_address_iterator->connected
6009 == GNUNET_YES) ? "CONNECTED"
6011 (foreign_address_iterator->validated
6012 == GNUNET_YES) ? "VALIDATED"
6014 transmit_address_to_client(tc, addr_buf);
6015 GNUNET_free (addr_buf);
6017 else if (foreign_address_iterator->addrlen == 0)
6019 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
6020 (foreign_address_iterator->connected
6021 == GNUNET_YES) ? "CONNECTED"
6023 (foreign_address_iterator->validated
6024 == GNUNET_YES) ? "VALIDATED"
6026 transmit_address_to_client (tc, addr_buf);
6027 GNUNET_free (addr_buf);
6030 foreign_address_iterator = foreign_address_iterator->next;
6032 ready_iterator = ready_iterator->next;
6034 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6035 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6036 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6042 output_addresses (void *cls,
6043 const GNUNET_HashCode *key,
6046 struct GNUNET_SERVER_TransmitContext *tc = cls;
6047 struct NeighbourMapEntry *neighbor_iterator = value;
6048 struct ForeignAddressList *foreign_address_iterator;
6049 struct TransportPlugin *transport_plugin;
6050 struct ReadyList *ready_iterator;
6053 ready_iterator = neighbor_iterator->plugins;
6054 while (ready_iterator != NULL)
6056 foreign_address_iterator = ready_iterator->addresses;
6057 while (foreign_address_iterator != NULL)
6059 transport_plugin = foreign_address_iterator->ready_list->plugin;
6060 if (foreign_address_iterator->addr != NULL)
6062 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6063 GNUNET_i2s(&neighbor_iterator->id),
6064 a2s (transport_plugin->short_name,
6065 foreign_address_iterator->addr,
6066 foreign_address_iterator->addrlen),
6067 (foreign_address_iterator->connected
6068 == GNUNET_YES) ? "CONNECTED"
6070 (foreign_address_iterator->validated
6071 == GNUNET_YES) ? "VALIDATED"
6073 transmit_address_to_client (tc, addr_buf);
6074 GNUNET_free (addr_buf);
6076 else if (foreign_address_iterator->addrlen == 0)
6078 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6079 GNUNET_i2s (&neighbor_iterator->id),
6081 (foreign_address_iterator->connected
6082 == GNUNET_YES) ? "CONNECTED"
6084 (foreign_address_iterator->validated
6085 == GNUNET_YES) ? "VALIDATED"
6087 transmit_address_to_client (tc, addr_buf);
6088 GNUNET_free (addr_buf);
6091 foreign_address_iterator = foreign_address_iterator->next;
6093 ready_iterator = ready_iterator->next;
6100 * Handle AddressIterateMessage
6102 * @param cls closure (always NULL)
6103 * @param client identification of the client
6104 * @param message the actual message
6107 handle_address_iterate (void *cls,
6108 struct GNUNET_SERVER_Client *client,
6109 const struct GNUNET_MessageHeader *message)
6111 struct GNUNET_SERVER_TransmitContext *tc;
6114 size = ntohs (message->size);
6115 if (size < sizeof (struct AddressIterateMessage))
6117 GNUNET_break_op (0);
6118 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6121 GNUNET_SERVER_disable_receive_done_warning (client);
6122 tc = GNUNET_SERVER_transmit_context_create (client);
6123 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6126 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6127 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6128 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6132 static const struct GNUNET_MessageHeader *
6135 return (const struct GNUNET_MessageHeader*) our_hello;
6140 * Setup the environment for this plugin.
6143 create_environment (struct TransportPlugin *plug)
6145 plug->env.cfg = cfg;
6146 plug->env.my_identity = &my_identity;
6147 plug->env.get_our_hello = &do_get_our_hello;
6148 plug->env.cls = plug;
6149 plug->env.receive = &plugin_env_receive;
6150 plug->env.notify_address = &plugin_env_notify_address;
6151 plug->env.session_end = &plugin_env_session_end;
6152 plug->env.max_connections = max_connect_per_transport;
6153 plug->env.stats = stats;
6158 * Start the specified transport (load the plugin).
6161 start_transport (struct GNUNET_SERVER_Handle *server,
6164 struct TransportPlugin *plug;
6167 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6168 _("Loading `%s' transport plugin\n"), name);
6169 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6170 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6171 create_environment (plug);
6172 plug->short_name = GNUNET_strdup (name);
6173 plug->lib_name = libname;
6174 plug->next = plugins;
6176 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6177 if (plug->api == NULL)
6179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6180 _("Failed to load transport plugin for `%s'\n"), name);
6181 GNUNET_free (plug->short_name);
6182 plugins = plug->next;
6183 GNUNET_free (libname);
6190 null_mq_client_pointers (void *cls,
6191 const GNUNET_HashCode *key,
6194 struct TransportClient *pos = cls;
6195 struct NeighbourMapEntry *n = value;
6196 struct MessageQueue *mq;
6198 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6200 if (mq->client == pos)
6201 mq->client = NULL; /* do not use anymore! */
6208 * Called whenever a client is disconnected. Frees our
6209 * resources associated with that client.
6211 * @param cls closure
6212 * @param client identification of the client
6215 client_disconnect_notification (void *cls,
6216 struct GNUNET_SERVER_Client *client)
6218 struct TransportClient *pos;
6219 struct TransportClient *prev;
6220 struct ClientMessageQueueEntry *mqe;
6221 struct Blacklisters *bl;
6222 struct BlacklistCheck *bc;
6227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6228 "Client disconnected, cleaning up.\n");
6230 /* clean up blacklister */
6234 if (bl->client == client)
6239 if (bc->bl_pos == bl)
6241 bc->bl_pos = bl->next;
6244 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6247 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6248 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6254 GNUNET_CONTAINER_DLL_remove (bl_head,
6257 GNUNET_SERVER_client_drop (bl->client);
6263 /* clean up 'normal' clients */
6266 while ((pos != NULL) && (pos->client != client))
6273 while (NULL != (mqe = pos->message_queue_head))
6275 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6276 pos->message_queue_tail,
6278 pos->message_count--;
6281 if (NULL != neighbours)
6282 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6283 &null_mq_client_pointers,
6286 clients = pos->next;
6288 prev->next = pos->next;
6289 if (GNUNET_YES == pos->tcs_pending)
6294 if (pos->th != NULL)
6296 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6299 GNUNET_break (0 == pos->message_count);
6305 disconnect_all_neighbours (void *cls,
6306 const GNUNET_HashCode *key,
6309 struct NeighbourMapEntry *n = value;
6312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6313 "Disconnecting peer `%4s', %s\n",
6317 disconnect_neighbour (n, GNUNET_NO);
6323 * Function called when the service shuts down. Unloads our plugins
6324 * and cancels pending validations.
6326 * @param cls closure, unused
6327 * @param tc task context (unused)
6330 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6332 struct TransportPlugin *plug;
6333 struct OwnAddressList *al;
6334 struct CheckHelloValidatedContext *chvc;
6336 shutdown_in_progress = GNUNET_YES;
6337 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6338 &disconnect_all_neighbours,
6341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6342 "Transport service is unloading plugins...\n");
6344 while (NULL != (plug = plugins))
6346 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6348 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6349 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6351 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6352 GNUNET_free (plug->lib_name);
6353 GNUNET_free (plug->short_name);
6354 while (NULL != (al = plug->addresses))
6356 plug->addresses = al->next;
6359 plugins = plug->next;
6362 if (my_private_key != NULL)
6363 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6364 GNUNET_free_non_null (our_hello);
6366 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6369 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6370 validation_map = NULL;
6373 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6375 GNUNET_SCHEDULER_cancel(ats_task);
6376 ats_task = GNUNET_SCHEDULER_NO_TASK;
6383 /* free 'chvc' data structure */
6384 while (NULL != (chvc = chvc_head))
6386 chvc_head = chvc->next;
6387 if (chvc->piter != NULL)
6389 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6390 GNUNET_STATISTICS_update (stats,
6391 gettext_noop ("# outstanding peerinfo iterate requests"),
6398 GNUNET_assert (chvc->ve_count == 0);
6405 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6408 if (peerinfo != NULL)
6410 GNUNET_PEERINFO_disconnect (peerinfo);
6413 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6415 GNUNET_SCHEDULER_cancel (hello_task);
6416 hello_task = GNUNET_SCHEDULER_NO_TASK;
6418 /* Can we assume those are gone by now, or do we need to clean up
6420 GNUNET_break (bl_head == NULL);
6421 GNUNET_break (bc_head == NULL);
6422 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6427 void ats_result_cb ()
6429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6430 "ATS Result callback\n");
6435 struct AtsBuildContext
6437 struct ATS_mechanism * mechanisms;
6438 struct ATS_peer *peers;
6445 find_and_count_addresses (void *cls,
6446 const GNUNET_HashCode *key,
6449 struct AtsBuildContext *abc = cls;
6450 struct NeighbourMapEntry *next = value;
6451 int found_addresses = GNUNET_NO;
6453 struct ReadyList *r_next = next->plugins;
6454 while (r_next != NULL)
6456 struct ForeignAddressList * a_next = r_next->addresses;
6457 while (a_next != NULL)
6460 found_addresses = GNUNET_YES;
6461 a_next = a_next->next;
6463 r_next = r_next->next;
6465 if (found_addresses)
6472 setup_ats_problem (void *cls,
6473 const GNUNET_HashCode *key,
6476 struct AtsBuildContext *abc = cls;
6477 struct NeighbourMapEntry *next = value;
6479 int found_addresses = GNUNET_NO;
6480 struct ReadyList *r_next = next->plugins;
6481 while (r_next != NULL)
6483 struct ForeignAddressList * a_next = r_next->addresses;
6484 while (a_next != NULL)
6486 if (found_addresses == GNUNET_NO)
6488 abc->peers[abc->c_peers].peer = next->id;
6489 abc->peers[abc->c_peers].m_head = NULL;
6490 abc->peers[abc->c_peers].m_tail = NULL;
6491 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6493 abc->mechanisms[abc->c_mechs].addr = a_next;
6494 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6495 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6496 abc->mechanisms[abc->c_mechs].next = NULL;
6497 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6498 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6499 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6500 GNUNET_CONTAINER_DLL_insert_tail(abc->peers[abc->c_peers].m_head,
6501 abc->peers[abc->c_peers].m_tail,
6502 &abc->mechanisms[abc->c_mechs]);
6503 found_addresses = GNUNET_YES;
6505 a_next = a_next->next;
6507 r_next = r_next->next;
6509 if (found_addresses == GNUNET_YES)
6516 create_ats_information ( struct ATS_peer **p,
6518 struct ATS_mechanism ** m,
6521 struct AtsBuildContext abc;
6524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6525 "ATS requires clean address information\n");
6529 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6530 &find_and_count_addresses,
6533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6534 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6537 if ( (abc.c_peers == 0) && (abc.c_mechs == 0) )
6546 abc.mechanisms = GNUNET_malloc((1+abc.c_mechs) * sizeof (struct ATS_mechanism));
6547 abc.peers = GNUNET_malloc((1+abc.c_peers) * sizeof (struct ATS_peer));
6550 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6555 (*c_m) = abc.c_mechs;
6556 (*c_p) = abc.c_peers;
6558 (*m) = abc.mechanisms;
6563 schedule_ats (void *cls,
6564 const struct GNUNET_SCHEDULER_TaskContext *tc)
6566 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6570 ats_task = GNUNET_SCHEDULER_NO_TASK;
6571 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6574 if (shutdown_in_progress == GNUNET_YES)
6577 struct GNUNET_TIME_Relative delta =
6578 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6579 if (delta.rel_value < ats_minimum_interval.rel_value)
6582 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6583 "Minimum time between cycles not reached\n");
6589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6592 ats_calculate_bandwidth_distribution (ats);
6594 last_ats_execution = GNUNET_TIME_absolute_get();
6596 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6597 &schedule_ats, ats);
6602 struct ForeignAddressList * get_preferred_ats_address (
6603 struct NeighbourMapEntry *n)
6605 // TODO get ATS prefered address
6606 return find_ready_address(n);
6610 * Initiate transport service.
6612 * @param cls closure
6613 * @param server the initialized server
6614 * @param c configuration to use
6618 struct GNUNET_SERVER_Handle *server,
6619 const struct GNUNET_CONFIGURATION_Handle *c)
6621 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6622 {&handle_start, NULL,
6623 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6624 {&handle_hello, NULL,
6625 GNUNET_MESSAGE_TYPE_HELLO, 0},
6626 {&handle_send, NULL,
6627 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6628 {&handle_request_connect, NULL,
6629 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6630 {&handle_set_quota, NULL,
6631 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6632 {&handle_address_lookup, NULL,
6633 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6635 {&handle_peer_address_lookup, NULL,
6636 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6638 {&handle_address_iterate, NULL,
6639 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6641 {&handle_blacklist_init, NULL,
6642 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6643 {&handle_blacklist_reply, NULL,
6644 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6650 unsigned long long tneigh;
6653 shutdown_in_progress = GNUNET_NO;
6655 stats = GNUNET_STATISTICS_create ("transport", cfg);
6656 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6657 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6658 /* parse configuration */
6660 GNUNET_CONFIGURATION_get_value_number (c,
6665 GNUNET_CONFIGURATION_get_value_filename (c,
6667 "HOSTKEY", &keyfile)))
6669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6671 ("Transport service is lacking key configuration settings. Exiting.\n"));
6672 GNUNET_SCHEDULER_shutdown ();
6675 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6678 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6679 validation_map = NULL;
6680 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6685 max_connect_per_transport = (uint32_t) tneigh;
6686 peerinfo = GNUNET_PEERINFO_connect (cfg);
6687 if (peerinfo == NULL)
6689 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6690 _("Could not access PEERINFO service. Exiting.\n"));
6691 GNUNET_SCHEDULER_shutdown ();
6694 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6697 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6698 validation_map = NULL;
6699 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6701 GNUNET_free (keyfile);
6704 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6705 GNUNET_free (keyfile);
6706 if (my_private_key == NULL)
6708 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6710 ("Transport service could not access hostkey. Exiting.\n"));
6711 GNUNET_SCHEDULER_shutdown ();
6714 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6717 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6718 validation_map = NULL;
6719 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6723 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6724 GNUNET_CRYPTO_hash (&my_public_key,
6725 sizeof (my_public_key), &my_identity.hashPubKey);
6726 /* setup notification */
6727 GNUNET_SERVER_disconnect_notify (server,
6728 &client_disconnect_notification, NULL);
6729 /* load plugins... */
6732 GNUNET_CONFIGURATION_get_value_string (c,
6733 "TRANSPORT", "PLUGINS", &plugs))
6735 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6736 _("Starting transport plugins `%s'\n"), plugs);
6737 pos = strtok (plugs, " ");
6740 start_transport (server, pos);
6742 pos = strtok (NULL, " ");
6744 GNUNET_free (plugs);
6746 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6747 &shutdown_task, NULL);
6751 /* Initializing ATS */
6754 unsigned long long value;
6759 int v_b_min = 64000;
6763 ats_minimum_interval = ATS_MIN_INTERVAL;
6764 ats_regular_interval = ATS_EXEC_INTERVAL;
6766 /* loading cost ressources */
6767 for (co=0; co<available_ressources; co++)
6769 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6770 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6772 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6779 "Found ressource cost: [%s] = %llu\n",
6782 ressources[co].c_max = value;
6785 GNUNET_free (section);
6786 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6787 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6789 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6796 "Found ressource cost: [%s] = %llu\n",
6799 ressources[co].c_min = value;
6802 GNUNET_free (section);
6805 ats = ats_init (D, U, R, v_b_min, v_n_min,
6806 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6807 &create_ats_information,
6809 ats_set_logging_options (ats,
6812 GNUNET_break (GNUNET_OK ==
6813 GNUNET_CONFIGURATION_get_value_time (cfg,
6815 "ATS_EXEC_INTERVAL",
6816 &ats_regular_interval));
6817 GNUNET_break (GNUNET_OK ==
6818 GNUNET_CONFIGURATION_get_value_time (cfg,
6821 &ats_minimum_interval));
6823 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6828 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6829 _("Transport service ready.\n"));
6831 /* If we have a blacklist file, read from it */
6832 read_blacklist_file(cfg);
6833 /* process client requests */
6834 GNUNET_SERVER_add_handlers (server, handlers);
6839 * The main function for the transport service.
6841 * @param argc number of arguments from the command line
6842 * @param argv command line arguments
6843 * @return 0 ok, 1 on error
6846 main (int argc, char *const *argv)
6848 a2s (NULL, NULL, 0); /* make compiler happy */
6849 return (GNUNET_OK ==
6850 GNUNET_SERVICE_run (argc,
6853 GNUNET_SERVICE_OPTION_NONE,
6854 &run, NULL)) ? 0 : 1;
6857 /* end of gnunet-service-transport.c */