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_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 NeighbourList;
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 NeighbourList *neighbour;
442 * Entry in linked list of all of our current neighbours.
448 * This is a linked list.
450 struct NeighbourList *next;
453 * Which of our transports is connected to this peer
454 * and what is their status?
456 struct ReadyList *plugins;
459 * Head of list of messages we would like to send to this peer;
460 * must contain at most one message per client.
462 struct MessageQueue *messages_head;
465 * Tail of list of messages we would like to send to this peer; must
466 * contain at most one message per client.
468 struct MessageQueue *messages_tail;
471 * Head of list of messages of messages we expected the continuation
472 * to be called to destroy the message
474 struct MessageQueue *cont_head;
477 * Tail of list of messages of messages we expected the continuation
478 * to be called to destroy the message
480 struct MessageQueue *cont_tail;
483 * Buffer for at most one payload message used when we receive
484 * payload data before our PING-PONG has succeeded. We then
485 * store such messages in this intermediary buffer until the
486 * connection is fully up.
488 struct GNUNET_MessageHeader *pre_connect_message_buffer;
491 * Context for peerinfo iteration.
492 * NULL after we are done processing peerinfo's information.
494 struct GNUNET_PEERINFO_IteratorContext *piter;
497 * Public key for this peer. Valid only if the respective flag is set below.
499 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
502 * Identity of this neighbour.
504 struct GNUNET_PeerIdentity id;
507 * ID of task scheduled to run when this peer is about to
508 * time out (will free resources associated with the peer).
510 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
513 * ID of task scheduled to run when we should retry transmitting
514 * the head of the message queue. Actually triggered when the
515 * transmission is timing out (we trigger instantly when we have
516 * a chance of success).
518 GNUNET_SCHEDULER_TaskIdentifier retry_task;
521 * How long until we should consider this peer dead
522 * (if we don't receive another message in the
525 struct GNUNET_TIME_Absolute peer_timeout;
528 * Tracker for inbound bandwidth.
530 struct GNUNET_BANDWIDTH_Tracker in_tracker;
533 * The latency we have seen for this particular address for
534 * this particular peer. This latency may have been calculated
535 * over multiple transports. This value reflects how long it took
536 * us to receive a response when SENDING via this particular
537 * transport/neighbour/address combination!
539 * FIXME: we need to periodically send PINGs to update this
540 * latency (at least more often than the current "huge" (11h?)
543 struct GNUNET_TIME_Relative latency;
546 * How often has the other peer (recently) violated the
547 * inbound traffic limit? Incremented by 10 per violation,
548 * decremented by 1 per non-violation (for each
551 unsigned int quota_violation_count;
554 * DV distance to this peer (1 if no DV is used).
559 * Have we seen an PONG from this neighbour in the past (and
560 * not had a disconnect since)?
565 * Do we have a valid public key for this neighbour?
567 int public_key_valid;
570 * Are we already in the process of disconnecting this neighbour?
575 * Performance data for the peer.
577 struct GNUNET_TRANSPORT_ATS_Information *ats;
581 * Message used to ask a peer to validate receipt (to check an address
582 * from a HELLO). Followed by the address we are trying to validate,
583 * or an empty address if we are just sending a PING to confirm that a
584 * connection which the receiver (of the PING) initiated is still valid.
586 struct TransportPingMessage
590 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
592 struct GNUNET_MessageHeader header;
595 * Challenge code (to ensure fresh reply).
597 uint32_t challenge GNUNET_PACKED;
600 * Who is the intended recipient?
602 struct GNUNET_PeerIdentity target;
608 * Message used to validate a HELLO. The challenge is included in the
609 * confirmation to make matching of replies to requests possible. The
610 * signature signs our public key, an expiration time and our address.<p>
612 * This message is followed by our transport address that the PING tried
613 * to confirm (if we liked it). The address can be empty (zero bytes)
614 * if the PING had not address either (and we received the request via
615 * a connection that we initiated).
617 struct TransportPongMessage
621 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
623 struct GNUNET_MessageHeader header;
626 * Challenge code from PING (showing freshness). Not part of what
627 * is signed so that we can re-use signatures.
629 uint32_t challenge GNUNET_PACKED;
634 struct GNUNET_CRYPTO_RsaSignature signature;
637 * What are we signing and why? Two possible reason codes can be here:
638 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
639 * plausible address for this peer (pid is set to identity of signer); or
640 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
641 * an address we used to connect to the peer with the given pid.
643 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
646 * When does this signature expire?
648 struct GNUNET_TIME_AbsoluteNBO expiration;
651 * Either the identity of the peer Who signed this message, or the
652 * identity of the peer that we're connected to using the given
653 * address (depending on purpose.type).
655 struct GNUNET_PeerIdentity pid;
658 * Size of address appended to this message (part of what is
659 * being signed, hence not redundant).
667 * Linked list of messages to be transmitted to the client. Each
668 * entry is followed by the actual message.
670 struct ClientMessageQueueEntry
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *next;
678 * This is a doubly-linked list.
680 struct ClientMessageQueueEntry *prev;
685 * Client connected to the transport service.
687 struct TransportClient
691 * This is a linked list.
693 struct TransportClient *next;
696 * Handle to the client.
698 struct GNUNET_SERVER_Client *client;
701 * Linked list of messages yet to be transmitted to
704 struct ClientMessageQueueEntry *message_queue_head;
707 * Tail of linked list of messages yet to be transmitted to the
710 struct ClientMessageQueueEntry *message_queue_tail;
713 * Current transmit request handle.
715 struct GNUNET_CONNECTION_TransmitHandle *th;
718 * Is a call to "transmit_send_continuation" pending? If so, we
719 * must not free this struct (even if the corresponding client
720 * disconnects) and instead only remove it from the linked list and
721 * set the "client" field to NULL.
726 * Length of the list of messages pending for this client.
728 unsigned int message_count;
734 * Context of currently active requests to peerinfo
735 * for validation of HELLOs.
737 struct CheckHelloValidatedContext;
741 * Entry in map of all HELLOs awaiting validation.
743 struct ValidationEntry
747 * NULL if this entry is not part of a larger HELLO validation.
749 struct CheckHelloValidatedContext *chvc;
752 * The address, actually a pointer to the end
753 * of this struct. Do not free!
758 * Name of the transport.
760 char *transport_name;
763 * The public key of the peer.
765 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
768 * ID of task that will clean up this entry if we don't succeed
769 * with the validation first.
771 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
774 * At what time did we send this validation?
776 struct GNUNET_TIME_Absolute send_time;
779 * Session being validated (or NULL for none).
781 struct Session *session;
784 * Challenge number we used.
797 * Context of currently active requests to peerinfo
798 * for validation of HELLOs.
800 struct CheckHelloValidatedContext
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *next;
809 * This is a doubly-linked list.
811 struct CheckHelloValidatedContext *prev;
814 * Hello that we are validating.
816 const struct GNUNET_HELLO_Message *hello;
819 * Context for peerinfo iteration.
820 * NULL after we are done processing peerinfo's information.
822 struct GNUNET_PEERINFO_IteratorContext *piter;
825 * Was a HELLO known for this peer to peerinfo?
830 * Number of validation entries currently referring to this
833 unsigned int ve_count;
838 * All zero hash for comparison.
840 static GNUNET_HashCode null_hash;
845 static struct GNUNET_HELLO_Message *our_hello;
850 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
855 static struct GNUNET_PeerIdentity my_identity;
860 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
865 const struct GNUNET_CONFIGURATION_Handle *cfg;
868 * Linked list of all clients to this service.
870 static struct TransportClient *clients;
873 * All loaded plugins.
875 static struct TransportPlugin *plugins;
878 * Handle to peerinfo service.
880 static struct GNUNET_PEERINFO_Handle *peerinfo;
883 * All known neighbours and their HELLOs.
885 static struct NeighbourList *neighbours;
888 * Number of neighbours we'd like to have.
890 static uint32_t max_connect_per_transport;
893 * Head of linked list.
895 static struct CheckHelloValidatedContext *chvc_head;
898 * Tail of linked list.
900 static struct CheckHelloValidatedContext *chvc_tail;
903 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
904 * of the given peer that we are currently validating).
906 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
909 * Handle for reporting statistics.
911 static struct GNUNET_STATISTICS_Handle *stats;
914 * Identifier of 'refresh_hello' task.
916 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
919 * Identifier of ats scheduler task.
921 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
924 * Is transport service shutting down ?
926 static int shutdown_in_progress;
929 * Handle for ats information
931 static struct ATS_Handle *ats;
934 * Time of last ats execution
936 struct GNUNET_TIME_Absolute last_ats_execution;
938 * Minimum interval between two ATS executions
940 struct GNUNET_TIME_Relative ats_minimum_interval;
942 * Regular interval when ATS execution is triggered
944 struct GNUNET_TIME_Relative ats_regular_interval;
947 * The peer specified by the given neighbour has timed-out or a plugin
948 * has disconnected. We may either need to do nothing (other plugins
949 * still up), or trigger a full disconnect and clean up. This
950 * function updates our state and do the necessary notifications.
951 * Also notifies our clients that the neighbour is now officially
954 * @param n the neighbour list entry for the peer
955 * @param check should we just check if all plugins
956 * disconnected or must we ask all plugins to
959 static void disconnect_neighbour (struct NeighbourList *n, int check);
962 * Check the ready list for the given neighbour and if a plugin is
963 * ready for transmission (and if we have a message), do so!
965 * @param nexi target peer for which to transmit
967 static void try_transmission_to_peer (struct NeighbourList *n);
969 struct ForeignAddressList * get_preferred_ats_address (
970 struct NeighbourList *n);
973 * Find an entry in the neighbour list for a particular peer.
975 * @return NULL if not found.
977 static struct NeighbourList *
978 find_neighbour (const struct GNUNET_PeerIdentity *key)
980 struct NeighbourList *head = neighbours;
982 while ((head != NULL) &&
983 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
988 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
992 for (c=0; c<available_quality_metrics; c++)
994 if (ats_index == qm[c].atis_index)
996 fal->quality[c].values[0] = fal->quality[c].values[1];
997 fal->quality[c].values[1] = fal->quality[c].values[2];
998 fal->quality[c].values[2] = value;
1000 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1003 if (set == GNUNET_NO)
1005 for (c=0; c<available_ressources; c++)
1007 if (ats_index == ressources[c].atis_index)
1009 fal->ressources[c].c = value;
1011 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1019 update_addr_ats (struct ForeignAddressList *fal,
1020 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1025 for (c1=0; c1<ats_count; c1++)
1027 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1033 * Find an entry in the transport list for a particular transport.
1035 * @return NULL if not found.
1037 static struct TransportPlugin *
1038 find_transport (const char *short_name)
1040 struct TransportPlugin *head = plugins;
1041 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1047 * Is a particular peer blacklisted for a particular transport?
1049 * @param peer the peer to check for
1050 * @param plugin the plugin used to connect to the peer
1052 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1055 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1058 if (plugin->blacklist != NULL)
1060 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 "Peer `%s:%s' is blacklisted!\n",
1065 plugin->short_name, GNUNET_i2s (peer));
1068 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1078 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1079 char *transport_name)
1081 struct TransportPlugin *plugin;
1083 plugin = find_transport(transport_name);
1084 if (plugin == NULL) /* Nothing to do */
1087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088 "Adding peer `%s' with plugin `%s' to blacklist\n",
1092 if (plugin->blacklist == NULL)
1093 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1094 GNUNET_assert(plugin->blacklist != NULL);
1095 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1097 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1102 * Read the blacklist file, containing transport:peer entries.
1103 * Provided the transport is loaded, set up hashmap with these
1104 * entries to blacklist peers by transport.
1108 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1115 struct GNUNET_PeerIdentity pid;
1117 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1118 unsigned int entries_found;
1119 char *transport_name;
1122 GNUNET_CONFIGURATION_get_value_filename (cfg,
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129 "Option `%s' in section `%s' not specified!\n",
1135 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1136 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1137 | GNUNET_DISK_PERM_USER_WRITE);
1138 if (0 != STAT (fn, &frstat))
1140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1141 _("Could not read blacklist file `%s'\n"), fn);
1145 if (frstat.st_size == 0)
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 _("Blacklist file `%s' is empty.\n"),
1155 /* FIXME: use mmap */
1156 data = GNUNET_malloc_large (frstat.st_size);
1157 GNUNET_assert(data != NULL);
1158 if (frstat.st_size !=
1159 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1162 _("Failed to read blacklist from `%s'\n"), fn);
1169 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1171 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1172 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1175 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1178 if (colon_pos >= frstat.st_size)
1180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1181 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1182 (unsigned long long) colon_pos);
1188 if (isspace( (unsigned char) data[colon_pos]))
1190 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1191 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1192 (unsigned long long) colon_pos);
1194 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1198 tsize = colon_pos - pos;
1199 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1201 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1202 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1203 (unsigned long long) colon_pos);
1212 transport_name = GNUNET_malloc(tsize + 1);
1213 memcpy(transport_name, &data[pos], tsize);
1214 pos = colon_pos + 1;
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217 "Read transport name %s in blacklist file.\n",
1220 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1221 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1223 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1224 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1225 (unsigned long long) pos);
1227 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1229 GNUNET_free_non_null(transport_name);
1232 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1233 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1235 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1236 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1237 (unsigned long long) pos,
1242 if (0 != memcmp (&pid,
1244 sizeof (struct GNUNET_PeerIdentity)))
1247 add_peer_to_blacklist (&pid,
1252 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1253 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1257 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1258 GNUNET_free_non_null(transport_name);
1259 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1262 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1269 * Function called to notify a client about the socket being ready to
1270 * queue more data. "buf" will be NULL and "size" zero if the socket
1271 * was closed for writing in the meantime.
1273 * @param cls closure
1274 * @param size number of bytes available in buf
1275 * @param buf where the callee should write the message
1276 * @return number of bytes written to buf
1279 transmit_to_client_callback (void *cls, size_t size, void *buf)
1281 struct TransportClient *client = cls;
1282 struct ClientMessageQueueEntry *q;
1285 const struct GNUNET_MessageHeader *msg;
1292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293 "Transmission to client failed, closing connection.\n");
1295 /* fatal error with client, free message queue! */
1296 while (NULL != (q = client->message_queue_head))
1298 GNUNET_STATISTICS_update (stats,
1299 gettext_noop ("# bytes discarded (could not transmit to client)"),
1300 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1302 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1303 client->message_queue_tail,
1307 client->message_count = 0;
1312 while (NULL != (q = client->message_queue_head))
1314 msg = (const struct GNUNET_MessageHeader *) &q[1];
1315 msize = ntohs (msg->size);
1316 if (msize + tsize > size)
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1320 "Transmitting message of type %u to client.\n",
1323 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1324 client->message_queue_tail,
1326 memcpy (&cbuf[tsize], msg, msize);
1329 client->message_count--;
1333 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1334 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1336 GNUNET_TIME_UNIT_FOREVER_REL,
1337 &transmit_to_client_callback,
1339 GNUNET_assert (client->th != NULL);
1346 * Convert an address to a string.
1348 * @param plugin name of the plugin responsible for the address
1349 * @param addr binary address
1350 * @param addr_len number of bytes in addr
1351 * @return NULL on error, otherwise address string
1354 a2s (const char *plugin,
1358 struct TransportPlugin *p;
1362 p = find_transport (plugin);
1363 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1366 return p->api->address_to_string (NULL,
1376 * Iterator to free entries in the validation_map.
1378 * @param cls closure (unused)
1379 * @param key current key code
1380 * @param value value in the hash map (validation to abort)
1381 * @return GNUNET_YES (always)
1384 abort_validation (void *cls,
1385 const GNUNET_HashCode * key,
1388 struct ValidationEntry *va = value;
1390 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1391 GNUNET_SCHEDULER_cancel (va->timeout_task);
1392 GNUNET_free (va->transport_name);
1393 if (va->chvc != NULL)
1395 va->chvc->ve_count--;
1396 if (va->chvc->ve_count == 0)
1398 GNUNET_CONTAINER_DLL_remove (chvc_head,
1401 GNUNET_free (va->chvc);
1411 * HELLO validation cleanup task (validation failed).
1413 * @param cls the 'struct ValidationEntry' that failed
1414 * @param tc scheduler context (unused)
1417 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1419 struct ValidationEntry *va = cls;
1420 struct GNUNET_PeerIdentity pid;
1422 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1423 GNUNET_STATISTICS_update (stats,
1424 gettext_noop ("# address validation timeouts"),
1427 GNUNET_CRYPTO_hash (&va->publicKey,
1429 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1431 GNUNET_break (GNUNET_OK ==
1432 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1435 abort_validation (NULL, NULL, va);
1441 * Send the specified message to the specified client. Since multiple
1442 * messages may be pending for the same client at a time, this code
1443 * makes sure that no message is lost.
1445 * @param client client to transmit the message to
1446 * @param msg the message to send
1447 * @param may_drop can this message be dropped if the
1448 * message queue for this client is getting far too large?
1451 transmit_to_client (struct TransportClient *client,
1452 const struct GNUNET_MessageHeader *msg, int may_drop)
1454 struct ClientMessageQueueEntry *q;
1457 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1459 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1461 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1464 client->message_count,
1466 GNUNET_STATISTICS_update (stats,
1467 gettext_noop ("# messages dropped due to slow client"),
1472 msize = ntohs (msg->size);
1473 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1474 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1475 memcpy (&q[1], msg, msize);
1476 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1477 client->message_queue_tail,
1479 client->message_count++;
1480 if (client->th == NULL)
1482 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1484 GNUNET_TIME_UNIT_FOREVER_REL,
1485 &transmit_to_client_callback,
1487 GNUNET_assert (client->th != NULL);
1493 * Transmit a 'SEND_OK' notification to the given client for the
1496 * @param client who to notify
1497 * @param n neighbour to notify about, can be NULL (on failure)
1498 * @param target target of the transmission
1499 * @param result status code for the transmission request
1502 transmit_send_ok (struct TransportClient *client,
1503 struct NeighbourList *n,
1504 const struct GNUNET_PeerIdentity *target,
1507 struct SendOkMessage send_ok_msg;
1509 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1510 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1511 send_ok_msg.success = htonl (result);
1513 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1515 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1516 send_ok_msg.peer = *target;
1517 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1522 * Mark the given FAL entry as 'connected' (and hence preferred for
1523 * sending); also mark all others for the same peer as 'not connected'
1524 * (since only one can be preferred).
1526 * @param fal address to set to 'connected'
1529 mark_address_connected (struct ForeignAddressList *fal);
1534 * We should re-try transmitting to the given peer,
1535 * hopefully we've learned something in the meantime.
1538 retry_transmission_task (void *cls,
1539 const struct GNUNET_SCHEDULER_TaskContext *tc)
1541 struct NeighbourList *n = cls;
1543 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1544 try_transmission_to_peer (n);
1549 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1550 * upon "completion" of a send request. This tells the API
1551 * that it is now legal to send another message to the given
1554 * @param cls closure, identifies the entry on the
1555 * message queue that was transmitted and the
1556 * client responsible for queuing the message
1557 * @param target the peer receiving the message
1558 * @param result GNUNET_OK on success, if the transmission
1559 * failed, we should not tell the client to transmit
1563 transmit_send_continuation (void *cls,
1564 const struct GNUNET_PeerIdentity *target,
1567 struct MessageQueue *mq = cls;
1568 struct NeighbourList *n;
1570 GNUNET_STATISTICS_update (stats,
1571 gettext_noop ("# bytes pending with plugins"),
1572 - (int64_t) mq->message_buf_size,
1574 if (result == GNUNET_OK)
1576 GNUNET_STATISTICS_update (stats,
1577 gettext_noop ("# bytes successfully transmitted by plugins"),
1578 mq->message_buf_size,
1583 GNUNET_STATISTICS_update (stats,
1584 gettext_noop ("# bytes with transmission failure by plugins"),
1585 mq->message_buf_size,
1588 if (mq->specific_address != NULL)
1590 if (result == GNUNET_OK)
1592 mq->specific_address->timeout =
1593 GNUNET_TIME_relative_to_absolute
1594 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1595 if (mq->specific_address->validated == GNUNET_YES)
1596 mark_address_connected (mq->specific_address);
1600 if (mq->specific_address->connected != GNUNET_NO)
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1605 a2s (mq->specific_address->ready_list->plugin->short_name,
1606 mq->specific_address->addr,
1607 mq->specific_address->addrlen));
1609 GNUNET_STATISTICS_update (stats,
1610 gettext_noop ("# connected addresses"),
1613 mq->specific_address->connected = GNUNET_NO;
1616 if (! mq->internal_msg)
1617 mq->specific_address->in_transmit = GNUNET_NO;
1619 n = find_neighbour (&mq->neighbour_id);
1620 if (mq->client != NULL)
1621 transmit_send_ok (mq->client, n, target, result);
1622 GNUNET_assert (n != NULL);
1623 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1627 if (result == GNUNET_OK)
1628 try_transmission_to_peer (n);
1629 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1630 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1636 * Check the ready list for the given neighbour and if a plugin is
1637 * ready for transmission (and if we have a message), do so!
1639 * @param neighbour target peer for which to transmit
1642 try_transmission_to_peer (struct NeighbourList *n)
1644 struct ReadyList *rl;
1645 struct MessageQueue *mq;
1646 struct GNUNET_TIME_Relative timeout;
1650 if (n->messages_head == NULL)
1653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1654 "Transmission queue for `%4s' is empty\n",
1655 GNUNET_i2s (&n->id));
1657 return; /* nothing to do */
1660 mq = n->messages_head;
1661 force_address = GNUNET_YES;
1662 if (mq->specific_address == NULL)
1665 mq->specific_address = get_preferred_ats_address(n);
1666 GNUNET_STATISTICS_update (stats,
1667 gettext_noop ("# transport selected peer address freely"),
1670 force_address = GNUNET_NO;
1672 if (mq->specific_address == NULL)
1674 GNUNET_STATISTICS_update (stats,
1675 gettext_noop ("# transport failed to selected peer address"),
1678 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1679 if (timeout.rel_value == 0)
1682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1683 "No destination address available to transmit message of size %u to peer `%4s'\n",
1684 mq->message_buf_size,
1685 GNUNET_i2s (&mq->neighbour_id));
1687 GNUNET_STATISTICS_update (stats,
1688 gettext_noop ("# bytes in message queue for other peers"),
1689 - (int64_t) mq->message_buf_size,
1691 GNUNET_STATISTICS_update (stats,
1692 gettext_noop ("# bytes discarded (no destination address available)"),
1693 mq->message_buf_size,
1695 if (mq->client != NULL)
1696 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1697 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1701 return; /* nobody ready */
1703 GNUNET_STATISTICS_update (stats,
1704 gettext_noop ("# message delivery deferred (no address)"),
1707 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1708 GNUNET_SCHEDULER_cancel (n->retry_task);
1709 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1710 &retry_transmission_task,
1713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1714 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1715 mq->message_buf_size,
1716 GNUNET_i2s (&mq->neighbour_id),
1719 /* FIXME: might want to trigger peerinfo lookup here
1720 (unless that's already pending...) */
1723 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1726 if (mq->specific_address->connected == GNUNET_NO)
1727 mq->specific_address->connect_attempts++;
1728 rl = mq->specific_address->ready_list;
1729 mq->plugin = rl->plugin;
1730 if (!mq->internal_msg)
1731 mq->specific_address->in_transmit = GNUNET_YES;
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1735 mq->message_buf_size,
1736 GNUNET_i2s (&n->id),
1737 (mq->specific_address->addr != NULL)
1738 ? a2s (mq->plugin->short_name,
1739 mq->specific_address->addr,
1740 mq->specific_address->addrlen)
1742 rl->plugin->short_name);
1744 GNUNET_STATISTICS_update (stats,
1745 gettext_noop ("# bytes in message queue for other peers"),
1746 - (int64_t) mq->message_buf_size,
1748 GNUNET_STATISTICS_update (stats,
1749 gettext_noop ("# bytes pending with plugins"),
1750 mq->message_buf_size,
1753 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1757 ret = rl->plugin->api->send (rl->plugin->api->cls,
1760 mq->message_buf_size,
1762 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1763 mq->specific_address->session,
1764 mq->specific_address->addr,
1765 mq->specific_address->addrlen,
1767 &transmit_send_continuation, mq);
1770 /* failure, but 'send' would not call continuation in this case,
1771 so we need to do it here! */
1772 transmit_send_continuation (mq,
1780 * Send the specified message to the specified peer.
1782 * @param client source of the transmission request (can be NULL)
1783 * @param peer_address ForeignAddressList where we should send this message
1784 * @param priority how important is the message
1785 * @param timeout how long do we have to transmit?
1786 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1787 * @param message_buf_size total size of all messages in message_buf
1788 * @param is_internal is this an internal message; these are pre-pended and
1789 * also do not count for plugins being "ready" to transmit
1790 * @param neighbour handle to the neighbour for transmission
1793 transmit_to_peer (struct TransportClient *client,
1794 struct ForeignAddressList *peer_address,
1795 unsigned int priority,
1796 struct GNUNET_TIME_Relative timeout,
1797 const char *message_buf,
1798 size_t message_buf_size,
1799 int is_internal, struct NeighbourList *neighbour)
1801 struct MessageQueue *mq;
1806 /* check for duplicate submission */
1807 mq = neighbour->messages_head;
1810 if (mq->client == client)
1812 /* client transmitted to same peer twice
1813 before getting SEND_OK! */
1821 GNUNET_STATISTICS_update (stats,
1822 gettext_noop ("# bytes in message queue for other peers"),
1825 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1826 mq->specific_address = peer_address;
1827 mq->client = client;
1828 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1829 memcpy (&mq[1], message_buf, message_buf_size);
1830 mq->message_buf = (const char*) &mq[1];
1831 mq->message_buf_size = message_buf_size;
1832 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1833 mq->internal_msg = is_internal;
1834 mq->priority = priority;
1835 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1837 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1838 neighbour->messages_tail,
1841 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1842 neighbour->messages_tail,
1843 neighbour->messages_tail,
1845 try_transmission_to_peer (neighbour);
1850 * Send a plain PING (without address or our HELLO) to the given
1851 * foreign address to try to establish a connection (and validate
1852 * that the other peer is really who he claimed he is).
1854 * @param n neighbour to PING
1857 transmit_plain_ping (struct NeighbourList *n)
1859 struct ValidationEntry *ve;
1860 struct TransportPingMessage ping;
1861 struct ReadyList *rl;
1862 struct TransportPlugin *plugin;
1863 struct ForeignAddressList *fal;
1865 if (! n->public_key_valid)
1867 /* This should not happen since the other peer
1868 should send us a HELLO prior to sending his
1870 GNUNET_break_op (0);
1871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1872 "Could not transmit plain PING to `%s': public key not known\n",
1873 GNUNET_i2s (&n->id));
1876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877 "Looking for addresses to transmit plain PING to `%s'\n",
1878 GNUNET_i2s (&n->id));
1879 for (rl = n->plugins; rl != NULL; rl = rl->next)
1881 plugin = rl->plugin;
1882 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1884 if (! fal->connected)
1886 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1887 ve->transport_name = GNUNET_strdup (plugin->short_name);
1888 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1890 ve->send_time = GNUNET_TIME_absolute_get();
1891 ve->session = fal->session;
1892 memcpy(&ve->publicKey,
1894 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1895 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1896 &timeout_hello_validation,
1898 GNUNET_CONTAINER_multihashmap_put (validation_map,
1901 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1902 ping.header.size = htons(sizeof(struct TransportPingMessage));
1903 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1904 ping.challenge = htonl(ve->challenge);
1905 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1906 GNUNET_STATISTICS_update (stats,
1907 gettext_noop ("# PING without HELLO messages sent"),
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911 "Transmitting plain PING to `%s'\n",
1912 GNUNET_i2s (&n->id));
1913 transmit_to_peer (NULL,
1915 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1916 HELLO_VERIFICATION_TIMEOUT,
1917 (const char*) &ping, sizeof (ping),
1925 * Mark the given FAL entry as 'connected' (and hence preferred for
1926 * sending); also mark all others for the same peer as 'not connected'
1927 * (since only one can be preferred).
1929 * @param fal address to set to 'connected'
1932 mark_address_connected(struct ForeignAddressList *fal)
1934 struct ForeignAddressList *pos;
1935 struct ForeignAddressList *inbound;
1936 struct ForeignAddressList *outbound;
1939 GNUNET_assert (GNUNET_YES == fal->validated);
1940 if (fal->connected == GNUNET_YES)
1941 return; /* nothing to do */
1946 pos = fal->ready_list->addresses;
1949 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1950 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) && (0
1953 else if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1958 pos = fal->ready_list->addresses;
1961 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1962 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) && (0
1965 else if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1971 if (inbound != NULL)
1972 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1973 if (outbound != NULL)
1974 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1977 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1978 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1979 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1980 &my_identity.hashPubKey, &null_hash)))
1983 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1987 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1988 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1989 &my_identity.hashPubKey, &null_hash))))
1992 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
1997 pos = fal->ready_list->addresses;
2000 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2004 GNUNET_ERROR_TYPE_DEBUG,
2005 "Marking address `%s' as no longer connected (due to connect on other address)\n",
2006 a2s (pos->ready_list->plugin->short_name, pos->addr,
2009 GNUNET_break (cnt == GNUNET_YES);
2012 fprintf(stderr, "Peer: %s, setting %s connection to disconnected.\n", GNUNET_i2s(&my_identity), (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2014 pos->connected = GNUNET_NO;
2015 GNUNET_STATISTICS_update (stats,
2016 gettext_noop ("# connected addresses"), -1,
2022 fal->connected = GNUNET_YES;
2023 if (GNUNET_YES == cnt)
2025 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2032 * Find an address in any of the available transports for
2033 * the given neighbour that would be good for message
2034 * transmission. This is essentially the transport selection
2037 * @param neighbour for whom to select an address
2038 * @return selected address, NULL if we have none
2040 struct ForeignAddressList *
2041 find_ready_address(struct NeighbourList *neighbour)
2043 struct ReadyList *head = neighbour->plugins;
2044 struct ForeignAddressList *addresses;
2045 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2046 struct ForeignAddressList *best_address;
2048 /* Hack to prefer unix domain sockets */
2049 struct ForeignAddressList *unix_address = NULL;
2051 best_address = NULL;
2052 while (head != NULL)
2054 addresses = head->addresses;
2055 while (addresses != NULL)
2057 if ( (addresses->timeout.abs_value < now.abs_value) &&
2058 (addresses->connected == GNUNET_YES) )
2061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062 "Marking long-time inactive connection to `%4s' as down.\n",
2063 GNUNET_i2s (&neighbour->id));
2065 GNUNET_STATISTICS_update (stats,
2066 gettext_noop ("# connected addresses"),
2069 addresses->connected = GNUNET_NO;
2071 addresses = addresses->next;
2074 addresses = head->addresses;
2075 while (addresses != NULL)
2078 if (addresses->addr != NULL)
2079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2080 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2081 a2s (head->plugin->short_name,
2083 addresses->addrlen),
2084 GNUNET_i2s (&neighbour->id),
2085 addresses->connected,
2086 addresses->in_transmit,
2087 addresses->validated,
2088 addresses->connect_attempts,
2089 (unsigned long long) addresses->timeout.abs_value,
2090 (unsigned int) addresses->distance);
2092 if (0==strcmp(head->plugin->short_name,"unix"))
2094 if ( (unix_address == NULL) ||
2095 ( (unix_address != NULL) &&
2096 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2097 unix_address = addresses;
2099 if ( ( (best_address == NULL) ||
2100 (addresses->connected == GNUNET_YES) ||
2101 (best_address->connected == GNUNET_NO) ) &&
2102 (addresses->in_transmit == GNUNET_NO) &&
2103 ( (best_address == NULL) ||
2104 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2105 best_address = addresses;
2106 /* FIXME: also give lower-latency addresses that are not
2107 connected a chance some times... */
2108 addresses = addresses->next;
2110 if (unix_address != NULL)
2114 if (unix_address != NULL)
2116 best_address = unix_address;
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2119 "Found UNIX address, forced this address\n");
2122 if (best_address != NULL)
2125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2126 "Best address found (`%s') has latency of %llu ms.\n",
2127 (best_address->addrlen > 0)
2128 ? a2s (best_address->ready_list->plugin->short_name,
2130 best_address->addrlen)
2132 best_address->latency.rel_value);
2137 GNUNET_STATISTICS_update (stats,
2138 gettext_noop ("# transmission attempts failed (no address)"),
2143 return best_address;
2150 struct GeneratorContext
2152 struct TransportPlugin *plug_pos;
2153 struct OwnAddressList *addr_pos;
2154 struct GNUNET_TIME_Absolute expiration;
2162 address_generator (void *cls, size_t max, void *buf)
2164 struct GeneratorContext *gc = cls;
2167 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2169 gc->plug_pos = gc->plug_pos->next;
2170 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2172 if (NULL == gc->plug_pos)
2177 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2180 gc->addr_pos->addrlen, buf, max);
2181 gc->addr_pos = gc->addr_pos->next;
2187 * Construct our HELLO message from all of the addresses of
2188 * all of the transports.
2191 * @param tc scheduler context
2194 refresh_hello_task (void *cls,
2195 const struct GNUNET_SCHEDULER_TaskContext *tc)
2197 struct GNUNET_HELLO_Message *hello;
2198 struct TransportClient *cpos;
2199 struct NeighbourList *npos;
2200 struct GeneratorContext gc;
2202 hello_task = GNUNET_SCHEDULER_NO_TASK;
2203 gc.plug_pos = plugins;
2204 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2205 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2206 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2209 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2211 GNUNET_STATISTICS_update (stats,
2212 gettext_noop ("# refreshed my HELLO"),
2216 while (cpos != NULL)
2218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2219 "Transmitting my HELLO to client!\n");
2220 transmit_to_client (cpos,
2221 (const struct GNUNET_MessageHeader *) hello,
2226 GNUNET_free_non_null (our_hello);
2228 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2229 for (npos = neighbours; npos != NULL; npos = npos->next)
2231 if (GNUNET_YES != npos->received_pong)
2234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2235 "Transmitting updated `%s' to neighbour `%4s'\n",
2236 "HELLO", GNUNET_i2s (&npos->id));
2238 GNUNET_STATISTICS_update (stats,
2239 gettext_noop ("# transmitted my HELLO to other peers"),
2242 transmit_to_peer (NULL, NULL, 0,
2243 HELLO_ADDRESS_EXPIRATION,
2244 (const char *) our_hello,
2245 GNUNET_HELLO_size(our_hello),
2252 * Schedule task to refresh hello (unless such a
2253 * task exists already).
2258 #if DEBUG_TRANSPORT_HELLO
2259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2260 "refresh_hello() called!\n");
2262 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2265 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2271 * Iterator over hash map entries that NULLs the session of validation
2272 * entries that match the given session.
2274 * @param cls closure (the 'struct Session*' to match against)
2275 * @param key current key code (peer ID, not used)
2276 * @param value value in the hash map ('struct ValidationEntry*')
2277 * @return GNUNET_YES (we should continue to iterate)
2280 remove_session_validations (void *cls,
2281 const GNUNET_HashCode * key,
2284 struct Session *session = cls;
2285 struct ValidationEntry *ve = value;
2287 if (session == ve->session)
2294 * We've been disconnected from the other peer (for some
2295 * connection-oriented transport). Either quickly
2296 * re-establish the connection or signal the disconnect
2299 * Only signal CORE level disconnect if ALL addresses
2300 * for the peer are exhausted.
2302 * @param p overall plugin context
2303 * @param nl neighbour that was disconnected
2306 try_fast_reconnect (struct TransportPlugin *p,
2307 struct NeighbourList *nl)
2309 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2310 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2311 "try_fast_reconnect not implemented!\n");
2312 /* Note: the idea here is to hide problems with transports (or
2313 switching between plugins) from the core to eliminate the need to
2314 re-negotiate session keys and the like; OTOH, we should tell core
2315 quickly (much faster than timeout) `if a connection was lost and
2316 could not be re-established (i.e. other peer went down or is
2317 unable / refuses to communicate);
2319 So we should consider:
2320 1) ideally: our own willingness / need to connect
2321 2) prior failures to connect to this peer (by plugin)
2322 3) ideally: reasons why other peer terminated (as far as knowable)
2324 Most importantly, it must be POSSIBLE for another peer to terminate
2325 a connection for a while (without us instantly re-establishing it).
2326 Similarly, if another peer is gone we should quickly notify CORE.
2327 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2328 on the other end), we should reconnect in such a way that BOTH CORE
2329 services never even notice.
2330 Furthermore, the same mechanism (or small variation) could be used
2331 to switch to a better-performing plugin (ATS).
2333 Finally, this needs to be tested throughly... */
2336 * GNUNET_NO in the call below makes transport disconnect the peer,
2337 * even if only a single address (out of say, six) went away. This
2338 * function must be careful to ONLY disconnect if the peer is gone,
2339 * not just a specific address.
2341 * More specifically, half the places it was used had it WRONG.
2344 /* No reconnect, signal disconnect instead! */
2347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2348 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2349 "try_fast_reconnect");
2351 GNUNET_STATISTICS_update (stats,
2352 gettext_noop ("# disconnects due to try_fast_reconnect"),
2356 disconnect_neighbour (nl, GNUNET_YES);
2362 * Function that will be called whenever the plugin internally
2363 * cleans up a session pointer and hence the service needs to
2364 * discard all of those sessions as well. Plugins that do not
2365 * use sessions can simply omit calling this function and always
2366 * use NULL wherever a session pointer is needed.
2368 * @param cls closure
2369 * @param peer which peer was the session for
2370 * @param session which session is being destoyed
2373 plugin_env_session_end (void *cls,
2374 const struct GNUNET_PeerIdentity *peer,
2375 struct Session *session)
2377 struct TransportPlugin *p = cls;
2378 struct NeighbourList *nl;
2379 struct ReadyList *rl;
2380 struct ForeignAddressList *pos;
2381 struct ForeignAddressList *prev;
2384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2385 "Session ended with peer `%4s', %s\n",
2387 "plugin_env_session_end");
2389 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2390 &remove_session_validations,
2392 nl = find_neighbour (peer);
2396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2397 "No neighbour record found for peer `%4s'\n",
2400 return; /* was never marked as connected */
2405 if (rl->plugin == p)
2412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2413 "Plugin was associated with peer `%4s'\n",
2416 GNUNET_STATISTICS_update (stats,
2417 gettext_noop ("# disconnects due to session end"),
2420 disconnect_neighbour (nl, GNUNET_YES);
2424 pos = rl->addresses;
2425 while ( (pos != NULL) &&
2426 (pos->session != session) )
2434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2435 "Session was never marked as ready for peer `%4s'\n",
2439 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2441 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2442 if (validations_pending ==GNUNET_YES)
2445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2451 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2452 GNUNET_STATISTICS_update (stats,
2453 gettext_noop ("# disconnects due to unready session"),
2457 disconnect_neighbour (nl, GNUNET_YES);
2458 return; /* was never marked as connected */
2460 pos->session = NULL;
2461 pos->connected = GNUNET_NO;
2462 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2464 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2465 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2468 if (pos->addrlen != 0)
2470 if (nl->received_pong != GNUNET_NO)
2472 GNUNET_STATISTICS_update (stats,
2473 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2476 if (GNUNET_YES == pos->connected)
2477 try_fast_reconnect (p, nl);
2481 GNUNET_STATISTICS_update (stats,
2482 gettext_noop ("# disconnects due to missing pong"),
2485 /* FIXME this is never true?! See: line 2416*/
2486 if (GNUNET_YES == pos->connected)
2487 disconnect_neighbour (nl, GNUNET_YES);
2492 GNUNET_STATISTICS_update (stats,
2493 gettext_noop ("# connected addresses"),
2497 /* was inbound connection, free 'pos' */
2499 rl->addresses = pos->next;
2501 prev->next = pos->next;
2502 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2504 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2505 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2507 GNUNET_free_non_null(pos->ressources);
2508 GNUNET_free_non_null(pos->quality);
2509 ats_modify_problem_state (ats, ATS_MODIFIED);
2511 if (GNUNET_YES != pos->connected)
2513 /* nothing else to do, connection was never up... */
2519 if (nl->received_pong == GNUNET_NO)
2521 GNUNET_STATISTICS_update (stats,
2522 gettext_noop ("# disconnects due to NO pong"),
2525 disconnect_neighbour (nl, GNUNET_YES);
2526 return; /* nothing to do, never connected... */
2528 /* check if we have any validated addresses left */
2529 pos = rl->addresses;
2532 if (GNUNET_YES == pos->validated)
2534 GNUNET_STATISTICS_update (stats,
2535 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2538 try_fast_reconnect (p, nl);
2543 /* no valid addresses left, signal disconnect! */
2546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547 "Disconnecting peer `%4s', %s\n",
2549 "plugin_env_session_end");
2551 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2552 * it means there aren't any left for this PLUGIN/PEER combination! So
2553 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2554 * when it isn't necessary. Using GNUNET_YES at least checks to see
2555 * if there are any addresses that work first, so as not to overdo it.
2558 GNUNET_STATISTICS_update (stats,
2559 gettext_noop ("# disconnects due to plugin_env_session_end"),
2562 disconnect_neighbour (nl, GNUNET_YES);
2567 * Function that must be called by each plugin to notify the
2568 * transport service about the addresses under which the transport
2569 * provided by the plugin can be reached.
2571 * @param cls closure
2572 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2573 * @param addr one of the addresses of the host, NULL for the last address
2574 * the specific address format depends on the transport
2575 * @param addrlen length of the address
2578 plugin_env_notify_address (void *cls,
2583 struct TransportPlugin *p = cls;
2584 struct OwnAddressList *al;
2585 struct OwnAddressList *prev;
2587 GNUNET_assert (p->api != NULL);
2589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2590 (add_remove == GNUNET_YES)
2591 ? "Adding `%s':%s to the set of our addresses\n"
2592 : "Removing `%s':%s from the set of our addresses\n",
2597 GNUNET_assert (addr != NULL);
2598 if (GNUNET_NO == add_remove)
2604 if ( (addrlen == al->addrlen) &&
2605 (0 == memcmp (addr, &al[1], addrlen)) )
2608 p->addresses = al->next;
2610 prev->next = al->next;
2621 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2622 al->next = p->addresses;
2624 al->addrlen = addrlen;
2625 memcpy (&al[1], addr, addrlen);
2631 * Notify all of our clients about a peer connecting.
2634 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2635 struct GNUNET_TIME_Relative latency,
2638 struct ConnectInfoMessage * cim;
2639 struct TransportClient *cpos;
2643 if (0 == memcmp (peer,
2645 sizeof (struct GNUNET_PeerIdentity)))
2651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652 "Notifying clients about connection with `%s'\n",
2655 GNUNET_STATISTICS_update (stats,
2656 gettext_noop ("# peers connected"),
2661 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2662 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2663 cim = GNUNET_malloc (size);
2664 cim->header.size = htons (size);
2665 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2666 cim->ats_count = htonl(2);
2667 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2668 (&cim->ats)[0].value = htonl (distance);
2669 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2670 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2671 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2672 (&cim->ats)[2].value = htonl (0);
2673 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2675 /* notify ats about connecting peer */
2676 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2678 ats_modify_problem_state(ats, ATS_MODIFIED);
2679 ats_calculate_bandwidth_distribution (ats, stats);
2682 while (cpos != NULL)
2684 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2692 * Notify all of our clients about a peer disconnecting.
2695 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2697 struct DisconnectInfoMessage dim;
2698 struct TransportClient *cpos;
2700 if (0 == memcmp (peer,
2702 sizeof (struct GNUNET_PeerIdentity)))
2708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2709 "Notifying clients about lost connection to `%s'\n",
2712 GNUNET_STATISTICS_update (stats,
2713 gettext_noop ("# peers connected"),
2716 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2717 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2718 dim.reserved = htonl (0);
2719 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2721 /* notify ats about connecting peer */
2722 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2724 ats_modify_problem_state(ats, ATS_MODIFIED);
2725 ats_calculate_bandwidth_distribution (ats, stats);
2729 while (cpos != NULL)
2731 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2738 * Find a ForeignAddressList entry for the given neighbour
2739 * that matches the given address and transport.
2741 * @param neighbour which peer we care about
2742 * @param tname name of the transport plugin
2743 * @param session session to look for, NULL for 'any'; otherwise
2744 * can be used for the service to "learn" this session ID
2746 * @param addr binary address
2747 * @param addrlen length of addr
2748 * @return NULL if no such entry exists
2750 static struct ForeignAddressList *
2751 find_peer_address(struct NeighbourList *neighbour,
2753 struct Session *session,
2757 struct ReadyList *head;
2758 struct ForeignAddressList *pos;
2760 head = neighbour->plugins;
2761 while (head != NULL)
2763 if (0 == strcmp (tname, head->plugin->short_name))
2769 pos = head->addresses;
2770 while ( (pos != NULL) &&
2771 ( (pos->addrlen != addrlen) ||
2772 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2774 if ( (session != NULL) &&
2775 (pos->session == session) )
2779 if ( (session != NULL) && (pos != NULL) )
2780 pos->session = session; /* learn it! */
2786 * Get the peer address struct for the given neighbour and
2787 * address. If it doesn't yet exist, create it.
2789 * @param neighbour which peer we care about
2790 * @param tname name of the transport plugin
2791 * @param session session of the plugin, or NULL for none
2792 * @param addr binary address
2793 * @param addrlen length of addr
2794 * @return NULL if we do not have a transport plugin for 'tname'
2796 static struct ForeignAddressList *
2797 add_peer_address (struct NeighbourList *neighbour,
2799 struct Session *session,
2803 struct ReadyList *head;
2804 struct ForeignAddressList *ret;
2807 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2810 head = neighbour->plugins;
2812 while (head != NULL)
2814 if (0 == strcmp (tname, head->plugin->short_name))
2820 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2821 ret->session = session;
2822 if ((addrlen > 0) && (addr != NULL))
2824 ret->addr = (const char*) &ret[1];
2825 memcpy (&ret[1], addr, addrlen);
2832 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2833 for (c=0; c<available_ressources; c++)
2835 struct ATS_ressource_entry *r = ret->ressources;
2837 r[c].atis_index = ressources[c].atis_index;
2838 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2840 r[c].c = ressources[c].c_unix;
2842 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2844 r[c].c = ressources[c].c_udp;
2846 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2848 r[c].c = ressources[c].c_tcp;
2850 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2852 r[c].c = ressources[c].c_http;
2854 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2856 r[c].c = ressources[c].c_https;
2858 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2860 r[c].c = ressources[c].c_wlan;
2864 r[c].c = ressources[c].c_default;
2865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2866 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2867 GNUNET_i2s(&neighbour->id),
2868 neighbour->plugins->plugin->short_name);
2872 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2873 ret->addrlen = addrlen;
2874 ret->expires = GNUNET_TIME_relative_to_absolute
2875 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2876 ret->latency = GNUNET_TIME_relative_get_forever();
2878 ret->timeout = GNUNET_TIME_relative_to_absolute
2879 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2880 ret->ready_list = head;
2881 ret->next = head->addresses;
2882 head->addresses = ret;
2888 * Closure for 'add_validated_address'.
2890 struct AddValidatedAddressContext
2893 * Entry that has been validated.
2895 const struct ValidationEntry *ve;
2898 * Flag set after we have added the address so
2899 * that we terminate the iteration next time.
2906 * Callback function used to fill a buffer of max bytes with a list of
2907 * addresses in the format used by HELLOs. Should use
2908 * "GNUNET_HELLO_add_address" as a helper function.
2910 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2911 * @param max maximum number of bytes that can be written to buf
2912 * @param buf where to write the address information
2913 * @return number of bytes written, 0 to signal the
2914 * end of the iteration.
2917 add_validated_address (void *cls,
2918 size_t max, void *buf)
2920 struct AddValidatedAddressContext *avac = cls;
2921 const struct ValidationEntry *ve = avac->ve;
2923 if (GNUNET_YES == avac->done)
2925 avac->done = GNUNET_YES;
2926 return GNUNET_HELLO_add_address (ve->transport_name,
2927 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2937 * Closure for 'check_address_exists'.
2939 struct CheckAddressExistsClosure
2942 * Address to check for.
2947 * Name of the transport.
2954 struct Session *session;
2957 * Set to GNUNET_YES if the address exists.
2970 * Iterator over hash map entries. Checks if the given
2971 * validation entry is for the same address as what is given
2974 * @param cls the 'struct CheckAddressExistsClosure*'
2975 * @param key current key code (ignored)
2976 * @param value value in the hash map ('struct ValidationEntry')
2977 * @return GNUNET_YES if we should continue to
2978 * iterate (mismatch), GNUNET_NO if not (entry matched)
2981 check_address_exists (void *cls,
2982 const GNUNET_HashCode * key,
2985 struct CheckAddressExistsClosure *caec = cls;
2986 struct ValidationEntry *ve = value;
2988 if ( (0 == strcmp (caec->tname,
2989 ve->transport_name)) &&
2990 (caec->addrlen == ve->addrlen) &&
2991 (0 == memcmp (caec->addr,
2995 caec->exists = GNUNET_YES;
2998 if ( (ve->session != NULL) &&
2999 (caec->session == ve->session) )
3001 caec->exists = GNUNET_YES;
3009 neighbour_timeout_task (void *cls,
3010 const struct GNUNET_SCHEDULER_TaskContext *tc)
3012 struct NeighbourList *n = cls;
3015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3016 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3018 GNUNET_STATISTICS_update (stats,
3019 gettext_noop ("# disconnects due to timeout"),
3022 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3023 disconnect_neighbour (n, GNUNET_NO);
3028 * Schedule the job that will cause us to send a PING to the
3029 * foreign address to evaluate its validity and latency.
3031 * @param fal address to PING
3034 schedule_next_ping (struct ForeignAddressList *fal);
3038 * Add the given address to the list of foreign addresses
3039 * available for the given peer (check for duplicates).
3041 * @param cls the respective 'struct NeighbourList' to update
3042 * @param tname name of the transport
3043 * @param expiration expiration time
3044 * @param addr the address
3045 * @param addrlen length of the address
3046 * @return GNUNET_OK (always)
3049 add_to_foreign_address_list (void *cls,
3051 struct GNUNET_TIME_Absolute expiration,
3055 struct NeighbourList *n = cls;
3056 struct ForeignAddressList *fal;
3059 GNUNET_STATISTICS_update (stats,
3060 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3064 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3067 #if DEBUG_TRANSPORT_HELLO
3068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3069 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3070 a2s (tname, addr, addrlen),
3072 GNUNET_i2s (&n->id),
3073 expiration.abs_value);
3075 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3078 GNUNET_STATISTICS_update (stats,
3079 gettext_noop ("# previously validated addresses lacking transport"),
3085 fal->expires = GNUNET_TIME_absolute_max (expiration,
3087 schedule_next_ping (fal);
3093 fal->expires = GNUNET_TIME_absolute_max (expiration,
3099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3100 "Failed to add new address for `%4s'\n",
3101 GNUNET_i2s (&n->id));
3105 if (fal->validated == GNUNET_NO)
3107 fal->validated = GNUNET_YES;
3108 GNUNET_STATISTICS_update (stats,
3109 gettext_noop ("# peer addresses considered valid"),
3113 if (try == GNUNET_YES)
3116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3117 "Have new addresses, will try to trigger transmissions.\n");
3119 try_transmission_to_peer (n);
3126 * Add addresses in validated HELLO "h" to the set of addresses
3127 * we have for this peer.
3129 * @param cls closure ('struct NeighbourList*')
3130 * @param peer id of the peer, NULL for last call
3131 * @param h hello message for the peer (can be NULL)
3132 * @param err_msg NULL if successful, otherwise contains error message
3135 add_hello_for_peer (void *cls,
3136 const struct GNUNET_PeerIdentity *peer,
3137 const struct GNUNET_HELLO_Message *h,
3138 const char *err_msg)
3140 struct NeighbourList *n = cls;
3142 if (err_msg != NULL)
3145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3146 _("Error in communication with PEERINFO service: %s\n"),
3153 GNUNET_STATISTICS_update (stats,
3154 gettext_noop ("# outstanding peerinfo iterate requests"),
3161 return; /* no HELLO available */
3163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3164 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3168 if (GNUNET_YES != n->public_key_valid)
3170 GNUNET_HELLO_get_key (h, &n->publicKey);
3171 n->public_key_valid = GNUNET_YES;
3173 GNUNET_HELLO_iterate_addresses (h,
3175 &add_to_foreign_address_list,
3181 * Create a fresh entry in our neighbour list for the given peer.
3182 * Will try to transmit our current HELLO to the new neighbour.
3183 * Do not call this function directly, use 'setup_peer_check_blacklist.
3185 * @param peer the peer for which we create the entry
3186 * @param do_hello should we schedule transmitting a HELLO
3187 * @return the new neighbour list entry
3189 static struct NeighbourList *
3190 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3193 struct NeighbourList *n;
3194 struct TransportPlugin *tp;
3195 struct ReadyList *rl;
3197 GNUNET_assert (0 != memcmp (peer,
3199 sizeof (struct GNUNET_PeerIdentity)));
3201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3202 "Setting up state for neighbour `%4s'\n",
3205 GNUNET_STATISTICS_update (stats,
3206 gettext_noop ("# active neighbours"),
3209 n = GNUNET_malloc (sizeof (struct NeighbourList));
3210 n->next = neighbours;
3214 GNUNET_TIME_relative_to_absolute
3215 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3216 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3217 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3218 MAX_BANDWIDTH_CARRY_S);
3222 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3224 rl = GNUNET_malloc (sizeof (struct ReadyList));
3226 rl->next = n->plugins;
3229 rl->addresses = NULL;
3233 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3235 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3236 &neighbour_timeout_task, n);
3239 GNUNET_STATISTICS_update (stats,
3240 gettext_noop ("# peerinfo new neighbor iterate requests"),
3243 GNUNET_STATISTICS_update (stats,
3244 gettext_noop ("# outstanding peerinfo iterate requests"),
3247 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3248 GNUNET_TIME_UNIT_FOREVER_REL,
3249 &add_hello_for_peer, n);
3251 GNUNET_STATISTICS_update (stats,
3252 gettext_noop ("# HELLO's sent to new neighbors"),
3255 if (NULL != our_hello)
3256 transmit_to_peer (NULL, NULL, 0,
3257 HELLO_ADDRESS_EXPIRATION,
3258 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3266 * Function called after we have checked if communicating
3267 * with a given peer is acceptable.
3269 * @param cls closure
3270 * @param n NULL if communication is not acceptable
3272 typedef void (*SetupContinuation)(void *cls,
3273 struct NeighbourList *n);
3277 * Information kept for each client registered to perform
3283 * This is a linked list.
3285 struct Blacklisters *next;
3288 * This is a linked list.
3290 struct Blacklisters *prev;
3293 * Client responsible for this entry.
3295 struct GNUNET_SERVER_Client *client;
3298 * Blacklist check that we're currently performing.
3300 struct BlacklistCheck *bc;
3306 * Head of DLL of blacklisting clients.
3308 static struct Blacklisters *bl_head;
3311 * Tail of DLL of blacklisting clients.
3313 static struct Blacklisters *bl_tail;
3317 * Context we use when performing a blacklist check.
3319 struct BlacklistCheck
3323 * This is a linked list.
3325 struct BlacklistCheck *next;
3328 * This is a linked list.
3330 struct BlacklistCheck *prev;
3333 * Peer being checked.
3335 struct GNUNET_PeerIdentity peer;
3338 * Option for setup neighbour afterwards.
3343 * Continuation to call with the result.
3345 SetupContinuation cont;
3353 * Current transmission request handle for this client, or NULL if no
3354 * request is pending.
3356 struct GNUNET_CONNECTION_TransmitHandle *th;
3359 * Our current position in the blacklisters list.
3361 struct Blacklisters *bl_pos;
3364 * Current task performing the check.
3366 GNUNET_SCHEDULER_TaskIdentifier task;
3371 * Head of DLL of active blacklisting queries.
3373 static struct BlacklistCheck *bc_head;
3376 * Tail of DLL of active blacklisting queries.
3378 static struct BlacklistCheck *bc_tail;
3382 * Perform next action in the blacklist check.
3384 * @param cls the 'struct BlacklistCheck*'
3388 do_blacklist_check (void *cls,
3389 const struct GNUNET_SCHEDULER_TaskContext *tc);
3392 * Transmit blacklist query to the client.
3394 * @param cls the 'struct BlacklistCheck'
3395 * @param size number of bytes allowed
3396 * @param buf where to copy the message
3397 * @return number of bytes copied to buf
3400 transmit_blacklist_message (void *cls,
3404 struct BlacklistCheck *bc = cls;
3405 struct Blacklisters *bl;
3406 struct BlacklistMessage bm;
3411 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3412 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3414 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3415 "Failed to send blacklist test for peer `%s' to client\n",
3416 GNUNET_i2s (&bc->peer));
3420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3421 "Sending blacklist test for peer `%s' to client\n",
3422 GNUNET_i2s (&bc->peer));
3425 bm.header.size = htons (sizeof (struct BlacklistMessage));
3426 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3427 bm.is_allowed = htonl (0);
3429 memcpy (buf, &bm, sizeof (bm));
3430 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3436 * Perform next action in the blacklist check.
3438 * @param cls the 'struct BlacklistCheck*'
3442 do_blacklist_check (void *cls,
3443 const struct GNUNET_SCHEDULER_TaskContext *tc)
3445 struct BlacklistCheck *bc = cls;
3446 struct Blacklisters *bl;
3448 bc->task = GNUNET_SCHEDULER_NO_TASK;
3453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3454 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3455 GNUNET_i2s (&bc->peer));
3457 bc->cont (bc->cont_cls,
3458 setup_new_neighbour (&bc->peer, bc->do_hello));
3465 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3466 sizeof (struct BlacklistMessage),
3467 GNUNET_TIME_UNIT_FOREVER_REL,
3468 &transmit_blacklist_message,
3475 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3476 * does not yet exist, check the blacklist. If the blacklist says creating
3477 * one is acceptable, create one and call the continuation; otherwise
3478 * call the continuation with NULL.
3480 * @param peer peer to setup or look up a struct NeighbourList for
3481 * @param do_hello should we also schedule sending our HELLO to the peer
3482 * if this is a new record
3483 * @param cont function to call with the 'struct NeigbhbourList*'
3484 * @param cont_cls closure for cont
3487 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3489 SetupContinuation cont,
3492 struct NeighbourList *n;
3493 struct BlacklistCheck *bc;
3495 n = find_neighbour(peer);
3499 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3500 "Neighbour record exists for peer `%s'\n",
3507 if (bl_head == NULL)
3510 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3512 setup_new_neighbour(peer, do_hello);
3515 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3516 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3518 bc->do_hello = do_hello;
3520 bc->cont_cls = cont_cls;
3521 bc->bl_pos = bl_head;
3522 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3528 * Function called with the result of querying a new blacklister about
3529 * it being allowed (or not) to continue to talk to an existing neighbour.
3531 * @param cls the original 'struct NeighbourList'
3532 * @param n NULL if we need to disconnect
3535 confirm_or_drop_neighbour (void *cls,
3536 struct NeighbourList *n)
3538 struct NeighbourList * orig = cls;
3543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3544 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3545 "confirm_or_drop_neighboUr");
3547 GNUNET_STATISTICS_update (stats,
3548 gettext_noop ("# disconnects due to blacklist"),
3551 disconnect_neighbour (orig, GNUNET_NO);
3557 * Handle a request to start a blacklist.
3559 * @param cls closure (always NULL)
3560 * @param client identification of the client
3561 * @param message the actual message
3564 handle_blacklist_init (void *cls,
3565 struct GNUNET_SERVER_Client *client,
3566 const struct GNUNET_MessageHeader *message)
3568 struct Blacklisters *bl;
3569 struct BlacklistCheck *bc;
3570 struct NeighbourList *n;
3575 if (bl->client == client)
3578 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3583 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3584 bl->client = client;
3585 GNUNET_SERVER_client_keep (client);
3586 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3587 /* confirm that all existing connections are OK! */
3591 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3592 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3594 bc->do_hello = GNUNET_NO;
3595 bc->cont = &confirm_or_drop_neighbour;
3598 if (n == neighbours) /* 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,
3608 * Handle a request to blacklist a peer.
3610 * @param cls closure (always NULL)
3611 * @param client identification of the client
3612 * @param message the actual message
3615 handle_blacklist_reply (void *cls,
3616 struct GNUNET_SERVER_Client *client,
3617 const struct GNUNET_MessageHeader *message)
3619 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3620 struct Blacklisters *bl;
3621 struct BlacklistCheck *bc;
3624 while ( (bl != NULL) &&
3625 (bl->client != client) )
3630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3631 "Blacklist client disconnected\n");
3633 /* FIXME: other error handling here!? */
3634 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3639 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3643 "Blacklist check failed, peer not allowed\n");
3645 bc->cont (bc->cont_cls, NULL);
3646 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3653 "Blacklist check succeeded, continuing with checks\n");
3655 bc->bl_pos = bc->bl_pos->next;
3656 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3659 /* check if any other bc's are waiting for this blacklister */
3663 if ( (bc->bl_pos == bl) &&
3664 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3665 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3673 * Send periodic PING messages to a given foreign address.
3675 * @param cls our 'struct PeriodicValidationContext*'
3676 * @param tc task context
3679 send_periodic_ping (void *cls,
3680 const struct GNUNET_SCHEDULER_TaskContext *tc)
3682 struct ForeignAddressList *peer_address = cls;
3683 struct TransportPlugin *tp;
3684 struct ValidationEntry *va;
3685 struct NeighbourList *neighbour;
3686 struct TransportPingMessage ping;
3687 struct CheckAddressExistsClosure caec;
3689 uint16_t hello_size;
3693 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3696 GNUNET_assert (peer_address != NULL);
3697 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3699 tp = peer_address->ready_list->plugin;
3700 neighbour = peer_address->ready_list->neighbour;
3701 if (GNUNET_YES != neighbour->public_key_valid)
3703 /* no public key yet, try again later */
3704 schedule_next_ping (peer_address);
3707 caec.addr = peer_address->addr;
3708 caec.addrlen = peer_address->addrlen;
3709 caec.tname = tp->short_name;
3710 caec.session = peer_address->session;
3711 caec.exists = GNUNET_NO;
3713 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3714 &check_address_exists,
3716 if (caec.exists == GNUNET_YES)
3718 /* During validation attempts we will likely trigger the other
3719 peer trying to validate our address which in turn will cause
3720 it to send us its HELLO, so we expect to hit this case rather
3721 frequently. Only print something if we are very verbose. */
3722 #if DEBUG_TRANSPORT > 1
3723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3724 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3725 (peer_address->addr != NULL)
3726 ? a2s (tp->short_name,
3728 peer_address->addrlen)
3731 GNUNET_i2s (&neighbour->id));
3733 schedule_next_ping (peer_address);
3736 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3737 va->transport_name = GNUNET_strdup (tp->short_name);
3738 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3740 va->send_time = GNUNET_TIME_absolute_get();
3741 va->session = peer_address->session;
3742 if (peer_address->addr != NULL)
3744 va->addr = (const void*) &va[1];
3745 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3746 va->addrlen = peer_address->addrlen;
3748 memcpy(&va->publicKey,
3749 &neighbour->publicKey,
3750 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3752 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3753 &timeout_hello_validation,
3755 GNUNET_CONTAINER_multihashmap_put (validation_map,
3756 &neighbour->id.hashPubKey,
3758 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3760 if (peer_address->validated != GNUNET_YES)
3761 hello_size = GNUNET_HELLO_size(our_hello);
3765 tsize = sizeof(struct TransportPingMessage) + hello_size;
3767 if (peer_address->addr != NULL)
3769 slen = strlen (tp->short_name) + 1;
3770 tsize += slen + peer_address->addrlen;
3774 slen = 0; /* make gcc happy */
3776 message_buf = GNUNET_malloc(tsize);
3777 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3778 ping.challenge = htonl(va->challenge);
3779 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3780 if (peer_address->validated != GNUNET_YES)
3782 memcpy(message_buf, our_hello, hello_size);
3785 if (peer_address->addr != NULL)
3787 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3788 peer_address->addrlen +
3790 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3793 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3795 peer_address->addrlen);
3799 ping.header.size = htons(sizeof(struct TransportPingMessage));
3802 memcpy(&message_buf[hello_size],
3804 sizeof(struct TransportPingMessage));
3806 #if DEBUG_TRANSPORT_REVALIDATION
3807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3808 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3809 (peer_address->addr != NULL)
3810 ? a2s (peer_address->plugin->short_name,
3812 peer_address->addrlen)
3815 GNUNET_i2s (&neighbour->id),
3816 "HELLO", hello_size,
3819 if (peer_address->validated != GNUNET_YES)
3820 GNUNET_STATISTICS_update (stats,
3821 gettext_noop ("# PING with HELLO messages sent"),
3825 GNUNET_STATISTICS_update (stats,
3826 gettext_noop ("# PING without HELLO messages sent"),
3829 GNUNET_STATISTICS_update (stats,
3830 gettext_noop ("# PING messages sent for re-validation"),
3833 transmit_to_peer (NULL, peer_address,
3834 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3835 HELLO_VERIFICATION_TIMEOUT,
3837 GNUNET_YES, neighbour);
3838 GNUNET_free(message_buf);
3839 schedule_next_ping (peer_address);
3844 * Schedule the job that will cause us to send a PING to the
3845 * foreign address to evaluate its validity and latency.
3847 * @param fal address to PING
3850 schedule_next_ping (struct ForeignAddressList *fal)
3852 struct GNUNET_TIME_Relative delay;
3854 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3856 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3857 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3859 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3860 delay.rel_value /= 2; /* do before expiration */
3861 delay = GNUNET_TIME_relative_min (delay,
3862 LATENCY_EVALUATION_MAX_DELAY);
3863 if (GNUNET_YES != fal->estimated)
3865 delay = GNUNET_TIME_UNIT_ZERO;
3866 fal->estimated = GNUNET_YES;
3869 if (GNUNET_YES == fal->connected)
3871 delay = GNUNET_TIME_relative_min (delay,
3872 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3874 /* FIXME: also adjust delay based on how close the last
3875 observed latency is to the latency of the best alternative */
3876 /* bound how fast we can go */
3877 delay = GNUNET_TIME_relative_max (delay,
3878 GNUNET_TIME_UNIT_SECONDS);
3879 /* randomize a bit (to avoid doing all at the same time) */
3880 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3882 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3883 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3884 &send_periodic_ping,
3892 * Function that will be called if we receive some payload
3893 * from another peer.
3895 * @param message the payload
3896 * @param n peer who claimed to be the sender
3899 handle_payload_message (const struct GNUNET_MessageHeader *message,
3900 struct NeighbourList *n)
3902 struct InboundMessage *im;
3903 struct TransportClient *cpos;
3906 msize = ntohs (message->size);
3907 if (n->received_pong == GNUNET_NO)
3910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3911 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3912 ntohs (message->type),
3913 ntohs (message->size),
3914 GNUNET_i2s (&n->id));
3916 GNUNET_free_non_null (n->pre_connect_message_buffer);
3917 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3918 memcpy (n->pre_connect_message_buffer, message, msize);
3923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3924 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3925 ntohs (message->type),
3926 ntohs (message->size),
3927 GNUNET_i2s (&n->id));
3929 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3932 n->quota_violation_count++;
3934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3935 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3936 n->in_tracker.available_bytes_per_s__,
3937 n->quota_violation_count);
3939 /* Discount 32k per violation */
3940 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3945 if (n->quota_violation_count > 0)
3947 /* try to add 32k back */
3948 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3950 n->quota_violation_count--;
3953 GNUNET_STATISTICS_update (stats,
3954 gettext_noop ("# payload received from other peers"),
3957 /* transmit message to all clients */
3958 uint32_t ats_count = 2;
3959 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3960 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3963 im = GNUNET_malloc (size);
3964 im->header.size = htons (size);
3965 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3967 im->ats_count = htonl(ats_count);
3968 /* Setting ATS data */
3969 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3970 (&(im->ats))[0].value = htonl (n->distance);
3971 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3972 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3973 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3974 (&(im->ats))[ats_count].value = htonl (0);
3976 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3978 while (cpos != NULL)
3980 transmit_to_client (cpos, &im->header, GNUNET_YES);
3988 * Iterator over hash map entries. Checks if the given validation
3989 * entry is for the same challenge as what is given in the PONG.
3991 * @param cls the 'struct TransportPongMessage*'
3992 * @param key peer identity
3993 * @param value value in the hash map ('struct ValidationEntry')
3994 * @return GNUNET_YES if we should continue to
3995 * iterate (mismatch), GNUNET_NO if not (entry matched)
3998 check_pending_validation (void *cls,
3999 const GNUNET_HashCode * key,
4002 const struct TransportPongMessage *pong = cls;
4003 struct ValidationEntry *ve = value;
4004 struct AddValidatedAddressContext avac;
4005 unsigned int challenge = ntohl(pong->challenge);
4006 struct GNUNET_HELLO_Message *hello;
4007 struct GNUNET_PeerIdentity target;
4008 struct NeighbourList *n;
4009 struct ForeignAddressList *fal;
4010 struct OwnAddressList *oal;
4011 struct TransportPlugin *tp;
4012 struct GNUNET_MessageHeader *prem;
4018 ps = ntohs (pong->header.size);
4019 if (ps < sizeof (struct TransportPongMessage))
4021 GNUNET_break_op (0);
4024 addr = (const char*) &pong[1];
4025 slen = strlen (ve->transport_name) + 1;
4026 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4027 (ve->challenge != challenge) ||
4028 (addr[slen-1] != '\0') ||
4029 (0 != strcmp (addr, ve->transport_name)) ||
4030 (ntohl (pong->purpose.size)
4031 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4033 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4034 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4039 alen = ps - sizeof (struct TransportPongMessage) - slen;
4040 switch (ntohl (pong->purpose.purpose))
4042 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4043 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4044 (0 != memcmp (&addr[slen],
4048 return GNUNET_YES; /* different entry, keep trying! */
4050 if (0 != memcmp (&pong->pid,
4052 sizeof (struct GNUNET_PeerIdentity)))
4054 GNUNET_break_op (0);
4058 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4063 GNUNET_break_op (0);
4068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4069 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4071 a2s (ve->transport_name,
4072 (const struct sockaddr *) ve->addr,
4074 ve->transport_name);
4077 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4078 if (0 != memcmp (&pong->pid,
4080 sizeof (struct GNUNET_PeerIdentity)))
4084 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4087 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4088 GNUNET_i2s (&my_identity),
4094 if (ve->addrlen != 0)
4096 /* must have been for a different validation entry */
4099 tp = find_transport (ve->transport_name);
4105 oal = tp->addresses;
4108 if ( (oal->addrlen == alen) &&
4109 (0 == memcmp (&oal[1],
4117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4118 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4119 GNUNET_i2s (&pong->pid),
4120 a2s (ve->transport_name,
4123 /* FIXME: since the sender of the PONG currently uses the
4124 wrong address (see FIMXE there!), we cannot run a
4125 proper check here... */
4131 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4136 GNUNET_break_op (0);
4141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4142 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4144 a2s (ve->transport_name,
4147 ve->transport_name);
4151 GNUNET_break_op (0);
4154 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4156 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4157 _("Received expired signature. Check system time.\n"));
4160 GNUNET_STATISTICS_update (stats,
4161 gettext_noop ("# address validation successes"),
4164 /* create the updated HELLO */
4165 GNUNET_CRYPTO_hash (&ve->publicKey,
4166 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4167 &target.hashPubKey);
4168 if (ve->addr != NULL)
4170 avac.done = GNUNET_NO;
4172 hello = GNUNET_HELLO_create (&ve->publicKey,
4173 &add_validated_address,
4175 GNUNET_PEERINFO_add_peer (peerinfo,
4177 GNUNET_free (hello);
4179 n = find_neighbour (&target);
4182 n->publicKey = ve->publicKey;
4183 n->public_key_valid = GNUNET_YES;
4184 fal = add_peer_address (n,
4189 GNUNET_assert (fal != NULL);
4190 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4191 fal->validated = GNUNET_YES;
4192 mark_address_connected (fal);
4193 GNUNET_STATISTICS_update (stats,
4194 gettext_noop ("# peer addresses considered valid"),
4197 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4198 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4200 schedule_next_ping (fal);
4201 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4202 n->latency = fal->latency;
4204 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4206 n->distance = fal->distance;
4207 if (GNUNET_NO == n->received_pong)
4209 n->received_pong = GNUNET_YES;
4210 notify_clients_connect (&target, n->latency, n->distance);
4211 if (NULL != (prem = n->pre_connect_message_buffer))
4213 n->pre_connect_message_buffer = NULL;
4214 handle_payload_message (prem, n);
4218 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4220 GNUNET_SCHEDULER_cancel (n->retry_task);
4221 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4222 try_transmission_to_peer (n);
4226 /* clean up validation entry */
4227 GNUNET_assert (GNUNET_YES ==
4228 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4231 abort_validation (NULL, NULL, ve);
4237 * Function that will be called if we receive a validation
4238 * of an address challenge that we transmitted to another
4239 * peer. Note that the validation should only be considered
4240 * acceptable if the challenge matches AND if the sender
4241 * address is at least a plausible address for this peer
4242 * (otherwise we may be seeing a MiM attack).
4244 * @param cls closure
4245 * @param message the pong message
4246 * @param peer who responded to our challenge
4247 * @param sender_address string describing our sender address (as observed
4248 * by the other peer in binary format)
4249 * @param sender_address_len number of bytes in 'sender_address'
4252 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4253 const struct GNUNET_PeerIdentity *peer,
4254 const char *sender_address,
4255 size_t sender_address_len)
4257 if (0 == memcmp (peer,
4259 sizeof (struct GNUNET_PeerIdentity)))
4261 /* PONG send to self, ignore */
4262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4263 "Receiving `%s' message from myself\n",
4267 #if DEBUG_TRANSPORT > 1
4268 /* we get tons of these that just get discarded, only log
4269 if we are quite verbose */
4270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4271 "Receiving `%s' message from `%4s'.\n", "PONG",
4274 GNUNET_STATISTICS_update (stats,
4275 gettext_noop ("# PONG messages received"),
4278 if (GNUNET_SYSERR !=
4279 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4281 &check_pending_validation,
4284 /* This is *expected* to happen a lot since we send
4285 PONGs to *all* known addresses of the sender of
4286 the PING, so most likely we get multiple PONGs
4287 per PING, and all but the first PONG will end up
4288 here. So really we should not print anything here
4289 unless we want to be very, very verbose... */
4290 #if DEBUG_TRANSPORT > 2
4291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4292 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4304 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4306 * @param cls the 'struct ValidationEntry*'
4307 * @param neighbour neighbour to validate, NULL if validation failed
4310 transmit_hello_and_ping (void *cls,
4311 struct NeighbourList *neighbour)
4313 struct ValidationEntry *va = cls;
4314 struct ForeignAddressList *peer_address;
4315 struct TransportPingMessage ping;
4316 uint16_t hello_size;
4319 struct GNUNET_PeerIdentity id;
4322 GNUNET_CRYPTO_hash (&va->publicKey,
4323 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4325 if (neighbour == NULL)
4327 /* FIXME: stats... */
4328 GNUNET_break (GNUNET_OK ==
4329 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4332 abort_validation (NULL, NULL, va);
4335 neighbour->publicKey = va->publicKey;
4336 neighbour->public_key_valid = GNUNET_YES;
4337 peer_address = add_peer_address (neighbour,
4338 va->transport_name, NULL,
4339 (const void*) &va[1],
4341 if (peer_address == NULL)
4343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4344 "Failed to add peer `%4s' for plugin `%s'\n",
4345 GNUNET_i2s (&neighbour->id),
4346 va->transport_name);
4347 GNUNET_break (GNUNET_OK ==
4348 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4351 abort_validation (NULL, NULL, va);
4354 if (NULL == our_hello)
4355 refresh_hello_task (NULL, NULL);
4356 hello_size = GNUNET_HELLO_size(our_hello);
4357 slen = strlen(va->transport_name) + 1;
4358 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4359 message_buf = GNUNET_malloc(tsize);
4360 ping.challenge = htonl(va->challenge);
4361 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4362 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4363 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4364 memcpy(message_buf, our_hello, hello_size);
4365 memcpy(&message_buf[hello_size],
4367 sizeof(struct TransportPingMessage));
4368 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4371 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4376 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4379 : a2s (va->transport_name,
4380 (const void*) &va[1], va->addrlen),
4382 GNUNET_i2s (&neighbour->id),
4383 "HELLO", hello_size,
4384 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4387 GNUNET_STATISTICS_update (stats,
4388 gettext_noop ("# PING messages sent for initial validation"),
4391 transmit_to_peer (NULL, peer_address,
4392 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4393 HELLO_VERIFICATION_TIMEOUT,
4395 GNUNET_YES, neighbour);
4396 GNUNET_free(message_buf);
4401 * Check if the given address is already being validated; if not,
4402 * append the given address to the list of entries that are being be
4403 * validated and initiate validation.
4405 * @param cls closure ('struct CheckHelloValidatedContext *')
4406 * @param tname name of the transport
4407 * @param expiration expiration time
4408 * @param addr the address
4409 * @param addrlen length of the address
4410 * @return GNUNET_OK (always)
4413 run_validation (void *cls,
4415 struct GNUNET_TIME_Absolute expiration,
4419 struct CheckHelloValidatedContext *chvc = cls;
4420 struct GNUNET_PeerIdentity id;
4421 struct TransportPlugin *tp;
4422 struct ValidationEntry *va;
4423 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4424 struct CheckAddressExistsClosure caec;
4425 struct OwnAddressList *oal;
4427 GNUNET_assert (addr != NULL);
4429 GNUNET_STATISTICS_update (stats,
4430 gettext_noop ("# peer addresses scheduled for validation"),
4433 tp = find_transport (tname);
4436 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4437 GNUNET_ERROR_TYPE_BULK,
4439 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4441 GNUNET_STATISTICS_update (stats,
4442 gettext_noop ("# peer addresses not validated (plugin not available)"),
4447 /* check if this is one of our own addresses */
4448 oal = tp->addresses;
4451 if ( (oal->addrlen == addrlen) &&
4452 (0 == memcmp (&oal[1],
4456 /* not plausible, this address is equivalent to our own address! */
4457 GNUNET_STATISTICS_update (stats,
4458 gettext_noop ("# peer addresses not validated (loopback)"),
4465 GNUNET_HELLO_get_key (chvc->hello, &pk);
4466 GNUNET_CRYPTO_hash (&pk,
4468 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4471 if (is_blacklisted(&id, tp))
4474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4475 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4483 caec.addrlen = addrlen;
4484 caec.session = NULL;
4486 caec.exists = GNUNET_NO;
4487 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4488 &check_address_exists,
4490 if (caec.exists == GNUNET_YES)
4492 /* During validation attempts we will likely trigger the other
4493 peer trying to validate our address which in turn will cause
4494 it to send us its HELLO, so we expect to hit this case rather
4495 frequently. Only print something if we are very verbose. */
4496 #if DEBUG_TRANSPORT > 1
4497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4498 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4499 a2s (tname, addr, addrlen),
4503 GNUNET_STATISTICS_update (stats,
4504 gettext_noop ("# peer addresses not validated (in progress)"),
4509 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4512 va->transport_name = GNUNET_strdup (tname);
4513 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4515 va->send_time = GNUNET_TIME_absolute_get();
4516 va->addr = (const void*) &va[1];
4517 memcpy (&va[1], addr, addrlen);
4518 va->addrlen = addrlen;
4519 GNUNET_HELLO_get_key (chvc->hello,
4521 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4522 &timeout_hello_validation,
4524 GNUNET_CONTAINER_multihashmap_put (validation_map,
4527 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4528 setup_peer_check_blacklist (&id, GNUNET_NO,
4529 &transmit_hello_and_ping,
4536 * Check if addresses in validated hello "h" overlap with
4537 * those in "chvc->hello" and validate the rest.
4539 * @param cls closure
4540 * @param peer id of the peer, NULL for last call
4541 * @param h hello message for the peer (can be NULL)
4542 * @param err_msg NULL if successful, otherwise contains error message
4545 check_hello_validated (void *cls,
4546 const struct GNUNET_PeerIdentity *peer,
4547 const struct GNUNET_HELLO_Message *h,
4548 const char *err_msg)
4550 struct CheckHelloValidatedContext *chvc = cls;
4551 struct GNUNET_HELLO_Message *plain_hello;
4552 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4553 struct GNUNET_PeerIdentity target;
4554 struct NeighbourList *n;
4556 if (err_msg != NULL)
4559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4560 _("Error in communication with PEERINFO service: %s\n"),
4568 GNUNET_STATISTICS_update (stats,
4569 gettext_noop ("# outstanding peerinfo iterate requests"),
4573 if (GNUNET_NO == chvc->hello_known)
4575 /* notify PEERINFO about the peer now, so that we at least
4576 have the public key if some other component needs it */
4577 GNUNET_HELLO_get_key (chvc->hello, &pk);
4578 GNUNET_CRYPTO_hash (&pk,
4579 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4580 &target.hashPubKey);
4581 plain_hello = GNUNET_HELLO_create (&pk,
4584 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4585 GNUNET_free (plain_hello);
4586 #if DEBUG_TRANSPORT_HELLO
4587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4588 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4590 GNUNET_i2s (&target));
4592 GNUNET_STATISTICS_update (stats,
4593 gettext_noop ("# new HELLOs requiring full validation"),
4596 GNUNET_HELLO_iterate_addresses (chvc->hello,
4603 GNUNET_STATISTICS_update (stats,
4604 gettext_noop ("# duplicate HELLO (peer known)"),
4609 if (chvc->ve_count == 0)
4611 GNUNET_CONTAINER_DLL_remove (chvc_head,
4620 #if DEBUG_TRANSPORT_HELLO
4621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4622 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4626 chvc->hello_known = GNUNET_YES;
4627 n = find_neighbour (peer);
4630 #if DEBUG_TRANSPORT_HELLO
4631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4632 "Calling hello_iterate_addresses for %s!\n",
4635 GNUNET_HELLO_iterate_addresses (h,
4637 &add_to_foreign_address_list,
4639 try_transmission_to_peer (n);
4643 #if DEBUG_TRANSPORT_HELLO
4644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4645 "No existing neighbor record for %s!\n",
4648 GNUNET_STATISTICS_update (stats,
4649 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4653 GNUNET_STATISTICS_update (stats,
4654 gettext_noop ("# HELLO validations (update case)"),
4657 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4659 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4666 * Process HELLO-message.
4668 * @param plugin transport involved, may be NULL
4669 * @param message the actual message
4670 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4673 process_hello (struct TransportPlugin *plugin,
4674 const struct GNUNET_MessageHeader *message)
4677 struct GNUNET_PeerIdentity target;
4678 const struct GNUNET_HELLO_Message *hello;
4679 struct CheckHelloValidatedContext *chvc;
4680 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4681 struct NeighbourList *n;
4682 #if DEBUG_TRANSPORT_HELLO > 2
4686 hsize = ntohs (message->size);
4687 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4688 (hsize < sizeof (struct GNUNET_MessageHeader)))
4691 return GNUNET_SYSERR;
4693 GNUNET_STATISTICS_update (stats,
4694 gettext_noop ("# HELLOs received for validation"),
4698 hello = (const struct GNUNET_HELLO_Message *) message;
4699 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4701 #if DEBUG_TRANSPORT_HELLO
4702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4703 "Unable to get public key from `%s' for `%4s'!\n",
4705 GNUNET_i2s (&target));
4707 GNUNET_break_op (0);
4708 return GNUNET_SYSERR;
4710 GNUNET_CRYPTO_hash (&publicKey,
4711 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4712 &target.hashPubKey);
4714 #if DEBUG_TRANSPORT_HELLO
4715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4716 "Received `%s' message for `%4s'\n",
4718 GNUNET_i2s (&target));
4720 if (0 == memcmp (&my_identity,
4722 sizeof (struct GNUNET_PeerIdentity)))
4724 GNUNET_STATISTICS_update (stats,
4725 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4730 n = find_neighbour (&target);
4732 (! n->public_key_valid) )
4734 GNUNET_HELLO_get_key (hello, &n->publicKey);
4735 n->public_key_valid = GNUNET_YES;
4738 /* check if load is too high before doing expensive stuff */
4739 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4741 GNUNET_STATISTICS_update (stats,
4742 gettext_noop ("# HELLOs ignored due to high load"),
4745 #if DEBUG_TRANSPORT_HELLO
4746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4747 "Ignoring `%s' for `%4s', load too high.\n",
4749 GNUNET_i2s (&target));
4756 while (NULL != chvc)
4758 if (GNUNET_HELLO_equals (hello,
4760 GNUNET_TIME_absolute_get ()).abs_value > 0)
4762 #if DEBUG_TRANSPORT_HELLO > 2
4763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4764 "Received duplicate `%s' message for `%4s'; ignored\n",
4766 GNUNET_i2s (&target));
4768 return GNUNET_OK; /* validation already pending */
4770 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4771 GNUNET_break (0 != memcmp (hello, chvc->hello,
4772 GNUNET_HELLO_size(hello)));
4777 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4778 if ((NULL != temp_neighbor))
4780 fprintf(stderr, "Already know peer, ignoring hello\n");
4785 #if DEBUG_TRANSPORT_HELLO > 2
4788 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4791 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4794 GNUNET_i2s (&target),
4796 GNUNET_HELLO_size(hello));
4801 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4803 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4804 memcpy (&chvc[1], hello, hsize);
4805 GNUNET_CONTAINER_DLL_insert (chvc_head,
4808 /* finally, check if HELLO was previously validated
4809 (continuation will then schedule actual validation) */
4810 GNUNET_STATISTICS_update (stats,
4811 gettext_noop ("# peerinfo process hello iterate requests"),
4814 GNUNET_STATISTICS_update (stats,
4815 gettext_noop ("# outstanding peerinfo iterate requests"),
4818 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4820 HELLO_VERIFICATION_TIMEOUT,
4821 &check_hello_validated, chvc);
4827 * The peer specified by the given neighbour has timed-out or a plugin
4828 * has disconnected. We may either need to do nothing (other plugins
4829 * still up), or trigger a full disconnect and clean up. This
4830 * function updates our state and does the necessary notifications.
4831 * Also notifies our clients that the neighbour is now officially
4834 * @param n the neighbour list entry for the peer
4835 * @param check GNUNET_YES to check if ALL addresses for this peer
4836 * are gone, GNUNET_NO to force a disconnect of the peer
4837 * regardless of whether other addresses exist.
4840 disconnect_neighbour (struct NeighbourList *n, int check)
4842 struct ReadyList *rpos;
4843 struct NeighbourList *npos;
4844 struct NeighbourList *nprev;
4845 struct MessageQueue *mq;
4846 struct ForeignAddressList *peer_addresses;
4847 struct ForeignAddressList *peer_pos;
4849 if (GNUNET_YES == n->in_disconnect)
4851 if (GNUNET_YES == check)
4854 while (NULL != rpos)
4856 peer_addresses = rpos->addresses;
4857 while (peer_addresses != NULL)
4859 /* Do not disconnect if: an address is connected or an inbound address exists */
4860 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4864 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4865 GNUNET_i2s (&n->id),
4866 a2s (peer_addresses->ready_list->plugin->short_name,
4867 peer_addresses->addr,
4868 peer_addresses->addrlen));
4870 return; /* still connected */
4872 peer_addresses = peer_addresses->next;
4878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4879 "Disconnecting from `%4s'\n",
4880 GNUNET_i2s (&n->id));
4882 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4884 /* notify all clients about disconnect */
4885 if (GNUNET_YES == n->received_pong)
4887 n->received_pong = GNUNET_NO;
4888 notify_clients_disconnect (&n->id);
4891 ats_modify_problem_state(ats, ATS_MODIFIED);
4893 /* clean up all plugins, cancel connections and pending transmissions */
4894 while (NULL != (rpos = n->plugins))
4896 n->plugins = rpos->next;
4897 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4898 while (rpos->addresses != NULL)
4900 peer_pos = rpos->addresses;
4901 rpos->addresses = peer_pos->next;
4902 if (peer_pos->connected == GNUNET_YES)
4903 GNUNET_STATISTICS_update (stats,
4904 gettext_noop ("# connected addresses"),
4907 if (GNUNET_YES == peer_pos->validated)
4908 GNUNET_STATISTICS_update (stats,
4909 gettext_noop ("# peer addresses considered valid"),
4912 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4914 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4915 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4917 GNUNET_free(peer_pos->ressources);
4918 peer_pos->ressources = NULL;
4919 GNUNET_free(peer_pos->quality);
4920 peer_pos->ressources = NULL;
4921 GNUNET_free(peer_pos);
4926 /* free all messages on the queue */
4927 while (NULL != (mq = n->messages_head))
4929 GNUNET_STATISTICS_update (stats,
4930 gettext_noop ("# bytes in message queue for other peers"),
4931 - (int64_t) mq->message_buf_size,
4933 GNUNET_STATISTICS_update (stats,
4934 gettext_noop ("# bytes discarded due to disconnect"),
4935 mq->message_buf_size,
4937 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4940 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4942 sizeof(struct GNUNET_PeerIdentity)));
4946 while (NULL != (mq = n->cont_head))
4949 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4952 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4954 sizeof(struct GNUNET_PeerIdentity)));
4958 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4960 GNUNET_SCHEDULER_cancel (n->timeout_task);
4961 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4963 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4965 GNUNET_SCHEDULER_cancel (n->retry_task);
4966 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4968 if (n->piter != NULL)
4970 GNUNET_PEERINFO_iterate_cancel (n->piter);
4971 GNUNET_STATISTICS_update (stats,
4972 gettext_noop ("# outstanding peerinfo iterate requests"),
4978 /* remove n from neighbours list */
4981 while ((npos != NULL) && (npos != n))
4986 GNUNET_assert (npos != NULL);
4988 neighbours = n->next;
4990 nprev->next = n->next;
4992 /* finally, free n itself */
4993 GNUNET_STATISTICS_update (stats,
4994 gettext_noop ("# active neighbours"),
4997 GNUNET_free_non_null (n->pre_connect_message_buffer);
5003 * We have received a PING message from someone. Need to send a PONG message
5004 * in response to the peer by any means necessary.
5007 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5008 const struct GNUNET_PeerIdentity *peer,
5009 struct Session *session,
5010 const char *sender_address,
5011 uint16_t sender_address_len)
5013 struct TransportPlugin *plugin = cls;
5014 struct SessionHeader *session_header = (struct SessionHeader*) session;
5015 struct TransportPingMessage *ping;
5016 struct TransportPongMessage *pong;
5017 struct NeighbourList *n;
5018 struct ReadyList *rl;
5019 struct ForeignAddressList *fal;
5020 struct OwnAddressList *oal;
5026 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5028 GNUNET_break_op (0);
5029 return GNUNET_SYSERR;
5032 ping = (struct TransportPingMessage *) message;
5033 if (0 != memcmp (&ping->target,
5034 plugin->env.my_identity,
5035 sizeof (struct GNUNET_PeerIdentity)))
5038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5039 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5041 (sender_address != NULL)
5042 ? a2s (plugin->short_name,
5043 (const struct sockaddr *)sender_address,
5046 GNUNET_i2s (&ping->target));
5048 return GNUNET_SYSERR;
5051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5052 "Processing `%s' from `%s'\n",
5054 (sender_address != NULL)
5055 ? a2s (plugin->short_name,
5056 (const struct sockaddr *)sender_address,
5060 GNUNET_STATISTICS_update (stats,
5061 gettext_noop ("# PING messages received"),
5064 addr = (const char*) &ping[1];
5065 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5066 slen = strlen (plugin->short_name) + 1;
5069 /* peer wants to confirm that we have an outbound connection to him */
5070 if (session == NULL)
5072 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5073 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5075 return GNUNET_SYSERR;
5077 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5078 1) it is NULL when we need to have a real value
5079 2) it is documented to be the address of the sender (source-IP), where
5080 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5084 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5085 a2s (plugin->short_name,
5087 sender_address_len),
5090 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5091 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5092 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5093 pong->purpose.size =
5094 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5096 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5097 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5098 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5099 pong->challenge = ping->challenge;
5100 pong->addrlen = htonl(sender_address_len + slen);
5103 sizeof(struct GNUNET_PeerIdentity));
5107 if ((sender_address!=NULL) && (sender_address_len > 0))
5108 memcpy (&((char*)&pong[1])[slen],
5110 sender_address_len);
5111 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5113 /* create / update cached sig */
5115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5116 "Creating PONG signature to indicate active connection.\n");
5118 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5119 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5120 GNUNET_assert (GNUNET_OK ==
5121 GNUNET_CRYPTO_rsa_sign (my_private_key,
5123 &session_header->pong_signature));
5127 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5129 memcpy (&pong->signature,
5130 &session_header->pong_signature,
5131 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5137 /* peer wants to confirm that this is one of our addresses */
5141 plugin->api->check_address (plugin->api->cls,
5145 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5146 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5147 a2s (plugin->short_name,
5152 oal = plugin->addresses;
5155 if ( (oal->addrlen == alen) &&
5162 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5163 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5164 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5165 pong->purpose.size =
5166 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5168 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5169 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5170 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5171 pong->challenge = ping->challenge;
5172 pong->addrlen = htonl(alen + slen);
5175 sizeof(struct GNUNET_PeerIdentity));
5176 memcpy (&pong[1], plugin->short_name, slen);
5177 memcpy (&((char*)&pong[1])[slen], addr, alen);
5178 if ( (oal != NULL) &&
5179 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5181 /* create / update cached sig */
5183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5184 "Creating PONG signature to indicate ownership.\n");
5186 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5187 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5188 GNUNET_assert (GNUNET_OK ==
5189 GNUNET_CRYPTO_rsa_sign (my_private_key,
5191 &oal->pong_signature));
5192 memcpy (&pong->signature,
5193 &oal->pong_signature,
5194 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5196 else if (oal == NULL)
5198 /* not using cache (typically DV-only) */
5199 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5200 GNUNET_assert (GNUNET_OK ==
5201 GNUNET_CRYPTO_rsa_sign (my_private_key,
5207 /* can used cached version */
5208 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5209 memcpy (&pong->signature,
5210 &oal->pong_signature,
5211 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5214 n = find_neighbour(peer);
5215 GNUNET_assert (n != NULL);
5216 did_pong = GNUNET_NO;
5217 /* first try reliable response transmission */
5221 fal = rl->addresses;
5224 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5227 ntohs (pong->header.size),
5228 TRANSPORT_PONG_PRIORITY,
5229 HELLO_VERIFICATION_TIMEOUT,
5236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5237 "Transmitted PONG to `%s' via reliable mechanism\n",
5240 GNUNET_STATISTICS_update (stats,
5241 gettext_noop ("# PONGs unicast via reliable transport"),
5247 did_pong = GNUNET_YES;
5252 /* no reliable method found, do multicast */
5253 GNUNET_STATISTICS_update (stats,
5254 gettext_noop ("# PONGs multicast to all available addresses"),
5260 fal = rl->addresses;
5263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5264 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5266 a2s (rl->plugin->short_name,
5269 rl->plugin->short_name);
5270 transmit_to_peer(NULL, fal,
5271 TRANSPORT_PONG_PRIORITY,
5272 HELLO_VERIFICATION_TIMEOUT,
5274 ntohs(pong->header.size),
5277 did_pong = GNUNET_YES;
5283 if (GNUNET_YES != did_pong)
5284 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5285 _("Could not send PONG to `%s': no address available\n"),
5292 * Function called by the plugin for each received message. Update
5293 * data volumes, possibly notify plugins about reducing the rate at
5294 * which they read from the socket and generally forward to our
5297 * @param cls the "struct TransportPlugin *" we gave to the plugin
5298 * @param peer (claimed) identity of the other peer
5299 * @param message the message, NULL if we only care about
5300 * learning about the delay until we should receive again
5301 * @param ats_data information for automatic transport selection
5302 * @param ats_count number of elements in ats not including 0-terminator
5303 * @param session identifier used for this session (can be NULL)
5304 * @param sender_address binary address of the sender (if observed)
5305 * @param sender_address_len number of bytes in sender_address
5306 * @return how long in ms the plugin should wait until receiving more data
5307 * (plugins that do not support this, can ignore the return value)
5309 static struct GNUNET_TIME_Relative
5310 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5311 const struct GNUNET_MessageHeader *message,
5312 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5314 struct Session *session,
5315 const char *sender_address,
5316 uint16_t sender_address_len)
5318 struct TransportPlugin *plugin = cls;
5319 struct ReadyList *service_context;
5320 struct ForeignAddressList *peer_address;
5322 struct NeighbourList *n;
5323 struct GNUNET_TIME_Relative ret;
5327 if (0 == memcmp (peer,
5329 sizeof (struct GNUNET_PeerIdentity)))
5331 /* refuse to receive from myself */
5333 return GNUNET_TIME_UNIT_FOREVER_REL;
5335 if (is_blacklisted (peer, plugin))
5336 return GNUNET_TIME_UNIT_FOREVER_REL;
5337 n = find_neighbour (peer);
5339 n = setup_new_neighbour (peer, GNUNET_YES);
5340 service_context = n->plugins;
5341 while ((service_context != NULL) && (plugin != service_context->plugin))
5342 service_context = service_context->next;
5343 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5344 peer_address = NULL;
5347 for (c=0; c<ats_count; c++)
5348 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5349 distance = ntohl(ats_data[c].value);
5352 if (message != NULL)
5354 if ( (session != NULL) ||
5355 (sender_address != NULL) )
5356 peer_address = add_peer_address (n,
5360 sender_address_len);
5361 if (peer_address != NULL)
5363 update_addr_ats(peer_address, ats_data, ats_count);
5364 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5366 peer_address->distance = distance;
5367 if (GNUNET_YES == peer_address->validated)
5369 mark_address_connected (peer_address);
5370 schedule_next_ping (peer_address);
5375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5376 "New address is unvalidated, trying to validate it now\n");
5378 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5380 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5381 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5383 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5386 peer_address->timeout
5387 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5389 /* update traffic received amount ... */
5390 msize = ntohs (message->size);
5392 GNUNET_STATISTICS_update (stats,
5393 gettext_noop ("# bytes received from other peers"),
5396 n->distance = distance;
5398 GNUNET_TIME_relative_to_absolute
5399 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5400 GNUNET_SCHEDULER_cancel (n->timeout_task);
5402 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5403 &neighbour_timeout_task, n);
5404 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5406 /* dropping message due to frequent inbound volume violations! */
5407 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5408 GNUNET_ERROR_TYPE_BULK,
5410 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5411 n->in_tracker.available_bytes_per_s__,
5412 n->quota_violation_count);
5413 GNUNET_STATISTICS_update (stats,
5414 gettext_noop ("# bandwidth quota violations by other peers"),
5417 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5419 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5420 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5422 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5423 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5424 /* Force ressource and quality update */
5425 if ((value == 4) && (ats != NULL))
5426 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5427 /* Force cost update */
5428 if ((value == 3) && (ats != NULL))
5429 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5430 /* Force quality update */
5431 if ((value == 2) && (ats != NULL))
5432 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5433 /* Force full rebuild */
5434 if ((value == 1) && (ats != NULL))
5435 ats_modify_problem_state(ats, ATS_MODIFIED);
5439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5440 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5441 ntohs (message->type),
5442 ntohs (message->size),
5445 switch (ntohs (message->type))
5447 case GNUNET_MESSAGE_TYPE_HELLO:
5448 GNUNET_STATISTICS_update (stats,
5449 gettext_noop ("# HELLO messages received from other peers"),
5452 process_hello (plugin, message);
5454 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5455 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5456 if (GNUNET_YES != n->received_pong)
5457 transmit_plain_ping (n);
5459 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5460 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5462 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5465 handle_payload_message (message, n);
5469 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5470 if (ret.rel_value > 0)
5473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5474 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5475 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5476 (unsigned int) n->in_tracker.available_bytes_per_s__,
5477 (unsigned long long) ret.rel_value);
5479 GNUNET_STATISTICS_update (stats,
5480 gettext_noop ("# ms throttling suggested"),
5481 (int64_t) ret.rel_value,
5488 * Handle START-message. This is the first message sent to us
5489 * by any client which causes us to add it to our list.
5491 * @param cls closure (always NULL)
5492 * @param client identification of the client
5493 * @param message the actual message
5496 handle_start (void *cls,
5497 struct GNUNET_SERVER_Client *client,
5498 const struct GNUNET_MessageHeader *message)
5500 const struct StartMessage *start;
5501 struct TransportClient *c;
5502 struct ConnectInfoMessage * cim;
5503 struct NeighbourList *n;
5507 start = (const struct StartMessage*) message;
5509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5510 "Received `%s' request from client\n", "START");
5515 if (c->client == client)
5517 /* client already on our list! */
5519 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5524 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5525 (0 != memcmp (&start->self,
5527 sizeof (struct GNUNET_PeerIdentity))) )
5529 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5530 _("Rejecting control connection from peer `%s', which is not me!\n"),
5531 GNUNET_i2s (&start->self));
5532 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5535 c = GNUNET_malloc (sizeof (struct TransportClient));
5539 if (our_hello != NULL)
5542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5543 "Sending our own `%s' to new client\n", "HELLO");
5545 transmit_to_client (c,
5546 (const struct GNUNET_MessageHeader *) our_hello,
5548 /* tell new client about all existing connections */
5550 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5551 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5555 cim = GNUNET_malloc (size);
5556 cim->header.size = htons (size);
5557 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5558 cim->ats_count = htonl(ats_count);
5559 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5560 (&(cim->ats))[2].value = htonl (0);
5564 if (GNUNET_YES == n->received_pong)
5566 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5567 (&cim->ats)[0].value = htonl (n->distance);
5568 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5569 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5571 transmit_to_client (c, &cim->header, GNUNET_NO);
5579 #if DEBUG_TRANSPORT_HELLO
5580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5581 "No HELLO created yet, will transmit HELLO to client later!\n");
5585 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5590 * Handle HELLO-message.
5592 * @param cls closure (always NULL)
5593 * @param client identification of the client
5594 * @param message the actual message
5597 handle_hello (void *cls,
5598 struct GNUNET_SERVER_Client *client,
5599 const struct GNUNET_MessageHeader *message)
5603 GNUNET_STATISTICS_update (stats,
5604 gettext_noop ("# HELLOs received from clients"),
5607 ret = process_hello (NULL, message);
5608 GNUNET_SERVER_receive_done (client, ret);
5613 * Closure for 'transmit_client_message'; followed by
5614 * 'msize' bytes of the actual message.
5616 struct TransmitClientMessageContext
5619 * Client on whom's behalf we are sending.
5621 struct GNUNET_SERVER_Client *client;
5624 * Timeout for the transmission.
5626 struct GNUNET_TIME_Absolute timeout;
5634 * Size of the message in bytes.
5641 * Schedule transmission of a message we got from a client to a peer.
5643 * @param cls the 'struct TransmitClientMessageContext*'
5644 * @param n destination, or NULL on error (in that case, drop the message)
5647 transmit_client_message (void *cls,
5648 struct NeighbourList *n)
5650 struct TransmitClientMessageContext *tcmc = cls;
5651 struct TransportClient *tc;
5654 while ((tc != NULL) && (tc->client != tcmc->client))
5659 transmit_to_peer (tc, NULL, tcmc->priority,
5660 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5662 tcmc->msize, GNUNET_NO, n);
5664 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5665 GNUNET_SERVER_client_drop (tcmc->client);
5671 * Handle SEND-message.
5673 * @param cls closure (always NULL)
5674 * @param client identification of the client
5675 * @param message the actual message
5678 handle_send (void *cls,
5679 struct GNUNET_SERVER_Client *client,
5680 const struct GNUNET_MessageHeader *message)
5682 const struct OutboundMessage *obm;
5683 const struct GNUNET_MessageHeader *obmm;
5684 struct TransmitClientMessageContext *tcmc;
5688 size = ntohs (message->size);
5690 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5693 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5696 GNUNET_STATISTICS_update (stats,
5697 gettext_noop ("# payload received for other peers"),
5700 obm = (const struct OutboundMessage *) message;
5701 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5702 msize = size - sizeof (struct OutboundMessage);
5704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5705 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5706 "SEND", GNUNET_i2s (&obm->peer),
5710 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5711 tcmc->client = client;
5712 tcmc->priority = ntohl (obm->priority);
5713 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5714 tcmc->msize = msize;
5715 /* FIXME: this memcpy can be up to 7% of our total runtime */
5716 memcpy (&tcmc[1], obmm, msize);
5717 GNUNET_SERVER_client_keep (client);
5718 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5719 &transmit_client_message,
5725 * Handle request connect message
5727 * @param cls closure (always NULL)
5728 * @param client identification of the client
5729 * @param message the actual message
5732 handle_request_connect (void *cls,
5733 struct GNUNET_SERVER_Client *client,
5734 const struct GNUNET_MessageHeader *message)
5736 const struct TransportRequestConnectMessage *trcm =
5737 (const struct TransportRequestConnectMessage *) message;
5739 GNUNET_STATISTICS_update (stats,
5740 gettext_noop ("# REQUEST CONNECT messages received"),
5744 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5745 "Received a request connect message for peer `%s'\n",
5746 GNUNET_i2s(&trcm->peer));
5748 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5750 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5755 * Handle SET_QUOTA-message.
5757 * @param cls closure (always NULL)
5758 * @param client identification of the client
5759 * @param message the actual message
5762 handle_set_quota (void *cls,
5763 struct GNUNET_SERVER_Client *client,
5764 const struct GNUNET_MessageHeader *message)
5766 const struct QuotaSetMessage *qsm =
5767 (const struct QuotaSetMessage *) message;
5768 struct NeighbourList *n;
5770 GNUNET_STATISTICS_update (stats,
5771 gettext_noop ("# SET QUOTA messages received"),
5774 n = find_neighbour (&qsm->peer);
5777 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5778 GNUNET_STATISTICS_update (stats,
5779 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5786 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5788 (unsigned int) ntohl (qsm->quota.value__),
5789 (unsigned int) n->in_tracker.available_bytes_per_s__,
5790 GNUNET_i2s (&qsm->peer));
5792 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5794 if (0 == ntohl (qsm->quota.value__))
5797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5798 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5801 GNUNET_STATISTICS_update (stats,
5802 gettext_noop ("# disconnects due to quota of 0"),
5805 disconnect_neighbour (n, GNUNET_NO);
5807 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5812 * Take the given address and append it to the set of results sent back to
5815 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5816 * @param address the resolved name, NULL to indicate the last response
5819 transmit_address_to_client (void *cls, const char *address)
5821 struct GNUNET_SERVER_TransmitContext *tc = cls;
5824 if (NULL != address)
5826 slen = strlen (address) + 1;
5827 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5828 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5832 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5838 * Handle AddressLookup-message.
5840 * @param cls closure (always NULL)
5841 * @param client identification of the client
5842 * @param message the actual message
5845 handle_address_lookup (void *cls,
5846 struct GNUNET_SERVER_Client *client,
5847 const struct GNUNET_MessageHeader *message)
5849 const struct AddressLookupMessage *alum;
5850 struct TransportPlugin *lsPlugin;
5851 const char *nameTransport;
5852 const char *address;
5854 struct GNUNET_SERVER_TransmitContext *tc;
5855 struct GNUNET_TIME_Absolute timeout;
5856 struct GNUNET_TIME_Relative rtimeout;
5859 size = ntohs (message->size);
5860 if (size < sizeof (struct AddressLookupMessage))
5862 GNUNET_break_op (0);
5863 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5866 alum = (const struct AddressLookupMessage *) message;
5867 uint32_t addressLen = ntohl (alum->addrlen);
5868 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5870 GNUNET_break_op (0);
5871 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5874 address = (const char *) &alum[1];
5875 nameTransport = (const char *) &address[addressLen];
5877 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5879 GNUNET_break_op (0);
5880 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5883 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5884 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5885 numeric = ntohl (alum->numeric_only);
5886 lsPlugin = find_transport (nameTransport);
5887 if (NULL == lsPlugin)
5889 tc = GNUNET_SERVER_transmit_context_create (client);
5890 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5891 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5892 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5895 GNUNET_SERVER_disable_receive_done_warning (client);
5896 tc = GNUNET_SERVER_transmit_context_create (client);
5897 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5899 address, addressLen,
5902 &transmit_address_to_client, tc);
5906 * Handle PeerAddressLookupMessage.
5908 * @param cls closure (always NULL)
5909 * @param client identification of the client
5910 * @param message the actual message
5913 handle_peer_address_lookup (void *cls,
5914 struct GNUNET_SERVER_Client *client,
5915 const struct GNUNET_MessageHeader *message)
5917 const struct PeerAddressLookupMessage *peer_address_lookup;
5918 struct NeighbourList *neighbor_iterator;
5919 struct ReadyList *ready_iterator;
5920 struct ForeignAddressList *foreign_address_iterator;
5921 struct TransportPlugin *transport_plugin;
5924 struct GNUNET_SERVER_TransmitContext *tc;
5925 struct GNUNET_TIME_Absolute timeout;
5926 struct GNUNET_TIME_Relative rtimeout;
5929 size = ntohs (message->size);
5930 if (size < sizeof (struct PeerAddressLookupMessage))
5932 GNUNET_break_op (0);
5933 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5936 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5938 timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5939 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5941 neighbor_iterator = neighbours;
5942 while (neighbor_iterator != NULL)
5944 if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5946 neighbor_iterator = neighbor_iterator->next;
5949 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5950 if (neighbor_iterator == NULL)
5953 tc = GNUNET_SERVER_transmit_context_create (client);
5954 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5955 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5956 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5960 ready_iterator = neighbor_iterator->plugins;
5961 GNUNET_SERVER_disable_receive_done_warning (client);
5962 tc = GNUNET_SERVER_transmit_context_create (client);
5963 while(ready_iterator != NULL)
5965 foreign_address_iterator = ready_iterator->addresses;
5966 while (foreign_address_iterator != NULL)
5968 transport_plugin = foreign_address_iterator->ready_list->plugin;
5969 if (foreign_address_iterator->addr != NULL)
5971 GNUNET_asprintf (&addr_buf, "%s --- %s",
5972 a2s (transport_plugin->short_name,
5973 foreign_address_iterator->addr,
5974 foreign_address_iterator->addrlen),
5975 (foreign_address_iterator->connected
5976 == GNUNET_YES) ? "CONNECTED"
5978 (foreign_address_iterator->validated
5979 == GNUNET_YES) ? "VALIDATED"
5981 transmit_address_to_client(tc, addr_buf);
5982 GNUNET_free(addr_buf);
5984 else if (foreign_address_iterator->addrlen == 0)
5986 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5987 (foreign_address_iterator->connected
5988 == GNUNET_YES) ? "CONNECTED"
5990 (foreign_address_iterator->validated
5991 == GNUNET_YES) ? "VALIDATED"
5993 transmit_address_to_client (tc, addr_buf);
5994 GNUNET_free(addr_buf);
5997 foreign_address_iterator = foreign_address_iterator->next;
5999 ready_iterator = ready_iterator->next;
6001 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6002 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6003 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6007 * Handle AddressIterateMessage
6009 * @param cls closure (always NULL)
6010 * @param client identification of the client
6011 * @param message the actual message
6014 handle_address_iterate (void *cls,
6015 struct GNUNET_SERVER_Client *client,
6016 const struct GNUNET_MessageHeader *message)
6018 const struct AddressIterateMessage *address_iterate;
6019 struct NeighbourList *neighbor_iterator;
6020 struct ReadyList *ready_iterator;
6021 struct ForeignAddressList *foreign_address_iterator;
6022 struct TransportPlugin *transport_plugin;
6025 struct GNUNET_SERVER_TransmitContext *tc;
6026 struct GNUNET_TIME_Absolute timeout;
6027 struct GNUNET_TIME_Relative rtimeout;
6030 size = ntohs (message->size);
6031 if (size < sizeof (struct AddressIterateMessage))
6033 GNUNET_break_op (0);
6034 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6037 address_iterate = (const struct AddressIterateMessage *) message;
6039 timeout = GNUNET_TIME_absolute_ntoh (address_iterate->timeout);
6040 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
6042 GNUNET_SERVER_disable_receive_done_warning (client);
6043 tc = GNUNET_SERVER_transmit_context_create (client);
6045 neighbor_iterator = neighbours;
6046 while (neighbor_iterator != NULL)
6048 ready_iterator = neighbor_iterator->plugins;
6049 while (ready_iterator != NULL)
6051 foreign_address_iterator = ready_iterator->addresses;
6052 while (foreign_address_iterator != NULL)
6054 transport_plugin = foreign_address_iterator->ready_list->plugin;
6055 if (foreign_address_iterator->addr != NULL)
6057 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6058 GNUNET_i2s(&neighbor_iterator->id),
6059 a2s (transport_plugin->short_name,
6060 foreign_address_iterator->addr,
6061 foreign_address_iterator->addrlen),
6062 (foreign_address_iterator->connected
6063 == GNUNET_YES) ? "CONNECTED"
6065 (foreign_address_iterator->validated
6066 == GNUNET_YES) ? "VALIDATED"
6068 transmit_address_to_client (tc, addr_buf);
6069 GNUNET_free(addr_buf);
6071 else if (foreign_address_iterator->addrlen == 0)
6073 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6074 GNUNET_i2s (&neighbor_iterator->id),
6076 (foreign_address_iterator->connected
6077 == GNUNET_YES) ? "CONNECTED"
6079 (foreign_address_iterator->validated
6080 == GNUNET_YES) ? "VALIDATED"
6082 transmit_address_to_client (tc, addr_buf);
6083 GNUNET_free(addr_buf);
6086 foreign_address_iterator = foreign_address_iterator->next;
6088 ready_iterator = ready_iterator->next;
6090 neighbor_iterator = neighbor_iterator->next;
6093 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6094 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6095 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6100 * Setup the environment for this plugin.
6103 create_environment (struct TransportPlugin *plug)
6105 plug->env.cfg = cfg;
6106 plug->env.my_identity = &my_identity;
6107 plug->env.our_hello = &our_hello;
6108 plug->env.cls = plug;
6109 plug->env.receive = &plugin_env_receive;
6110 plug->env.notify_address = &plugin_env_notify_address;
6111 plug->env.session_end = &plugin_env_session_end;
6112 plug->env.max_connections = max_connect_per_transport;
6113 plug->env.stats = stats;
6118 * Start the specified transport (load the plugin).
6121 start_transport (struct GNUNET_SERVER_Handle *server,
6124 struct TransportPlugin *plug;
6127 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6128 _("Loading `%s' transport plugin\n"), name);
6129 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6130 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6131 create_environment (plug);
6132 plug->short_name = GNUNET_strdup (name);
6133 plug->lib_name = libname;
6134 plug->next = plugins;
6136 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6137 if (plug->api == NULL)
6139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6140 _("Failed to load transport plugin for `%s'\n"), name);
6141 GNUNET_free (plug->short_name);
6142 plugins = plug->next;
6143 GNUNET_free (libname);
6150 * Called whenever a client is disconnected. Frees our
6151 * resources associated with that client.
6153 * @param cls closure
6154 * @param client identification of the client
6157 client_disconnect_notification (void *cls,
6158 struct GNUNET_SERVER_Client *client)
6160 struct TransportClient *pos;
6161 struct TransportClient *prev;
6162 struct ClientMessageQueueEntry *mqe;
6163 struct Blacklisters *bl;
6164 struct BlacklistCheck *bc;
6165 struct NeighbourList *n;
6166 struct MessageQueue *mq;
6171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6172 "Client disconnected, cleaning up.\n");
6174 /* clean up blacklister */
6178 if (bl->client == client)
6183 if (bc->bl_pos == bl)
6185 bc->bl_pos = bl->next;
6188 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6191 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6192 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6198 GNUNET_CONTAINER_DLL_remove (bl_head,
6201 GNUNET_SERVER_client_drop (bl->client);
6207 /* clean up 'normal' clients */
6210 while ((pos != NULL) && (pos->client != client))
6217 while (NULL != (mqe = pos->message_queue_head))
6219 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6220 pos->message_queue_tail,
6222 pos->message_count--;
6225 for (n = neighbours; n != NULL; n = n->next)
6227 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6229 if (mq->client == pos)
6230 mq->client = NULL; /* do not use anymore! */
6234 clients = pos->next;
6236 prev->next = pos->next;
6237 if (GNUNET_YES == pos->tcs_pending)
6242 if (pos->th != NULL)
6244 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6247 GNUNET_break (0 == pos->message_count);
6253 * Function called when the service shuts down. Unloads our plugins
6254 * and cancels pending validations.
6256 * @param cls closure, unused
6257 * @param tc task context (unused)
6260 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6262 struct TransportPlugin *plug;
6263 struct TransportPlugin *tmp;
6264 struct OwnAddressList *al;
6265 struct CheckHelloValidatedContext *chvc;
6267 shutdown_in_progress = GNUNET_YES;
6268 while (neighbours != NULL)
6271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6272 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6275 disconnect_neighbour (neighbours, GNUNET_NO);
6278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6279 "Transport service is unloading plugins...\n");
6282 while (plug != NULL)
6284 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6286 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6287 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6289 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6290 GNUNET_free (plug->lib_name);
6291 GNUNET_free (plug->short_name);
6292 while (NULL != (al = plug->addresses))
6294 plug->addresses = al->next;
6301 if (my_private_key != NULL)
6302 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6303 GNUNET_free_non_null (our_hello);
6305 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6308 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6309 validation_map = NULL;
6312 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6314 GNUNET_SCHEDULER_cancel(ats_task);
6315 ats_task = GNUNET_SCHEDULER_NO_TASK;
6320 /* free 'chvc' data structure */
6321 while (NULL != (chvc = chvc_head))
6323 chvc_head = chvc->next;
6324 if (chvc->piter != NULL)
6326 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6327 GNUNET_STATISTICS_update (stats,
6328 gettext_noop ("# outstanding peerinfo iterate requests"),
6335 GNUNET_assert (chvc->ve_count == 0);
6342 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6345 if (peerinfo != NULL)
6347 GNUNET_PEERINFO_disconnect (peerinfo);
6350 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6352 GNUNET_SCHEDULER_cancel (hello_task);
6353 hello_task = GNUNET_SCHEDULER_NO_TASK;
6355 /* Can we assume those are gone by now, or do we need to clean up
6357 GNUNET_break (bl_head == NULL);
6358 GNUNET_break (bc_head == NULL);
6362 void ats_result_cb ()
6364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6365 "ATS Result callback\n");
6369 void create_ats_information ( struct ATS_peer **p,
6371 struct ATS_mechanism ** m,
6375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6376 "ATS requires clean address information\n");
6378 struct ATS_mechanism * mechanisms;
6379 struct ATS_peer *peers;
6381 int connected_addresses = 0;
6384 struct NeighbourList *next = neighbours;
6388 int found_addresses = GNUNET_NO;
6389 struct ReadyList *r_next = next->plugins;
6390 while (r_next != NULL)
6392 struct ForeignAddressList * a_next = r_next->addresses;
6393 while (a_next != NULL)
6396 found_addresses = GNUNET_YES;
6397 a_next = a_next->next;
6399 r_next = r_next->next;
6401 if (found_addresses) c_peers++;
6406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6407 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6410 if ((c_peers == 0) && (c_mechs == 0))
6419 mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6420 peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6428 int found_addresses = GNUNET_NO;
6429 struct ReadyList *r_next = next->plugins;
6430 while (r_next != NULL)
6432 struct ForeignAddressList * a_next = r_next->addresses;
6433 while (a_next != NULL)
6435 if (a_next->connected == GNUNET_YES)
6436 connected_addresses ++;
6437 if (found_addresses == GNUNET_NO)
6439 peers[c_peers].peer = next->id;
6440 peers[c_peers].m_head = NULL;
6441 peers[c_peers].m_tail = NULL;
6442 peers[c_peers].f = 1.0 / c_mechs;
6445 mechanisms[c_mechs].addr = a_next;
6446 mechanisms[c_mechs].col_index = c_mechs;
6447 mechanisms[c_mechs].peer = &peers[c_peers];
6448 mechanisms[c_mechs].next = NULL;
6449 mechanisms[c_mechs].plugin = r_next->plugin;
6450 mechanisms[c_mechs].ressources = a_next->ressources;
6451 mechanisms[c_mechs].quality = a_next->quality;
6453 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6454 peers[c_peers].m_tail,
6455 &mechanisms[c_mechs]);
6456 found_addresses = GNUNET_YES;
6459 a_next = a_next->next;
6461 r_next = r_next->next;
6463 if (found_addresses == GNUNET_YES)
6474 GNUNET_STATISTICS_set(stats,
6475 gettext_noop ("# connected addresses"),
6476 connected_addresses,
6481 schedule_ats (void *cls,
6482 const struct GNUNET_SCHEDULER_TaskContext *tc)
6484 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6488 ats_task = GNUNET_SCHEDULER_NO_TASK;
6489 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6492 if (shutdown_in_progress == GNUNET_YES)
6495 struct GNUNET_TIME_Relative delta =
6496 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6497 if (delta.rel_value < ats_minimum_interval.rel_value)
6500 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6501 "Minimum time between cycles not reached\n");
6507 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6509 ats_calculate_bandwidth_distribution (ats, stats);
6510 last_ats_execution = GNUNET_TIME_absolute_get();
6512 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6513 &schedule_ats, ats);
6516 struct ForeignAddressList * get_preferred_ats_address (
6517 struct NeighbourList *n)
6519 // TODO get ATS prefered address
6520 return find_ready_address(n);
6524 * Initiate transport service.
6526 * @param cls closure
6527 * @param server the initialized server
6528 * @param c configuration to use
6532 struct GNUNET_SERVER_Handle *server,
6533 const struct GNUNET_CONFIGURATION_Handle *c)
6535 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6536 {&handle_start, NULL,
6537 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6538 {&handle_hello, NULL,
6539 GNUNET_MESSAGE_TYPE_HELLO, 0},
6540 {&handle_send, NULL,
6541 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6542 {&handle_request_connect, NULL,
6543 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6544 {&handle_set_quota, NULL,
6545 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6546 {&handle_address_lookup, NULL,
6547 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6549 {&handle_peer_address_lookup, NULL,
6550 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6552 {&handle_address_iterate, NULL,
6553 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6555 {&handle_blacklist_init, NULL,
6556 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6557 {&handle_blacklist_reply, NULL,
6558 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6564 unsigned long long tneigh;
6567 shutdown_in_progress = GNUNET_NO;
6569 stats = GNUNET_STATISTICS_create ("transport", cfg);
6570 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6571 /* parse configuration */
6573 GNUNET_CONFIGURATION_get_value_number (c,
6578 GNUNET_CONFIGURATION_get_value_filename (c,
6580 "HOSTKEY", &keyfile)))
6582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6584 ("Transport service is lacking key configuration settings. Exiting.\n"));
6585 GNUNET_SCHEDULER_shutdown ();
6588 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6591 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6592 validation_map = NULL;
6596 max_connect_per_transport = (uint32_t) tneigh;
6597 peerinfo = GNUNET_PEERINFO_connect (cfg);
6598 if (peerinfo == NULL)
6600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6601 _("Could not access PEERINFO service. Exiting.\n"));
6602 GNUNET_SCHEDULER_shutdown ();
6605 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6608 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6609 validation_map = NULL;
6610 GNUNET_free (keyfile);
6613 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6614 GNUNET_free (keyfile);
6615 if (my_private_key == NULL)
6617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6619 ("Transport service could not access hostkey. Exiting.\n"));
6620 GNUNET_SCHEDULER_shutdown ();
6623 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6626 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6627 validation_map = NULL;
6630 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6631 GNUNET_CRYPTO_hash (&my_public_key,
6632 sizeof (my_public_key), &my_identity.hashPubKey);
6633 /* setup notification */
6634 GNUNET_SERVER_disconnect_notify (server,
6635 &client_disconnect_notification, NULL);
6636 /* load plugins... */
6639 GNUNET_CONFIGURATION_get_value_string (c,
6640 "TRANSPORT", "PLUGINS", &plugs))
6642 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6643 _("Starting transport plugins `%s'\n"), plugs);
6644 pos = strtok (plugs, " ");
6647 start_transport (server, pos);
6649 pos = strtok (NULL, " ");
6651 GNUNET_free (plugs);
6653 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6654 &shutdown_task, NULL);
6658 /* Initializing ATS */
6661 unsigned long long value;
6666 int v_b_min = 64000;
6669 ats_minimum_interval = ATS_MIN_INTERVAL;
6670 ats_regular_interval = ATS_EXEC_INTERVAL;
6672 /* loading cost ressources */
6673 for (co=0; co<available_ressources; co++)
6675 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6676 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6678 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6685 "Found ressource cost: [%s] = %llu\n",
6688 ressources[co].c_max = value;
6691 GNUNET_free (section);
6692 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6693 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6695 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6702 "Found ressource cost: [%s] = %llu\n",
6705 ressources[co].c_min = value;
6708 GNUNET_free (section);
6711 ats = ats_init (D, U, R, v_b_min, v_n_min,
6712 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6713 create_ats_information,
6716 int log_problem = GNUNET_NO;
6717 int log_solution = GNUNET_NO;
6718 int overwrite_dump = GNUNET_NO;
6719 int minimum_peers = 0;
6720 int minimum_addresses = 0;
6722 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6723 log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6724 "transport","DUMP_MLP");
6726 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6727 log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6728 "transport","DUMP_SOLUTION");
6729 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
6730 overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6731 "transport","DUMP_OVERWRITE");
6732 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
6734 GNUNET_CONFIGURATION_get_value_number(cfg,
6735 "transport","DUMP_MIN_PEERS", &value);
6736 minimum_peers = value;
6738 if (GNUNET_CONFIGURATION_have_value(cfg,
6739 "transport", "DUMP_MIN_ADDRS"))
6741 GNUNET_CONFIGURATION_get_value_number(cfg,
6742 "transport","DUMP_MIN_ADDRS", &value);
6743 minimum_addresses= value;
6745 if (GNUNET_CONFIGURATION_have_value(cfg,
6746 "transport", "DUMP_OVERWRITE"))
6748 GNUNET_CONFIGURATION_get_value_number(cfg,
6749 "transport","DUMP_OVERWRITE", &value);
6750 overwrite_dump = value;
6753 if (GNUNET_CONFIGURATION_have_value(cfg,
6754 "transport", "ATS_MIN_INTERVAL"))
6756 GNUNET_CONFIGURATION_get_value_number(cfg,
6757 "transport","ATS_MIN_INTERVAL", &value);
6758 ats_minimum_interval.rel_value = value;
6761 if (GNUNET_CONFIGURATION_have_value(cfg,
6762 "transport", "ATS_EXEC_INTERVAL"))
6764 GNUNET_CONFIGURATION_get_value_number(cfg,
6765 "transport","ATS_EXEC_INTERVAL", &value);
6766 ats_regular_interval.rel_value = value;
6768 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
6770 GNUNET_CONFIGURATION_get_value_number(cfg,
6771 "transport","ATS_MIN_INTERVAL", &value);
6772 ats_minimum_interval.rel_value = value;
6775 ats_set_logging_options (ats,
6783 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6789 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6790 _("Transport service ready.\n"));
6792 /* If we have a blacklist file, read from it */
6793 read_blacklist_file(cfg);
6794 /* process client requests */
6795 GNUNET_SERVER_add_handlers (server, handlers);
6800 * The main function for the transport service.
6802 * @param argc number of arguments from the command line
6803 * @param argv command line arguments
6804 * @return 0 ok, 1 on error
6807 main (int argc, char *const *argv)
6809 a2s (NULL, NULL, 0); /* make compiler happy */
6810 return (GNUNET_OK ==
6811 GNUNET_SERVICE_run (argc,
6814 GNUNET_SERVICE_OPTION_NONE,
6815 &run, NULL)) ? 0 : 1;
6818 /* end of gnunet-service-transport.c */