2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "gnunet-service-transport_ats.h"
41 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_INBOUND GNUNET_NO
54 * Should we do some additional checks (to validate behavior
57 #define EXTRA_CHECKS GNUNET_YES
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
71 #define MAX_PENDING (128 * 1024)
74 * Size of the per-transport blacklist hash maps.
76 #define TRANSPORT_BLACKLIST_HT_SIZE 16
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
83 #define MAX_CONNECT_RETRY 3
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
90 #define MAX_HELLO_LOAD 4
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
96 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
106 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
115 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
118 * Priority to use for PONG messages.
120 #define TRANSPORT_PONG_PRIORITY 4
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
126 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
133 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
141 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * List of addresses of other peers
146 struct ForeignAddressList
149 * This is a linked list.
151 struct ForeignAddressList *next;
154 * Which ready list does this entry belong to.
156 struct ReadyList *ready_list;
159 * How long until we auto-expire this address (unless it is
160 * re-confirmed by the transport)?
162 struct GNUNET_TIME_Absolute expires;
165 * Task used to re-validate addresses, updates latencies and
168 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176 * Session (or NULL if no valid session currently exists or if the
177 * plugin does not use sessions).
179 struct Session *session;
181 struct ATS_ressource_entry * ressources;
183 struct ATS_quality_entry * quality;
186 * What was the last latency observed for this address, plugin and peer?
188 struct GNUNET_TIME_Relative latency;
191 * If we did not successfully transmit a message to the given peer
192 * via this connection during the specified time, we should consider
193 * the connection to be dead. This is used in the case that a TCP
194 * transport simply stalls writing to the stream but does not
195 * formerly get a signal that the other peer died.
197 struct GNUNET_TIME_Absolute timeout;
200 * How often have we tried to connect using this plugin? Used to
201 * discriminate against addresses that do not work well.
202 * FIXME: not yet used, but should be!
204 unsigned int connect_attempts;
207 * DV distance to this peer (1 if no DV is used).
208 * FIXME: need to set this from transport plugins!
218 * Have we ever estimated the latency of this address? Used to
219 * ensure that the first time we add an address, we immediately
225 * Are we currently connected via this address? The first time we
226 * successfully transmit or receive data to a peer via a particular
227 * address, we set this to GNUNET_YES. If we later get an error
228 * (disconnect notification, transmission failure, timeout), we set
229 * it back to GNUNET_NO.
234 * Is this plugin currently busy transmitting to the specific target?
235 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
236 * messages do not count as 'in transmit'.
241 * Has this address been validated yet?
249 * Entry in linked list of network addresses for ourselves. Also
250 * includes a cached signature for 'struct TransportPongMessage's.
252 struct OwnAddressList
255 * This is a linked list.
257 struct OwnAddressList *next;
260 * How long until the current signature expires? (ZERO if the
261 * signature was never created).
263 struct GNUNET_TIME_Absolute pong_sig_expires;
266 * Signature for a 'struct TransportPongMessage' for this address.
268 struct GNUNET_CRYPTO_RsaSignature pong_signature;
279 * Entry in linked list of all of our plugins.
281 struct TransportPlugin
284 * This is a linked list.
286 struct TransportPlugin *next;
289 * API of the transport as returned by the plugin's
290 * initialization function.
292 struct GNUNET_TRANSPORT_PluginFunctions *api;
295 * Short name for the plugin (i.e. "tcp").
300 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
305 * List of our known addresses for this transport.
307 struct OwnAddressList *addresses;
310 * Environment this transport service is using
313 struct GNUNET_TRANSPORT_PluginEnvironment env;
316 * ID of task that is used to clean up expired addresses.
318 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
321 * Set to GNUNET_YES if we need to scrap the existing list of
322 * "addresses" and start fresh when we receive the next address
323 * update from a transport. Set to GNUNET_NO if we should just add
324 * the new address to the list and wait for the commit call.
328 struct ATS_plugin * rc;
331 * Hashmap of blacklisted peers for this particular transport.
333 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
336 struct 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;
1001 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1005 if (set == GNUNET_NO)
1007 for (c=0; c<available_ressources; c++)
1009 if (ats_index == ressources[c].atis_index)
1011 fal->ressources[c].c = value;
1014 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1023 update_addr_ats (struct ForeignAddressList *fal,
1024 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1029 for (c1=0; c1<ats_count; c1++)
1031 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1037 * Find an entry in the transport list for a particular transport.
1039 * @return NULL if not found.
1041 static struct TransportPlugin *
1042 find_transport (const char *short_name)
1044 struct TransportPlugin *head = plugins;
1045 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1051 * Is a particular peer blacklisted for a particular transport?
1053 * @param peer the peer to check for
1054 * @param plugin the plugin used to connect to the peer
1056 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1059 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1062 if (plugin->blacklist != NULL)
1064 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Peer `%s:%s' is blacklisted!\n",
1069 plugin->short_name, GNUNET_i2s (peer));
1072 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1082 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1083 char *transport_name)
1085 struct TransportPlugin *plugin;
1087 plugin = find_transport(transport_name);
1088 if (plugin == NULL) /* Nothing to do */
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 "Adding peer `%s' with plugin `%s' to blacklist\n",
1096 if (plugin->blacklist == NULL)
1097 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1098 GNUNET_assert(plugin->blacklist != NULL);
1099 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1106 * Read the blacklist file, containing transport:peer entries.
1107 * Provided the transport is loaded, set up hashmap with these
1108 * entries to blacklist peers by transport.
1112 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1119 struct GNUNET_PeerIdentity pid;
1121 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1122 unsigned int entries_found;
1123 char *transport_name;
1126 GNUNET_CONFIGURATION_get_value_filename (cfg,
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Option `%s' in section `%s' not specified!\n",
1139 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1140 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1141 | GNUNET_DISK_PERM_USER_WRITE);
1142 if (0 != STAT (fn, &frstat))
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 _("Could not read blacklist file `%s'\n"), fn);
1149 if (frstat.st_size == 0)
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 _("Blacklist file `%s' is empty.\n"),
1159 /* FIXME: use mmap */
1160 data = GNUNET_malloc_large (frstat.st_size);
1161 GNUNET_assert(data != NULL);
1162 if (frstat.st_size !=
1163 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _("Failed to read blacklist from `%s'\n"), fn);
1173 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1175 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1176 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1179 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1182 if (colon_pos >= frstat.st_size)
1184 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1185 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1186 (unsigned long long) colon_pos);
1192 if (isspace( (unsigned char) data[colon_pos]))
1194 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1195 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1196 (unsigned long long) colon_pos);
1198 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1202 tsize = colon_pos - pos;
1203 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1206 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1207 (unsigned long long) colon_pos);
1216 transport_name = GNUNET_malloc(tsize + 1);
1217 memcpy(transport_name, &data[pos], tsize);
1218 pos = colon_pos + 1;
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Read transport name %s in blacklist file.\n",
1224 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1225 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1227 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1228 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1229 (unsigned long long) pos);
1231 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1233 GNUNET_free_non_null(transport_name);
1236 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1237 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1239 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1240 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1241 (unsigned long long) pos,
1246 if (0 != memcmp (&pid,
1248 sizeof (struct GNUNET_PeerIdentity)))
1251 add_peer_to_blacklist (&pid,
1256 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1257 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1261 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1262 GNUNET_free_non_null(transport_name);
1263 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1266 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1273 * Function called to notify a client about the socket being ready to
1274 * queue more data. "buf" will be NULL and "size" zero if the socket
1275 * was closed for writing in the meantime.
1277 * @param cls closure
1278 * @param size number of bytes available in buf
1279 * @param buf where the callee should write the message
1280 * @return number of bytes written to buf
1283 transmit_to_client_callback (void *cls, size_t size, void *buf)
1285 struct TransportClient *client = cls;
1286 struct ClientMessageQueueEntry *q;
1289 const struct GNUNET_MessageHeader *msg;
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Transmission to client failed, closing connection.\n");
1299 /* fatal error with client, free message queue! */
1300 while (NULL != (q = client->message_queue_head))
1302 GNUNET_STATISTICS_update (stats,
1303 gettext_noop ("# bytes discarded (could not transmit to client)"),
1304 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1306 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1307 client->message_queue_tail,
1311 client->message_count = 0;
1316 while (NULL != (q = client->message_queue_head))
1318 msg = (const struct GNUNET_MessageHeader *) &q[1];
1319 msize = ntohs (msg->size);
1320 if (msize + tsize > size)
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "Transmitting message of type %u to client.\n",
1327 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1328 client->message_queue_tail,
1330 memcpy (&cbuf[tsize], msg, msize);
1333 client->message_count--;
1337 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1338 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1340 GNUNET_TIME_UNIT_FOREVER_REL,
1341 &transmit_to_client_callback,
1343 GNUNET_assert (client->th != NULL);
1350 * Convert an address to a string.
1352 * @param plugin name of the plugin responsible for the address
1353 * @param addr binary address
1354 * @param addr_len number of bytes in addr
1355 * @return NULL on error, otherwise address string
1358 a2s (const char *plugin,
1362 struct TransportPlugin *p;
1366 p = find_transport (plugin);
1367 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1370 return p->api->address_to_string (NULL,
1380 * Iterator to free entries in the validation_map.
1382 * @param cls closure (unused)
1383 * @param key current key code
1384 * @param value value in the hash map (validation to abort)
1385 * @return GNUNET_YES (always)
1388 abort_validation (void *cls,
1389 const GNUNET_HashCode * key,
1392 struct ValidationEntry *va = value;
1394 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1395 GNUNET_SCHEDULER_cancel (va->timeout_task);
1396 GNUNET_free (va->transport_name);
1397 if (va->chvc != NULL)
1399 va->chvc->ve_count--;
1400 if (va->chvc->ve_count == 0)
1402 GNUNET_CONTAINER_DLL_remove (chvc_head,
1405 GNUNET_free (va->chvc);
1415 * HELLO validation cleanup task (validation failed).
1417 * @param cls the 'struct ValidationEntry' that failed
1418 * @param tc scheduler context (unused)
1421 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1423 struct ValidationEntry *va = cls;
1424 struct GNUNET_PeerIdentity pid;
1426 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1427 GNUNET_STATISTICS_update (stats,
1428 gettext_noop ("# address validation timeouts"),
1431 GNUNET_CRYPTO_hash (&va->publicKey,
1433 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1435 GNUNET_break (GNUNET_OK ==
1436 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1439 abort_validation (NULL, NULL, va);
1445 * Send the specified message to the specified client. Since multiple
1446 * messages may be pending for the same client at a time, this code
1447 * makes sure that no message is lost.
1449 * @param client client to transmit the message to
1450 * @param msg the message to send
1451 * @param may_drop can this message be dropped if the
1452 * message queue for this client is getting far too large?
1455 transmit_to_client (struct TransportClient *client,
1456 const struct GNUNET_MessageHeader *msg, int may_drop)
1458 struct ClientMessageQueueEntry *q;
1461 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1463 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1465 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1468 client->message_count,
1470 GNUNET_STATISTICS_update (stats,
1471 gettext_noop ("# messages dropped due to slow client"),
1476 msize = ntohs (msg->size);
1477 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1478 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1479 memcpy (&q[1], msg, msize);
1480 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1481 client->message_queue_tail,
1483 client->message_count++;
1484 if (client->th == NULL)
1486 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1488 GNUNET_TIME_UNIT_FOREVER_REL,
1489 &transmit_to_client_callback,
1491 GNUNET_assert (client->th != NULL);
1497 * Transmit a 'SEND_OK' notification to the given client for the
1500 * @param client who to notify
1501 * @param n neighbour to notify about, can be NULL (on failure)
1502 * @param target target of the transmission
1503 * @param result status code for the transmission request
1506 transmit_send_ok (struct TransportClient *client,
1507 struct NeighbourList *n,
1508 const struct GNUNET_PeerIdentity *target,
1511 struct SendOkMessage send_ok_msg;
1513 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1514 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1515 send_ok_msg.success = htonl (result);
1517 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1519 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1520 send_ok_msg.peer = *target;
1521 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1526 * Mark the given FAL entry as 'connected' (and hence preferred for
1527 * sending); also mark all others for the same peer as 'not connected'
1528 * (since only one can be preferred).
1530 * @param fal address to set to 'connected'
1533 mark_address_connected (struct ForeignAddressList *fal);
1538 * We should re-try transmitting to the given peer,
1539 * hopefully we've learned something in the meantime.
1542 retry_transmission_task (void *cls,
1543 const struct GNUNET_SCHEDULER_TaskContext *tc)
1545 struct NeighbourList *n = cls;
1547 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1548 try_transmission_to_peer (n);
1553 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1554 * upon "completion" of a send request. This tells the API
1555 * that it is now legal to send another message to the given
1558 * @param cls closure, identifies the entry on the
1559 * message queue that was transmitted and the
1560 * client responsible for queuing the message
1561 * @param target the peer receiving the message
1562 * @param result GNUNET_OK on success, if the transmission
1563 * failed, we should not tell the client to transmit
1567 transmit_send_continuation (void *cls,
1568 const struct GNUNET_PeerIdentity *target,
1571 struct MessageQueue *mq = cls;
1572 struct NeighbourList *n;
1574 GNUNET_STATISTICS_update (stats,
1575 gettext_noop ("# bytes pending with plugins"),
1576 - (int64_t) mq->message_buf_size,
1578 if (result == GNUNET_OK)
1580 GNUNET_STATISTICS_update (stats,
1581 gettext_noop ("# bytes successfully transmitted by plugins"),
1582 mq->message_buf_size,
1587 GNUNET_STATISTICS_update (stats,
1588 gettext_noop ("# bytes with transmission failure by plugins"),
1589 mq->message_buf_size,
1592 if (mq->specific_address != NULL)
1594 if (result == GNUNET_OK)
1596 mq->specific_address->timeout =
1597 GNUNET_TIME_relative_to_absolute
1598 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1599 if (mq->specific_address->validated == GNUNET_YES)
1600 mark_address_connected (mq->specific_address);
1604 if (mq->specific_address->connected != GNUNET_NO)
1607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1609 a2s (mq->specific_address->ready_list->plugin->short_name,
1610 mq->specific_address->addr,
1611 mq->specific_address->addrlen));
1613 GNUNET_STATISTICS_update (stats,
1614 gettext_noop ("# connected addresses"),
1617 mq->specific_address->connected = GNUNET_NO;
1620 if (! mq->internal_msg)
1621 mq->specific_address->in_transmit = GNUNET_NO;
1623 n = find_neighbour (&mq->neighbour_id);
1624 if (mq->client != NULL)
1625 transmit_send_ok (mq->client, n, target, result);
1626 GNUNET_assert (n != NULL);
1627 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1631 if (result == GNUNET_OK)
1632 try_transmission_to_peer (n);
1633 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1634 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1640 * Check the ready list for the given neighbour and if a plugin is
1641 * ready for transmission (and if we have a message), do so!
1643 * @param neighbour target peer for which to transmit
1646 try_transmission_to_peer (struct NeighbourList *n)
1648 struct ReadyList *rl;
1649 struct MessageQueue *mq;
1650 struct GNUNET_TIME_Relative timeout;
1654 if (n->messages_head == NULL)
1657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1658 "Transmission queue for `%4s' is empty\n",
1659 GNUNET_i2s (&n->id));
1661 return; /* nothing to do */
1664 mq = n->messages_head;
1665 force_address = GNUNET_YES;
1666 if (mq->specific_address == NULL)
1669 mq->specific_address = get_preferred_ats_address(n);
1670 GNUNET_STATISTICS_update (stats,
1671 gettext_noop ("# transport selected peer address freely"),
1674 force_address = GNUNET_NO;
1676 if (mq->specific_address == NULL)
1678 GNUNET_STATISTICS_update (stats,
1679 gettext_noop ("# transport failed to selected peer address"),
1682 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1683 if (timeout.rel_value == 0)
1686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1687 "No destination address available to transmit message of size %u to peer `%4s'\n",
1688 mq->message_buf_size,
1689 GNUNET_i2s (&mq->neighbour_id));
1691 GNUNET_STATISTICS_update (stats,
1692 gettext_noop ("# bytes in message queue for other peers"),
1693 - (int64_t) mq->message_buf_size,
1695 GNUNET_STATISTICS_update (stats,
1696 gettext_noop ("# bytes discarded (no destination address available)"),
1697 mq->message_buf_size,
1699 if (mq->client != NULL)
1700 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1701 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1705 return; /* nobody ready */
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# message delivery deferred (no address)"),
1711 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1712 GNUNET_SCHEDULER_cancel (n->retry_task);
1713 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1714 &retry_transmission_task,
1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1719 mq->message_buf_size,
1720 GNUNET_i2s (&mq->neighbour_id),
1723 /* FIXME: might want to trigger peerinfo lookup here
1724 (unless that's already pending...) */
1727 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1730 if (mq->specific_address->connected == GNUNET_NO)
1731 mq->specific_address->connect_attempts++;
1732 rl = mq->specific_address->ready_list;
1733 mq->plugin = rl->plugin;
1734 if (!mq->internal_msg)
1735 mq->specific_address->in_transmit = GNUNET_YES;
1737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1738 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1739 mq->message_buf_size,
1740 GNUNET_i2s (&n->id),
1741 (mq->specific_address->addr != NULL)
1742 ? a2s (mq->plugin->short_name,
1743 mq->specific_address->addr,
1744 mq->specific_address->addrlen)
1746 rl->plugin->short_name);
1748 GNUNET_STATISTICS_update (stats,
1749 gettext_noop ("# bytes in message queue for other peers"),
1750 - (int64_t) mq->message_buf_size,
1752 GNUNET_STATISTICS_update (stats,
1753 gettext_noop ("# bytes pending with plugins"),
1754 mq->message_buf_size,
1757 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1761 ret = rl->plugin->api->send (rl->plugin->api->cls,
1764 mq->message_buf_size,
1766 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1767 mq->specific_address->session,
1768 mq->specific_address->addr,
1769 mq->specific_address->addrlen,
1771 &transmit_send_continuation, mq);
1774 /* failure, but 'send' would not call continuation in this case,
1775 so we need to do it here! */
1776 transmit_send_continuation (mq,
1784 * Send the specified message to the specified peer.
1786 * @param client source of the transmission request (can be NULL)
1787 * @param peer_address ForeignAddressList where we should send this message
1788 * @param priority how important is the message
1789 * @param timeout how long do we have to transmit?
1790 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1791 * @param message_buf_size total size of all messages in message_buf
1792 * @param is_internal is this an internal message; these are pre-pended and
1793 * also do not count for plugins being "ready" to transmit
1794 * @param neighbour handle to the neighbour for transmission
1797 transmit_to_peer (struct TransportClient *client,
1798 struct ForeignAddressList *peer_address,
1799 unsigned int priority,
1800 struct GNUNET_TIME_Relative timeout,
1801 const char *message_buf,
1802 size_t message_buf_size,
1803 int is_internal, struct NeighbourList *neighbour)
1805 struct MessageQueue *mq;
1810 /* check for duplicate submission */
1811 mq = neighbour->messages_head;
1814 if (mq->client == client)
1816 /* client transmitted to same peer twice
1817 before getting SEND_OK! */
1825 GNUNET_STATISTICS_update (stats,
1826 gettext_noop ("# bytes in message queue for other peers"),
1829 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1830 mq->specific_address = peer_address;
1831 mq->client = client;
1832 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1833 memcpy (&mq[1], message_buf, message_buf_size);
1834 mq->message_buf = (const char*) &mq[1];
1835 mq->message_buf_size = message_buf_size;
1836 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1837 mq->internal_msg = is_internal;
1838 mq->priority = priority;
1839 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1841 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1842 neighbour->messages_tail,
1845 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1846 neighbour->messages_tail,
1847 neighbour->messages_tail,
1849 try_transmission_to_peer (neighbour);
1854 * Send a plain PING (without address or our HELLO) to the given
1855 * foreign address to try to establish a connection (and validate
1856 * that the other peer is really who he claimed he is).
1858 * @param n neighbour to PING
1861 transmit_plain_ping (struct NeighbourList *n)
1863 struct ValidationEntry *ve;
1864 struct TransportPingMessage ping;
1865 struct ReadyList *rl;
1866 struct TransportPlugin *plugin;
1867 struct ForeignAddressList *fal;
1869 if (! n->public_key_valid)
1871 /* This should not happen since the other peer
1872 should send us a HELLO prior to sending his
1874 GNUNET_break_op (0);
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Could not transmit plain PING to `%s': public key not known\n",
1877 GNUNET_i2s (&n->id));
1880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881 "Looking for addresses to transmit plain PING to `%s'\n",
1882 GNUNET_i2s (&n->id));
1883 for (rl = n->plugins; rl != NULL; rl = rl->next)
1885 plugin = rl->plugin;
1886 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1888 if (! fal->connected)
1890 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1891 ve->transport_name = GNUNET_strdup (plugin->short_name);
1892 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1894 ve->send_time = GNUNET_TIME_absolute_get();
1895 ve->session = fal->session;
1896 memcpy(&ve->publicKey,
1898 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1899 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1900 &timeout_hello_validation,
1902 GNUNET_CONTAINER_multihashmap_put (validation_map,
1905 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1906 ping.header.size = htons(sizeof(struct TransportPingMessage));
1907 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1908 ping.challenge = htonl(ve->challenge);
1909 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1910 GNUNET_STATISTICS_update (stats,
1911 gettext_noop ("# PING without HELLO messages sent"),
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "Transmitting plain PING to `%s'\n",
1916 GNUNET_i2s (&n->id));
1917 transmit_to_peer (NULL,
1919 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1920 HELLO_VERIFICATION_TIMEOUT,
1921 (const char*) &ping, sizeof (ping),
1929 * Mark the given FAL entry as 'connected' (and hence preferred for
1930 * sending); also mark all others for the same peer as 'not connected'
1931 * (since only one can be preferred).
1933 * @param fal address to set to 'connected'
1936 mark_address_connected(struct ForeignAddressList *fal)
1938 struct ForeignAddressList *pos;
1939 struct ForeignAddressList *inbound;
1940 struct ForeignAddressList *outbound;
1943 GNUNET_assert (GNUNET_YES == fal->validated);
1944 if (fal->connected == GNUNET_YES)
1945 return; /* nothing to do */
1950 pos = fal->ready_list->addresses;
1953 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1954 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) && (0
1957 else if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1962 pos = fal->ready_list->addresses;
1965 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1966 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) && (0
1969 else if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1975 if (inbound != NULL)
1976 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1977 if (outbound != NULL)
1978 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1981 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1982 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1983 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1984 &my_identity.hashPubKey, &null_hash)))
1987 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1991 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1992 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1993 &my_identity.hashPubKey, &null_hash))))
1996 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
2001 pos = fal->ready_list->addresses;
2004 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2008 GNUNET_ERROR_TYPE_DEBUG,
2009 "Marking address `%s' as no longer connected (due to connect on other address)\n",
2010 a2s (pos->ready_list->plugin->short_name, pos->addr,
2013 GNUNET_break (cnt == GNUNET_YES);
2016 fprintf(stderr, "Peer: %s, setting %s connection to disconnected.\n", GNUNET_i2s(&my_identity), (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2018 pos->connected = GNUNET_NO;
2019 GNUNET_STATISTICS_update (stats,
2020 gettext_noop ("# connected addresses"), -1,
2026 fal->connected = GNUNET_YES;
2027 if (GNUNET_YES == cnt)
2029 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2036 * Find an address in any of the available transports for
2037 * the given neighbour that would be good for message
2038 * transmission. This is essentially the transport selection
2041 * @param neighbour for whom to select an address
2042 * @return selected address, NULL if we have none
2044 struct ForeignAddressList *
2045 find_ready_address(struct NeighbourList *neighbour)
2047 struct ReadyList *head = neighbour->plugins;
2048 struct ForeignAddressList *addresses;
2049 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2050 struct ForeignAddressList *best_address;
2052 /* Hack to prefer unix domain sockets */
2053 struct ForeignAddressList *unix_address = NULL;
2055 best_address = NULL;
2056 while (head != NULL)
2058 addresses = head->addresses;
2059 while (addresses != NULL)
2061 if ( (addresses->timeout.abs_value < now.abs_value) &&
2062 (addresses->connected == GNUNET_YES) )
2065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2066 "Marking long-time inactive connection to `%4s' as down.\n",
2067 GNUNET_i2s (&neighbour->id));
2069 GNUNET_STATISTICS_update (stats,
2070 gettext_noop ("# connected addresses"),
2073 addresses->connected = GNUNET_NO;
2075 addresses = addresses->next;
2078 addresses = head->addresses;
2079 while (addresses != NULL)
2082 if (addresses->addr != NULL)
2083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2085 a2s (head->plugin->short_name,
2087 addresses->addrlen),
2088 GNUNET_i2s (&neighbour->id),
2089 addresses->connected,
2090 addresses->in_transmit,
2091 addresses->validated,
2092 addresses->connect_attempts,
2093 (unsigned long long) addresses->timeout.abs_value,
2094 (unsigned int) addresses->distance);
2096 if (0==strcmp(head->plugin->short_name,"unix"))
2098 if ( (unix_address == NULL) ||
2099 ( (unix_address != NULL) &&
2100 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2101 unix_address = addresses;
2103 if ( ( (best_address == NULL) ||
2104 (addresses->connected == GNUNET_YES) ||
2105 (best_address->connected == GNUNET_NO) ) &&
2106 (addresses->in_transmit == GNUNET_NO) &&
2107 ( (best_address == NULL) ||
2108 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2109 best_address = addresses;
2110 /* FIXME: also give lower-latency addresses that are not
2111 connected a chance some times... */
2112 addresses = addresses->next;
2114 if (unix_address != NULL)
2118 if (unix_address != NULL)
2120 best_address = unix_address;
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2123 "Found UNIX address, forced this address\n");
2126 if (best_address != NULL)
2129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2130 "Best address found (`%s') has latency of %llu ms.\n",
2131 (best_address->addrlen > 0)
2132 ? a2s (best_address->ready_list->plugin->short_name,
2134 best_address->addrlen)
2136 best_address->latency.rel_value);
2141 GNUNET_STATISTICS_update (stats,
2142 gettext_noop ("# transmission attempts failed (no address)"),
2147 return best_address;
2154 struct GeneratorContext
2156 struct TransportPlugin *plug_pos;
2157 struct OwnAddressList *addr_pos;
2158 struct GNUNET_TIME_Absolute expiration;
2166 address_generator (void *cls, size_t max, void *buf)
2168 struct GeneratorContext *gc = cls;
2171 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2173 gc->plug_pos = gc->plug_pos->next;
2174 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2176 if (NULL == gc->plug_pos)
2181 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2184 gc->addr_pos->addrlen, buf, max);
2185 gc->addr_pos = gc->addr_pos->next;
2191 * Construct our HELLO message from all of the addresses of
2192 * all of the transports.
2195 * @param tc scheduler context
2198 refresh_hello_task (void *cls,
2199 const struct GNUNET_SCHEDULER_TaskContext *tc)
2201 struct GNUNET_HELLO_Message *hello;
2202 struct TransportClient *cpos;
2203 struct NeighbourList *npos;
2204 struct GeneratorContext gc;
2206 hello_task = GNUNET_SCHEDULER_NO_TASK;
2207 gc.plug_pos = plugins;
2208 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2209 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2210 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2213 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2215 GNUNET_STATISTICS_update (stats,
2216 gettext_noop ("# refreshed my HELLO"),
2220 while (cpos != NULL)
2222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2223 "Transmitting my HELLO to client!\n");
2224 transmit_to_client (cpos,
2225 (const struct GNUNET_MessageHeader *) hello,
2230 GNUNET_free_non_null (our_hello);
2232 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2233 for (npos = neighbours; npos != NULL; npos = npos->next)
2235 if (GNUNET_YES != npos->received_pong)
2238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2239 "Transmitting updated `%s' to neighbour `%4s'\n",
2240 "HELLO", GNUNET_i2s (&npos->id));
2242 GNUNET_STATISTICS_update (stats,
2243 gettext_noop ("# transmitted my HELLO to other peers"),
2246 transmit_to_peer (NULL, NULL, 0,
2247 HELLO_ADDRESS_EXPIRATION,
2248 (const char *) our_hello,
2249 GNUNET_HELLO_size(our_hello),
2256 * Schedule task to refresh hello (unless such a
2257 * task exists already).
2262 #if DEBUG_TRANSPORT_HELLO
2263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2264 "refresh_hello() called!\n");
2266 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2269 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2275 * Iterator over hash map entries that NULLs the session of validation
2276 * entries that match the given session.
2278 * @param cls closure (the 'struct Session*' to match against)
2279 * @param key current key code (peer ID, not used)
2280 * @param value value in the hash map ('struct ValidationEntry*')
2281 * @return GNUNET_YES (we should continue to iterate)
2284 remove_session_validations (void *cls,
2285 const GNUNET_HashCode * key,
2288 struct Session *session = cls;
2289 struct ValidationEntry *ve = value;
2291 if (session == ve->session)
2298 * We've been disconnected from the other peer (for some
2299 * connection-oriented transport). Either quickly
2300 * re-establish the connection or signal the disconnect
2303 * Only signal CORE level disconnect if ALL addresses
2304 * for the peer are exhausted.
2306 * @param p overall plugin context
2307 * @param nl neighbour that was disconnected
2310 try_fast_reconnect (struct TransportPlugin *p,
2311 struct NeighbourList *nl)
2313 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2314 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2315 "try_fast_reconnect not implemented!\n");
2316 /* Note: the idea here is to hide problems with transports (or
2317 switching between plugins) from the core to eliminate the need to
2318 re-negotiate session keys and the like; OTOH, we should tell core
2319 quickly (much faster than timeout) `if a connection was lost and
2320 could not be re-established (i.e. other peer went down or is
2321 unable / refuses to communicate);
2323 So we should consider:
2324 1) ideally: our own willingness / need to connect
2325 2) prior failures to connect to this peer (by plugin)
2326 3) ideally: reasons why other peer terminated (as far as knowable)
2328 Most importantly, it must be POSSIBLE for another peer to terminate
2329 a connection for a while (without us instantly re-establishing it).
2330 Similarly, if another peer is gone we should quickly notify CORE.
2331 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2332 on the other end), we should reconnect in such a way that BOTH CORE
2333 services never even notice.
2334 Furthermore, the same mechanism (or small variation) could be used
2335 to switch to a better-performing plugin (ATS).
2337 Finally, this needs to be tested throughly... */
2340 * GNUNET_NO in the call below makes transport disconnect the peer,
2341 * even if only a single address (out of say, six) went away. This
2342 * function must be careful to ONLY disconnect if the peer is gone,
2343 * not just a specific address.
2345 * More specifically, half the places it was used had it WRONG.
2348 /* No reconnect, signal disconnect instead! */
2351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2352 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2353 "try_fast_reconnect");
2355 GNUNET_STATISTICS_update (stats,
2356 gettext_noop ("# disconnects due to try_fast_reconnect"),
2360 disconnect_neighbour (nl, GNUNET_YES);
2366 * Function that will be called whenever the plugin internally
2367 * cleans up a session pointer and hence the service needs to
2368 * discard all of those sessions as well. Plugins that do not
2369 * use sessions can simply omit calling this function and always
2370 * use NULL wherever a session pointer is needed.
2372 * @param cls closure
2373 * @param peer which peer was the session for
2374 * @param session which session is being destoyed
2377 plugin_env_session_end (void *cls,
2378 const struct GNUNET_PeerIdentity *peer,
2379 struct Session *session)
2381 struct TransportPlugin *p = cls;
2382 struct NeighbourList *nl;
2383 struct ReadyList *rl;
2384 struct ForeignAddressList *pos;
2385 struct ForeignAddressList *prev;
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2389 "Session ended with peer `%4s', %s\n",
2391 "plugin_env_session_end");
2393 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2394 &remove_session_validations,
2396 nl = find_neighbour (peer);
2400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401 "No neighbour record found for peer `%4s'\n",
2404 return; /* was never marked as connected */
2409 if (rl->plugin == p)
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417 "Plugin was associated with peer `%4s'\n",
2420 GNUNET_STATISTICS_update (stats,
2421 gettext_noop ("# disconnects due to session end"),
2424 disconnect_neighbour (nl, GNUNET_YES);
2428 pos = rl->addresses;
2429 while ( (pos != NULL) &&
2430 (pos->session != session) )
2438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2439 "Session was never marked as ready for peer `%4s'\n",
2443 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2445 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2446 if (validations_pending ==GNUNET_YES)
2449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2450 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2455 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2456 GNUNET_STATISTICS_update (stats,
2457 gettext_noop ("# disconnects due to unready session"),
2461 disconnect_neighbour (nl, GNUNET_YES);
2462 return; /* was never marked as connected */
2464 pos->session = NULL;
2465 pos->connected = GNUNET_NO;
2466 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2468 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2469 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2472 if (pos->addrlen != 0)
2474 if (nl->received_pong != GNUNET_NO)
2476 GNUNET_STATISTICS_update (stats,
2477 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2480 if (GNUNET_YES == pos->connected)
2481 try_fast_reconnect (p, nl);
2485 GNUNET_STATISTICS_update (stats,
2486 gettext_noop ("# disconnects due to missing pong"),
2489 /* FIXME this is never true?! See: line 2416*/
2490 if (GNUNET_YES == pos->connected)
2491 disconnect_neighbour (nl, GNUNET_YES);
2496 GNUNET_STATISTICS_update (stats,
2497 gettext_noop ("# connected addresses"),
2501 /* was inbound connection, free 'pos' */
2503 rl->addresses = pos->next;
2505 prev->next = pos->next;
2506 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2508 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2509 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2511 GNUNET_free_non_null(pos->ressources);
2512 GNUNET_free_non_null(pos->quality);
2514 ats_modify_problem_state (ats, ATS_MODIFIED);
2516 if (GNUNET_YES != pos->connected)
2518 /* nothing else to do, connection was never up... */
2524 if (nl->received_pong == GNUNET_NO)
2526 GNUNET_STATISTICS_update (stats,
2527 gettext_noop ("# disconnects due to NO pong"),
2530 disconnect_neighbour (nl, GNUNET_YES);
2531 return; /* nothing to do, never connected... */
2533 /* check if we have any validated addresses left */
2534 pos = rl->addresses;
2537 if (GNUNET_YES == pos->validated)
2539 GNUNET_STATISTICS_update (stats,
2540 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2543 try_fast_reconnect (p, nl);
2548 /* no valid addresses left, signal disconnect! */
2551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2552 "Disconnecting peer `%4s', %s\n",
2554 "plugin_env_session_end");
2556 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2557 * it means there aren't any left for this PLUGIN/PEER combination! So
2558 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2559 * when it isn't necessary. Using GNUNET_YES at least checks to see
2560 * if there are any addresses that work first, so as not to overdo it.
2563 GNUNET_STATISTICS_update (stats,
2564 gettext_noop ("# disconnects due to plugin_env_session_end"),
2567 disconnect_neighbour (nl, GNUNET_YES);
2572 * Function that must be called by each plugin to notify the
2573 * transport service about the addresses under which the transport
2574 * provided by the plugin can be reached.
2576 * @param cls closure
2577 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2578 * @param addr one of the addresses of the host, NULL for the last address
2579 * the specific address format depends on the transport
2580 * @param addrlen length of the address
2583 plugin_env_notify_address (void *cls,
2588 struct TransportPlugin *p = cls;
2589 struct OwnAddressList *al;
2590 struct OwnAddressList *prev;
2592 GNUNET_assert (p->api != NULL);
2594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2595 (add_remove == GNUNET_YES)
2596 ? "Adding `%s':%s to the set of our addresses\n"
2597 : "Removing `%s':%s from the set of our addresses\n",
2602 GNUNET_assert (addr != NULL);
2603 if (GNUNET_NO == add_remove)
2609 if ( (addrlen == al->addrlen) &&
2610 (0 == memcmp (addr, &al[1], addrlen)) )
2613 p->addresses = al->next;
2615 prev->next = al->next;
2626 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2627 al->next = p->addresses;
2629 al->addrlen = addrlen;
2630 memcpy (&al[1], addr, addrlen);
2636 * Notify all of our clients about a peer connecting.
2639 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2640 struct GNUNET_TIME_Relative latency,
2643 struct ConnectInfoMessage * cim;
2644 struct TransportClient *cpos;
2648 if (0 == memcmp (peer,
2650 sizeof (struct GNUNET_PeerIdentity)))
2656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657 "Notifying clients about connection with `%s'\n",
2660 GNUNET_STATISTICS_update (stats,
2661 gettext_noop ("# peers connected"),
2666 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2667 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2668 cim = GNUNET_malloc (size);
2669 cim->header.size = htons (size);
2670 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2671 cim->ats_count = htonl(2);
2672 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2673 (&cim->ats)[0].value = htonl (distance);
2674 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2675 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2676 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2677 (&cim->ats)[2].value = htonl (0);
2678 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2680 /* notify ats about connecting peer */
2681 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2684 ats_modify_problem_state(ats, ATS_MODIFIED);
2685 ats_calculate_bandwidth_distribution (ats);
2689 while (cpos != NULL)
2691 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2699 * Notify all of our clients about a peer disconnecting.
2702 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2704 struct DisconnectInfoMessage dim;
2705 struct TransportClient *cpos;
2707 if (0 == memcmp (peer,
2709 sizeof (struct GNUNET_PeerIdentity)))
2715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2716 "Notifying clients about lost connection to `%s'\n",
2719 GNUNET_STATISTICS_update (stats,
2720 gettext_noop ("# peers connected"),
2723 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2724 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2725 dim.reserved = htonl (0);
2726 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2728 /* notify ats about connecting peer */
2729 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2732 ats_modify_problem_state(ats, ATS_MODIFIED);
2733 ats_calculate_bandwidth_distribution (ats);
2738 while (cpos != NULL)
2740 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2747 * Find a ForeignAddressList entry for the given neighbour
2748 * that matches the given address and transport.
2750 * @param neighbour which peer we care about
2751 * @param tname name of the transport plugin
2752 * @param session session to look for, NULL for 'any'; otherwise
2753 * can be used for the service to "learn" this session ID
2755 * @param addr binary address
2756 * @param addrlen length of addr
2757 * @return NULL if no such entry exists
2759 static struct ForeignAddressList *
2760 find_peer_address(struct NeighbourList *neighbour,
2762 struct Session *session,
2766 struct ReadyList *head;
2767 struct ForeignAddressList *pos;
2769 head = neighbour->plugins;
2770 while (head != NULL)
2772 if (0 == strcmp (tname, head->plugin->short_name))
2778 pos = head->addresses;
2779 while ( (pos != NULL) &&
2780 ( (pos->addrlen != addrlen) ||
2781 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2783 if ( (session != NULL) &&
2784 (pos->session == session) )
2788 if ( (session != NULL) && (pos != NULL) )
2789 pos->session = session; /* learn it! */
2795 * Get the peer address struct for the given neighbour and
2796 * address. If it doesn't yet exist, create it.
2798 * @param neighbour which peer we care about
2799 * @param tname name of the transport plugin
2800 * @param session session of the plugin, or NULL for none
2801 * @param addr binary address
2802 * @param addrlen length of addr
2803 * @return NULL if we do not have a transport plugin for 'tname'
2805 static struct ForeignAddressList *
2806 add_peer_address (struct NeighbourList *neighbour,
2808 struct Session *session,
2812 struct ReadyList *head;
2813 struct ForeignAddressList *ret;
2816 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2819 head = neighbour->plugins;
2821 while (head != NULL)
2823 if (0 == strcmp (tname, head->plugin->short_name))
2829 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2830 ret->session = session;
2831 if ((addrlen > 0) && (addr != NULL))
2833 ret->addr = (const char*) &ret[1];
2834 memcpy (&ret[1], addr, addrlen);
2841 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2842 for (c=0; c<available_ressources; c++)
2844 struct ATS_ressource_entry *r = ret->ressources;
2846 r[c].atis_index = ressources[c].atis_index;
2847 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2849 r[c].c = ressources[c].c_unix;
2851 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2853 r[c].c = ressources[c].c_udp;
2855 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2857 r[c].c = ressources[c].c_tcp;
2859 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2861 r[c].c = ressources[c].c_http;
2863 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2865 r[c].c = ressources[c].c_https;
2867 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2869 r[c].c = ressources[c].c_wlan;
2873 r[c].c = ressources[c].c_default;
2874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2875 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2876 GNUNET_i2s(&neighbour->id),
2877 neighbour->plugins->plugin->short_name);
2881 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2882 ret->addrlen = addrlen;
2883 ret->expires = GNUNET_TIME_relative_to_absolute
2884 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2885 ret->latency = GNUNET_TIME_relative_get_forever();
2887 ret->timeout = GNUNET_TIME_relative_to_absolute
2888 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2889 ret->ready_list = head;
2890 ret->next = head->addresses;
2891 head->addresses = ret;
2897 * Closure for 'add_validated_address'.
2899 struct AddValidatedAddressContext
2902 * Entry that has been validated.
2904 const struct ValidationEntry *ve;
2907 * Flag set after we have added the address so
2908 * that we terminate the iteration next time.
2915 * Callback function used to fill a buffer of max bytes with a list of
2916 * addresses in the format used by HELLOs. Should use
2917 * "GNUNET_HELLO_add_address" as a helper function.
2919 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2920 * @param max maximum number of bytes that can be written to buf
2921 * @param buf where to write the address information
2922 * @return number of bytes written, 0 to signal the
2923 * end of the iteration.
2926 add_validated_address (void *cls,
2927 size_t max, void *buf)
2929 struct AddValidatedAddressContext *avac = cls;
2930 const struct ValidationEntry *ve = avac->ve;
2932 if (GNUNET_YES == avac->done)
2934 avac->done = GNUNET_YES;
2935 return GNUNET_HELLO_add_address (ve->transport_name,
2936 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2946 * Closure for 'check_address_exists'.
2948 struct CheckAddressExistsClosure
2951 * Address to check for.
2956 * Name of the transport.
2963 struct Session *session;
2966 * Set to GNUNET_YES if the address exists.
2979 * Iterator over hash map entries. Checks if the given
2980 * validation entry is for the same address as what is given
2983 * @param cls the 'struct CheckAddressExistsClosure*'
2984 * @param key current key code (ignored)
2985 * @param value value in the hash map ('struct ValidationEntry')
2986 * @return GNUNET_YES if we should continue to
2987 * iterate (mismatch), GNUNET_NO if not (entry matched)
2990 check_address_exists (void *cls,
2991 const GNUNET_HashCode * key,
2994 struct CheckAddressExistsClosure *caec = cls;
2995 struct ValidationEntry *ve = value;
2997 if ( (0 == strcmp (caec->tname,
2998 ve->transport_name)) &&
2999 (caec->addrlen == ve->addrlen) &&
3000 (0 == memcmp (caec->addr,
3004 caec->exists = GNUNET_YES;
3007 if ( (ve->session != NULL) &&
3008 (caec->session == ve->session) )
3010 caec->exists = GNUNET_YES;
3018 neighbour_timeout_task (void *cls,
3019 const struct GNUNET_SCHEDULER_TaskContext *tc)
3021 struct NeighbourList *n = cls;
3024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3025 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3027 GNUNET_STATISTICS_update (stats,
3028 gettext_noop ("# disconnects due to timeout"),
3031 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3032 disconnect_neighbour (n, GNUNET_NO);
3037 * Schedule the job that will cause us to send a PING to the
3038 * foreign address to evaluate its validity and latency.
3040 * @param fal address to PING
3043 schedule_next_ping (struct ForeignAddressList *fal);
3047 * Add the given address to the list of foreign addresses
3048 * available for the given peer (check for duplicates).
3050 * @param cls the respective 'struct NeighbourList' to update
3051 * @param tname name of the transport
3052 * @param expiration expiration time
3053 * @param addr the address
3054 * @param addrlen length of the address
3055 * @return GNUNET_OK (always)
3058 add_to_foreign_address_list (void *cls,
3060 struct GNUNET_TIME_Absolute expiration,
3064 struct NeighbourList *n = cls;
3065 struct ForeignAddressList *fal;
3068 GNUNET_STATISTICS_update (stats,
3069 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3073 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3076 #if DEBUG_TRANSPORT_HELLO
3077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3078 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3079 a2s (tname, addr, addrlen),
3081 GNUNET_i2s (&n->id),
3082 expiration.abs_value);
3084 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3087 GNUNET_STATISTICS_update (stats,
3088 gettext_noop ("# previously validated addresses lacking transport"),
3094 fal->expires = GNUNET_TIME_absolute_max (expiration,
3096 schedule_next_ping (fal);
3102 fal->expires = GNUNET_TIME_absolute_max (expiration,
3108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3109 "Failed to add new address for `%4s'\n",
3110 GNUNET_i2s (&n->id));
3114 if (fal->validated == GNUNET_NO)
3116 fal->validated = GNUNET_YES;
3117 GNUNET_STATISTICS_update (stats,
3118 gettext_noop ("# peer addresses considered valid"),
3122 if (try == GNUNET_YES)
3125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3126 "Have new addresses, will try to trigger transmissions.\n");
3128 try_transmission_to_peer (n);
3135 * Add addresses in validated HELLO "h" to the set of addresses
3136 * we have for this peer.
3138 * @param cls closure ('struct NeighbourList*')
3139 * @param peer id of the peer, NULL for last call
3140 * @param h hello message for the peer (can be NULL)
3141 * @param err_msg NULL if successful, otherwise contains error message
3144 add_hello_for_peer (void *cls,
3145 const struct GNUNET_PeerIdentity *peer,
3146 const struct GNUNET_HELLO_Message *h,
3147 const char *err_msg)
3149 struct NeighbourList *n = cls;
3151 if (err_msg != NULL)
3154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3155 _("Error in communication with PEERINFO service: %s\n"),
3162 GNUNET_STATISTICS_update (stats,
3163 gettext_noop ("# outstanding peerinfo iterate requests"),
3170 return; /* no HELLO available */
3172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3177 if (GNUNET_YES != n->public_key_valid)
3179 GNUNET_HELLO_get_key (h, &n->publicKey);
3180 n->public_key_valid = GNUNET_YES;
3182 GNUNET_HELLO_iterate_addresses (h,
3184 &add_to_foreign_address_list,
3190 * Create a fresh entry in our neighbour list for the given peer.
3191 * Will try to transmit our current HELLO to the new neighbour.
3192 * Do not call this function directly, use 'setup_peer_check_blacklist.
3194 * @param peer the peer for which we create the entry
3195 * @param do_hello should we schedule transmitting a HELLO
3196 * @return the new neighbour list entry
3198 static struct NeighbourList *
3199 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3202 struct NeighbourList *n;
3203 struct TransportPlugin *tp;
3204 struct ReadyList *rl;
3206 GNUNET_assert (0 != memcmp (peer,
3208 sizeof (struct GNUNET_PeerIdentity)));
3210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211 "Setting up state for neighbour `%4s'\n",
3214 GNUNET_STATISTICS_update (stats,
3215 gettext_noop ("# active neighbours"),
3218 n = GNUNET_malloc (sizeof (struct NeighbourList));
3219 n->next = neighbours;
3223 GNUNET_TIME_relative_to_absolute
3224 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3225 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3226 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3227 MAX_BANDWIDTH_CARRY_S);
3231 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3233 rl = GNUNET_malloc (sizeof (struct ReadyList));
3235 rl->next = n->plugins;
3238 rl->addresses = NULL;
3242 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3244 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3245 &neighbour_timeout_task, n);
3248 GNUNET_STATISTICS_update (stats,
3249 gettext_noop ("# peerinfo new neighbor iterate requests"),
3252 GNUNET_STATISTICS_update (stats,
3253 gettext_noop ("# outstanding peerinfo iterate requests"),
3256 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3257 GNUNET_TIME_UNIT_FOREVER_REL,
3258 &add_hello_for_peer, n);
3260 GNUNET_STATISTICS_update (stats,
3261 gettext_noop ("# HELLO's sent to new neighbors"),
3264 if (NULL != our_hello)
3265 transmit_to_peer (NULL, NULL, 0,
3266 HELLO_ADDRESS_EXPIRATION,
3267 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3275 * Function called after we have checked if communicating
3276 * with a given peer is acceptable.
3278 * @param cls closure
3279 * @param n NULL if communication is not acceptable
3281 typedef void (*SetupContinuation)(void *cls,
3282 struct NeighbourList *n);
3286 * Information kept for each client registered to perform
3292 * This is a linked list.
3294 struct Blacklisters *next;
3297 * This is a linked list.
3299 struct Blacklisters *prev;
3302 * Client responsible for this entry.
3304 struct GNUNET_SERVER_Client *client;
3307 * Blacklist check that we're currently performing.
3309 struct BlacklistCheck *bc;
3315 * Head of DLL of blacklisting clients.
3317 static struct Blacklisters *bl_head;
3320 * Tail of DLL of blacklisting clients.
3322 static struct Blacklisters *bl_tail;
3326 * Context we use when performing a blacklist check.
3328 struct BlacklistCheck
3332 * This is a linked list.
3334 struct BlacklistCheck *next;
3337 * This is a linked list.
3339 struct BlacklistCheck *prev;
3342 * Peer being checked.
3344 struct GNUNET_PeerIdentity peer;
3347 * Option for setup neighbour afterwards.
3352 * Continuation to call with the result.
3354 SetupContinuation cont;
3362 * Current transmission request handle for this client, or NULL if no
3363 * request is pending.
3365 struct GNUNET_CONNECTION_TransmitHandle *th;
3368 * Our current position in the blacklisters list.
3370 struct Blacklisters *bl_pos;
3373 * Current task performing the check.
3375 GNUNET_SCHEDULER_TaskIdentifier task;
3380 * Head of DLL of active blacklisting queries.
3382 static struct BlacklistCheck *bc_head;
3385 * Tail of DLL of active blacklisting queries.
3387 static struct BlacklistCheck *bc_tail;
3391 * Perform next action in the blacklist check.
3393 * @param cls the 'struct BlacklistCheck*'
3397 do_blacklist_check (void *cls,
3398 const struct GNUNET_SCHEDULER_TaskContext *tc);
3401 * Transmit blacklist query to the client.
3403 * @param cls the 'struct BlacklistCheck'
3404 * @param size number of bytes allowed
3405 * @param buf where to copy the message
3406 * @return number of bytes copied to buf
3409 transmit_blacklist_message (void *cls,
3413 struct BlacklistCheck *bc = cls;
3414 struct Blacklisters *bl;
3415 struct BlacklistMessage bm;
3420 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3421 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3423 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3424 "Failed to send blacklist test for peer `%s' to client\n",
3425 GNUNET_i2s (&bc->peer));
3429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3430 "Sending blacklist test for peer `%s' to client\n",
3431 GNUNET_i2s (&bc->peer));
3434 bm.header.size = htons (sizeof (struct BlacklistMessage));
3435 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3436 bm.is_allowed = htonl (0);
3438 memcpy (buf, &bm, sizeof (bm));
3439 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3445 * Perform next action in the blacklist check.
3447 * @param cls the 'struct BlacklistCheck*'
3451 do_blacklist_check (void *cls,
3452 const struct GNUNET_SCHEDULER_TaskContext *tc)
3454 struct BlacklistCheck *bc = cls;
3455 struct Blacklisters *bl;
3457 bc->task = GNUNET_SCHEDULER_NO_TASK;
3462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3464 GNUNET_i2s (&bc->peer));
3466 bc->cont (bc->cont_cls,
3467 setup_new_neighbour (&bc->peer, bc->do_hello));
3474 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3475 sizeof (struct BlacklistMessage),
3476 GNUNET_TIME_UNIT_FOREVER_REL,
3477 &transmit_blacklist_message,
3484 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3485 * does not yet exist, check the blacklist. If the blacklist says creating
3486 * one is acceptable, create one and call the continuation; otherwise
3487 * call the continuation with NULL.
3489 * @param peer peer to setup or look up a struct NeighbourList for
3490 * @param do_hello should we also schedule sending our HELLO to the peer
3491 * if this is a new record
3492 * @param cont function to call with the 'struct NeigbhbourList*'
3493 * @param cont_cls closure for cont
3496 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3498 SetupContinuation cont,
3501 struct NeighbourList *n;
3502 struct BlacklistCheck *bc;
3504 n = find_neighbour(peer);
3508 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3509 "Neighbour record exists for peer `%s'\n",
3516 if (bl_head == NULL)
3519 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3521 setup_new_neighbour(peer, do_hello);
3524 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3525 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3527 bc->do_hello = do_hello;
3529 bc->cont_cls = cont_cls;
3530 bc->bl_pos = bl_head;
3531 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3537 * Function called with the result of querying a new blacklister about
3538 * it being allowed (or not) to continue to talk to an existing neighbour.
3540 * @param cls the original 'struct NeighbourList'
3541 * @param n NULL if we need to disconnect
3544 confirm_or_drop_neighbour (void *cls,
3545 struct NeighbourList *n)
3547 struct NeighbourList * orig = cls;
3552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3553 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3554 "confirm_or_drop_neighboUr");
3556 GNUNET_STATISTICS_update (stats,
3557 gettext_noop ("# disconnects due to blacklist"),
3560 disconnect_neighbour (orig, GNUNET_NO);
3566 * Handle a request to start a blacklist.
3568 * @param cls closure (always NULL)
3569 * @param client identification of the client
3570 * @param message the actual message
3573 handle_blacklist_init (void *cls,
3574 struct GNUNET_SERVER_Client *client,
3575 const struct GNUNET_MessageHeader *message)
3577 struct Blacklisters *bl;
3578 struct BlacklistCheck *bc;
3579 struct NeighbourList *n;
3584 if (bl->client == client)
3587 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3592 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3593 bl->client = client;
3594 GNUNET_SERVER_client_keep (client);
3595 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3596 /* confirm that all existing connections are OK! */
3600 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3601 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3603 bc->do_hello = GNUNET_NO;
3604 bc->cont = &confirm_or_drop_neighbour;
3607 if (n == neighbours) /* all would wait for the same client, no need to
3608 create more than just the first task right now */
3609 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3617 * Handle a request to blacklist a peer.
3619 * @param cls closure (always NULL)
3620 * @param client identification of the client
3621 * @param message the actual message
3624 handle_blacklist_reply (void *cls,
3625 struct GNUNET_SERVER_Client *client,
3626 const struct GNUNET_MessageHeader *message)
3628 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3629 struct Blacklisters *bl;
3630 struct BlacklistCheck *bc;
3633 while ( (bl != NULL) &&
3634 (bl->client != client) )
3639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3640 "Blacklist client disconnected\n");
3642 /* FIXME: other error handling here!? */
3643 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3648 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3652 "Blacklist check failed, peer not allowed\n");
3654 bc->cont (bc->cont_cls, NULL);
3655 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3662 "Blacklist check succeeded, continuing with checks\n");
3664 bc->bl_pos = bc->bl_pos->next;
3665 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3668 /* check if any other bc's are waiting for this blacklister */
3672 if ( (bc->bl_pos == bl) &&
3673 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3674 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3682 * Send periodic PING messages to a given foreign address.
3684 * @param cls our 'struct PeriodicValidationContext*'
3685 * @param tc task context
3688 send_periodic_ping (void *cls,
3689 const struct GNUNET_SCHEDULER_TaskContext *tc)
3691 struct ForeignAddressList *peer_address = cls;
3692 struct TransportPlugin *tp;
3693 struct ValidationEntry *va;
3694 struct NeighbourList *neighbour;
3695 struct TransportPingMessage ping;
3696 struct CheckAddressExistsClosure caec;
3698 uint16_t hello_size;
3702 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3703 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3705 GNUNET_assert (peer_address != NULL);
3706 tp = peer_address->ready_list->plugin;
3707 neighbour = peer_address->ready_list->neighbour;
3708 if (GNUNET_YES != neighbour->public_key_valid)
3710 /* no public key yet, try again later */
3711 schedule_next_ping (peer_address);
3714 caec.addr = peer_address->addr;
3715 caec.addrlen = peer_address->addrlen;
3716 caec.tname = tp->short_name;
3717 caec.session = peer_address->session;
3718 caec.exists = GNUNET_NO;
3720 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3721 &check_address_exists,
3723 if (caec.exists == GNUNET_YES)
3725 /* During validation attempts we will likely trigger the other
3726 peer trying to validate our address which in turn will cause
3727 it to send us its HELLO, so we expect to hit this case rather
3728 frequently. Only print something if we are very verbose. */
3729 #if DEBUG_TRANSPORT > 1
3730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3731 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3732 (peer_address->addr != NULL)
3733 ? a2s (tp->short_name,
3735 peer_address->addrlen)
3738 GNUNET_i2s (&neighbour->id));
3740 schedule_next_ping (peer_address);
3743 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3744 va->transport_name = GNUNET_strdup (tp->short_name);
3745 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3747 va->send_time = GNUNET_TIME_absolute_get();
3748 va->session = peer_address->session;
3749 if (peer_address->addr != NULL)
3751 va->addr = (const void*) &va[1];
3752 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3753 va->addrlen = peer_address->addrlen;
3755 memcpy(&va->publicKey,
3756 &neighbour->publicKey,
3757 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3759 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3760 &timeout_hello_validation,
3762 GNUNET_CONTAINER_multihashmap_put (validation_map,
3763 &neighbour->id.hashPubKey,
3765 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3767 if (peer_address->validated != GNUNET_YES)
3768 hello_size = GNUNET_HELLO_size(our_hello);
3772 tsize = sizeof(struct TransportPingMessage) + hello_size;
3774 if (peer_address->addr != NULL)
3776 slen = strlen (tp->short_name) + 1;
3777 tsize += slen + peer_address->addrlen;
3781 slen = 0; /* make gcc happy */
3783 message_buf = GNUNET_malloc(tsize);
3784 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3785 ping.challenge = htonl(va->challenge);
3786 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3787 if (peer_address->validated != GNUNET_YES)
3789 memcpy(message_buf, our_hello, hello_size);
3792 if (peer_address->addr != NULL)
3794 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3795 peer_address->addrlen +
3797 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3800 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3802 peer_address->addrlen);
3806 ping.header.size = htons(sizeof(struct TransportPingMessage));
3809 memcpy(&message_buf[hello_size],
3811 sizeof(struct TransportPingMessage));
3813 #if DEBUG_TRANSPORT_REVALIDATION
3814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3815 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3816 (peer_address->addr != NULL)
3817 ? a2s (peer_address->plugin->short_name,
3819 peer_address->addrlen)
3822 GNUNET_i2s (&neighbour->id),
3823 "HELLO", hello_size,
3826 if (peer_address->validated != GNUNET_YES)
3827 GNUNET_STATISTICS_update (stats,
3828 gettext_noop ("# PING with HELLO messages sent"),
3832 GNUNET_STATISTICS_update (stats,
3833 gettext_noop ("# PING without HELLO messages sent"),
3836 GNUNET_STATISTICS_update (stats,
3837 gettext_noop ("# PING messages sent for re-validation"),
3840 transmit_to_peer (NULL, peer_address,
3841 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3842 HELLO_VERIFICATION_TIMEOUT,
3844 GNUNET_YES, neighbour);
3845 GNUNET_free(message_buf);
3846 schedule_next_ping (peer_address);
3851 * Schedule the job that will cause us to send a PING to the
3852 * foreign address to evaluate its validity and latency.
3854 * @param fal address to PING
3857 schedule_next_ping (struct ForeignAddressList *fal)
3859 struct GNUNET_TIME_Relative delay;
3861 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3863 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3864 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3866 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3867 delay.rel_value /= 2; /* do before expiration */
3868 delay = GNUNET_TIME_relative_min (delay,
3869 LATENCY_EVALUATION_MAX_DELAY);
3870 if (GNUNET_YES != fal->estimated)
3872 delay = GNUNET_TIME_UNIT_ZERO;
3873 fal->estimated = GNUNET_YES;
3876 if (GNUNET_YES == fal->connected)
3878 delay = GNUNET_TIME_relative_min (delay,
3879 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3881 /* FIXME: also adjust delay based on how close the last
3882 observed latency is to the latency of the best alternative */
3883 /* bound how fast we can go */
3884 delay = GNUNET_TIME_relative_max (delay,
3885 GNUNET_TIME_UNIT_SECONDS);
3886 /* randomize a bit (to avoid doing all at the same time) */
3887 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3889 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3890 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3891 &send_periodic_ping,
3899 * Function that will be called if we receive some payload
3900 * from another peer.
3902 * @param message the payload
3903 * @param n peer who claimed to be the sender
3906 handle_payload_message (const struct GNUNET_MessageHeader *message,
3907 struct NeighbourList *n)
3909 struct InboundMessage *im;
3910 struct TransportClient *cpos;
3913 msize = ntohs (message->size);
3914 if (n->received_pong == GNUNET_NO)
3917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3918 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3919 ntohs (message->type),
3920 ntohs (message->size),
3921 GNUNET_i2s (&n->id));
3923 GNUNET_free_non_null (n->pre_connect_message_buffer);
3924 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3925 memcpy (n->pre_connect_message_buffer, message, msize);
3930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3931 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3932 ntohs (message->type),
3933 ntohs (message->size),
3934 GNUNET_i2s (&n->id));
3936 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3939 n->quota_violation_count++;
3941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3942 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3943 n->in_tracker.available_bytes_per_s__,
3944 n->quota_violation_count);
3946 /* Discount 32k per violation */
3947 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3952 if (n->quota_violation_count > 0)
3954 /* try to add 32k back */
3955 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3957 n->quota_violation_count--;
3960 GNUNET_STATISTICS_update (stats,
3961 gettext_noop ("# payload received from other peers"),
3964 /* transmit message to all clients */
3965 uint32_t ats_count = 2;
3966 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3967 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3970 im = GNUNET_malloc (size);
3971 im->header.size = htons (size);
3972 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3974 im->ats_count = htonl(ats_count);
3975 /* Setting ATS data */
3976 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3977 (&(im->ats))[0].value = htonl (n->distance);
3978 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3979 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3980 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3981 (&(im->ats))[ats_count].value = htonl (0);
3983 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3985 while (cpos != NULL)
3987 transmit_to_client (cpos, &im->header, GNUNET_YES);
3995 * Iterator over hash map entries. Checks if the given validation
3996 * entry is for the same challenge as what is given in the PONG.
3998 * @param cls the 'struct TransportPongMessage*'
3999 * @param key peer identity
4000 * @param value value in the hash map ('struct ValidationEntry')
4001 * @return GNUNET_YES if we should continue to
4002 * iterate (mismatch), GNUNET_NO if not (entry matched)
4005 check_pending_validation (void *cls,
4006 const GNUNET_HashCode * key,
4009 const struct TransportPongMessage *pong = cls;
4010 struct ValidationEntry *ve = value;
4011 struct AddValidatedAddressContext avac;
4012 unsigned int challenge = ntohl(pong->challenge);
4013 struct GNUNET_HELLO_Message *hello;
4014 struct GNUNET_PeerIdentity target;
4015 struct NeighbourList *n;
4016 struct ForeignAddressList *fal;
4017 struct OwnAddressList *oal;
4018 struct TransportPlugin *tp;
4019 struct GNUNET_MessageHeader *prem;
4025 ps = ntohs (pong->header.size);
4026 if (ps < sizeof (struct TransportPongMessage))
4028 GNUNET_break_op (0);
4031 addr = (const char*) &pong[1];
4032 slen = strlen (ve->transport_name) + 1;
4033 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4034 (ve->challenge != challenge) ||
4035 (addr[slen-1] != '\0') ||
4036 (0 != strcmp (addr, ve->transport_name)) ||
4037 (ntohl (pong->purpose.size)
4038 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4040 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4041 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4046 alen = ps - sizeof (struct TransportPongMessage) - slen;
4047 switch (ntohl (pong->purpose.purpose))
4049 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4050 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4051 (0 != memcmp (&addr[slen],
4055 return GNUNET_YES; /* different entry, keep trying! */
4057 if (0 != memcmp (&pong->pid,
4059 sizeof (struct GNUNET_PeerIdentity)))
4061 GNUNET_break_op (0);
4065 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4070 GNUNET_break_op (0);
4075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4076 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4078 a2s (ve->transport_name,
4079 (const struct sockaddr *) ve->addr,
4081 ve->transport_name);
4084 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4085 if (0 != memcmp (&pong->pid,
4087 sizeof (struct GNUNET_PeerIdentity)))
4091 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4094 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4095 GNUNET_i2s (&my_identity),
4101 if (ve->addrlen != 0)
4103 /* must have been for a different validation entry */
4106 tp = find_transport (ve->transport_name);
4112 oal = tp->addresses;
4115 if ( (oal->addrlen == alen) &&
4116 (0 == memcmp (&oal[1],
4124 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4125 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4126 GNUNET_i2s (&pong->pid),
4127 a2s (ve->transport_name,
4130 /* FIXME: since the sender of the PONG currently uses the
4131 wrong address (see FIMXE there!), we cannot run a
4132 proper check here... */
4138 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4143 GNUNET_break_op (0);
4148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4149 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4151 a2s (ve->transport_name,
4154 ve->transport_name);
4158 GNUNET_break_op (0);
4161 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4164 _("Received expired signature. Check system time.\n"));
4167 GNUNET_STATISTICS_update (stats,
4168 gettext_noop ("# address validation successes"),
4171 /* create the updated HELLO */
4172 GNUNET_CRYPTO_hash (&ve->publicKey,
4173 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4174 &target.hashPubKey);
4175 if (ve->addr != NULL)
4177 avac.done = GNUNET_NO;
4179 hello = GNUNET_HELLO_create (&ve->publicKey,
4180 &add_validated_address,
4182 GNUNET_PEERINFO_add_peer (peerinfo,
4184 GNUNET_free (hello);
4186 n = find_neighbour (&target);
4189 n->publicKey = ve->publicKey;
4190 n->public_key_valid = GNUNET_YES;
4191 fal = add_peer_address (n,
4196 GNUNET_assert (fal != NULL);
4197 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4198 fal->validated = GNUNET_YES;
4199 mark_address_connected (fal);
4200 GNUNET_STATISTICS_update (stats,
4201 gettext_noop ("# peer addresses considered valid"),
4204 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4205 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4207 schedule_next_ping (fal);
4208 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4209 n->latency = fal->latency;
4211 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4213 n->distance = fal->distance;
4214 if (GNUNET_NO == n->received_pong)
4216 n->received_pong = GNUNET_YES;
4217 notify_clients_connect (&target, n->latency, n->distance);
4218 if (NULL != (prem = n->pre_connect_message_buffer))
4220 n->pre_connect_message_buffer = NULL;
4221 handle_payload_message (prem, n);
4225 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4227 GNUNET_SCHEDULER_cancel (n->retry_task);
4228 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4229 try_transmission_to_peer (n);
4233 /* clean up validation entry */
4234 GNUNET_assert (GNUNET_YES ==
4235 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4238 abort_validation (NULL, NULL, ve);
4244 * Function that will be called if we receive a validation
4245 * of an address challenge that we transmitted to another
4246 * peer. Note that the validation should only be considered
4247 * acceptable if the challenge matches AND if the sender
4248 * address is at least a plausible address for this peer
4249 * (otherwise we may be seeing a MiM attack).
4251 * @param cls closure
4252 * @param message the pong message
4253 * @param peer who responded to our challenge
4254 * @param sender_address string describing our sender address (as observed
4255 * by the other peer in binary format)
4256 * @param sender_address_len number of bytes in 'sender_address'
4259 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4260 const struct GNUNET_PeerIdentity *peer,
4261 const char *sender_address,
4262 size_t sender_address_len)
4264 if (0 == memcmp (peer,
4266 sizeof (struct GNUNET_PeerIdentity)))
4268 /* PONG send to self, ignore */
4269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4270 "Receiving `%s' message from myself\n",
4274 #if DEBUG_TRANSPORT > 1
4275 /* we get tons of these that just get discarded, only log
4276 if we are quite verbose */
4277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4278 "Receiving `%s' message from `%4s'.\n", "PONG",
4281 GNUNET_STATISTICS_update (stats,
4282 gettext_noop ("# PONG messages received"),
4285 if (GNUNET_SYSERR !=
4286 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4288 &check_pending_validation,
4291 /* This is *expected* to happen a lot since we send
4292 PONGs to *all* known addresses of the sender of
4293 the PING, so most likely we get multiple PONGs
4294 per PING, and all but the first PONG will end up
4295 here. So really we should not print anything here
4296 unless we want to be very, very verbose... */
4297 #if DEBUG_TRANSPORT > 2
4298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4299 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4311 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4313 * @param cls the 'struct ValidationEntry*'
4314 * @param neighbour neighbour to validate, NULL if validation failed
4317 transmit_hello_and_ping (void *cls,
4318 struct NeighbourList *neighbour)
4320 struct ValidationEntry *va = cls;
4321 struct ForeignAddressList *peer_address;
4322 struct TransportPingMessage ping;
4323 uint16_t hello_size;
4326 struct GNUNET_PeerIdentity id;
4329 GNUNET_CRYPTO_hash (&va->publicKey,
4330 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4332 if (neighbour == NULL)
4334 /* FIXME: stats... */
4335 GNUNET_break (GNUNET_OK ==
4336 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4339 abort_validation (NULL, NULL, va);
4342 neighbour->publicKey = va->publicKey;
4343 neighbour->public_key_valid = GNUNET_YES;
4344 peer_address = add_peer_address (neighbour,
4345 va->transport_name, NULL,
4346 (const void*) &va[1],
4348 if (peer_address == NULL)
4350 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4351 "Failed to add peer `%4s' for plugin `%s'\n",
4352 GNUNET_i2s (&neighbour->id),
4353 va->transport_name);
4354 GNUNET_break (GNUNET_OK ==
4355 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4358 abort_validation (NULL, NULL, va);
4361 if (NULL == our_hello)
4362 refresh_hello_task (NULL, NULL);
4363 hello_size = GNUNET_HELLO_size(our_hello);
4364 slen = strlen(va->transport_name) + 1;
4365 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4366 message_buf = GNUNET_malloc(tsize);
4367 ping.challenge = htonl(va->challenge);
4368 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4369 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4370 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4371 memcpy(message_buf, our_hello, hello_size);
4372 memcpy(&message_buf[hello_size],
4374 sizeof(struct TransportPingMessage));
4375 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4378 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4383 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4386 : a2s (va->transport_name,
4387 (const void*) &va[1], va->addrlen),
4389 GNUNET_i2s (&neighbour->id),
4390 "HELLO", hello_size,
4391 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4394 GNUNET_STATISTICS_update (stats,
4395 gettext_noop ("# PING messages sent for initial validation"),
4398 transmit_to_peer (NULL, peer_address,
4399 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4400 HELLO_VERIFICATION_TIMEOUT,
4402 GNUNET_YES, neighbour);
4403 GNUNET_free(message_buf);
4408 * Check if the given address is already being validated; if not,
4409 * append the given address to the list of entries that are being be
4410 * validated and initiate validation.
4412 * @param cls closure ('struct CheckHelloValidatedContext *')
4413 * @param tname name of the transport
4414 * @param expiration expiration time
4415 * @param addr the address
4416 * @param addrlen length of the address
4417 * @return GNUNET_OK (always)
4420 run_validation (void *cls,
4422 struct GNUNET_TIME_Absolute expiration,
4426 struct CheckHelloValidatedContext *chvc = cls;
4427 struct GNUNET_PeerIdentity id;
4428 struct TransportPlugin *tp;
4429 struct ValidationEntry *va;
4430 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4431 struct CheckAddressExistsClosure caec;
4432 struct OwnAddressList *oal;
4434 GNUNET_assert (addr != NULL);
4436 GNUNET_STATISTICS_update (stats,
4437 gettext_noop ("# peer addresses scheduled for validation"),
4440 tp = find_transport (tname);
4443 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4444 GNUNET_ERROR_TYPE_BULK,
4446 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4448 GNUNET_STATISTICS_update (stats,
4449 gettext_noop ("# peer addresses not validated (plugin not available)"),
4454 /* check if this is one of our own addresses */
4455 oal = tp->addresses;
4458 if ( (oal->addrlen == addrlen) &&
4459 (0 == memcmp (&oal[1],
4463 /* not plausible, this address is equivalent to our own address! */
4464 GNUNET_STATISTICS_update (stats,
4465 gettext_noop ("# peer addresses not validated (loopback)"),
4472 GNUNET_HELLO_get_key (chvc->hello, &pk);
4473 GNUNET_CRYPTO_hash (&pk,
4475 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4478 if (is_blacklisted(&id, tp))
4481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4482 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4490 caec.addrlen = addrlen;
4491 caec.session = NULL;
4493 caec.exists = GNUNET_NO;
4494 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4495 &check_address_exists,
4497 if (caec.exists == GNUNET_YES)
4499 /* During validation attempts we will likely trigger the other
4500 peer trying to validate our address which in turn will cause
4501 it to send us its HELLO, so we expect to hit this case rather
4502 frequently. Only print something if we are very verbose. */
4503 #if DEBUG_TRANSPORT > 1
4504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4505 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4506 a2s (tname, addr, addrlen),
4510 GNUNET_STATISTICS_update (stats,
4511 gettext_noop ("# peer addresses not validated (in progress)"),
4516 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4519 va->transport_name = GNUNET_strdup (tname);
4520 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4522 va->send_time = GNUNET_TIME_absolute_get();
4523 va->addr = (const void*) &va[1];
4524 memcpy (&va[1], addr, addrlen);
4525 va->addrlen = addrlen;
4526 GNUNET_HELLO_get_key (chvc->hello,
4528 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4529 &timeout_hello_validation,
4531 GNUNET_CONTAINER_multihashmap_put (validation_map,
4534 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4535 setup_peer_check_blacklist (&id, GNUNET_NO,
4536 &transmit_hello_and_ping,
4543 * Check if addresses in validated hello "h" overlap with
4544 * those in "chvc->hello" and validate the rest.
4546 * @param cls closure
4547 * @param peer id of the peer, NULL for last call
4548 * @param h hello message for the peer (can be NULL)
4549 * @param err_msg NULL if successful, otherwise contains error message
4552 check_hello_validated (void *cls,
4553 const struct GNUNET_PeerIdentity *peer,
4554 const struct GNUNET_HELLO_Message *h,
4555 const char *err_msg)
4557 struct CheckHelloValidatedContext *chvc = cls;
4558 struct GNUNET_HELLO_Message *plain_hello;
4559 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4560 struct GNUNET_PeerIdentity target;
4561 struct NeighbourList *n;
4563 if (err_msg != NULL)
4566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4567 _("Error in communication with PEERINFO service: %s\n"),
4575 GNUNET_STATISTICS_update (stats,
4576 gettext_noop ("# outstanding peerinfo iterate requests"),
4580 if (GNUNET_NO == chvc->hello_known)
4582 /* notify PEERINFO about the peer now, so that we at least
4583 have the public key if some other component needs it */
4584 GNUNET_HELLO_get_key (chvc->hello, &pk);
4585 GNUNET_CRYPTO_hash (&pk,
4586 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4587 &target.hashPubKey);
4588 plain_hello = GNUNET_HELLO_create (&pk,
4591 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4592 GNUNET_free (plain_hello);
4593 #if DEBUG_TRANSPORT_HELLO
4594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4595 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4597 GNUNET_i2s (&target));
4599 GNUNET_STATISTICS_update (stats,
4600 gettext_noop ("# new HELLOs requiring full validation"),
4603 GNUNET_HELLO_iterate_addresses (chvc->hello,
4610 GNUNET_STATISTICS_update (stats,
4611 gettext_noop ("# duplicate HELLO (peer known)"),
4616 if (chvc->ve_count == 0)
4618 GNUNET_CONTAINER_DLL_remove (chvc_head,
4627 #if DEBUG_TRANSPORT_HELLO
4628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4629 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4633 chvc->hello_known = GNUNET_YES;
4634 n = find_neighbour (peer);
4637 #if DEBUG_TRANSPORT_HELLO
4638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4639 "Calling hello_iterate_addresses for %s!\n",
4642 GNUNET_HELLO_iterate_addresses (h,
4644 &add_to_foreign_address_list,
4646 try_transmission_to_peer (n);
4650 #if DEBUG_TRANSPORT_HELLO
4651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4652 "No existing neighbor record for %s!\n",
4655 GNUNET_STATISTICS_update (stats,
4656 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4660 GNUNET_STATISTICS_update (stats,
4661 gettext_noop ("# HELLO validations (update case)"),
4664 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4666 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4673 * Process HELLO-message.
4675 * @param plugin transport involved, may be NULL
4676 * @param message the actual message
4677 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4680 process_hello (struct TransportPlugin *plugin,
4681 const struct GNUNET_MessageHeader *message)
4684 struct GNUNET_PeerIdentity target;
4685 const struct GNUNET_HELLO_Message *hello;
4686 struct CheckHelloValidatedContext *chvc;
4687 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4688 struct NeighbourList *n;
4689 #if DEBUG_TRANSPORT_HELLO > 2
4693 hsize = ntohs (message->size);
4694 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4695 (hsize < sizeof (struct GNUNET_MessageHeader)))
4698 return GNUNET_SYSERR;
4700 GNUNET_STATISTICS_update (stats,
4701 gettext_noop ("# HELLOs received for validation"),
4705 hello = (const struct GNUNET_HELLO_Message *) message;
4706 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4708 #if DEBUG_TRANSPORT_HELLO
4709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4710 "Unable to get public key from `%s' for `%4s'!\n",
4712 GNUNET_i2s (&target));
4714 GNUNET_break_op (0);
4715 return GNUNET_SYSERR;
4717 GNUNET_CRYPTO_hash (&publicKey,
4718 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4719 &target.hashPubKey);
4721 #if DEBUG_TRANSPORT_HELLO
4722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4723 "Received `%s' message for `%4s'\n",
4725 GNUNET_i2s (&target));
4727 if (0 == memcmp (&my_identity,
4729 sizeof (struct GNUNET_PeerIdentity)))
4731 GNUNET_STATISTICS_update (stats,
4732 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4737 n = find_neighbour (&target);
4739 (! n->public_key_valid) )
4741 GNUNET_HELLO_get_key (hello, &n->publicKey);
4742 n->public_key_valid = GNUNET_YES;
4745 /* check if load is too high before doing expensive stuff */
4746 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4748 GNUNET_STATISTICS_update (stats,
4749 gettext_noop ("# HELLOs ignored due to high load"),
4752 #if DEBUG_TRANSPORT_HELLO
4753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4754 "Ignoring `%s' for `%4s', load too high.\n",
4756 GNUNET_i2s (&target));
4763 while (NULL != chvc)
4765 if (GNUNET_HELLO_equals (hello,
4767 GNUNET_TIME_absolute_get ()).abs_value > 0)
4769 #if DEBUG_TRANSPORT_HELLO > 2
4770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4771 "Received duplicate `%s' message for `%4s'; ignored\n",
4773 GNUNET_i2s (&target));
4775 return GNUNET_OK; /* validation already pending */
4777 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4778 GNUNET_break (0 != memcmp (hello, chvc->hello,
4779 GNUNET_HELLO_size(hello)));
4784 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4785 if ((NULL != temp_neighbor))
4787 fprintf(stderr, "Already know peer, ignoring hello\n");
4792 #if DEBUG_TRANSPORT_HELLO > 2
4795 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4798 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4801 GNUNET_i2s (&target),
4803 GNUNET_HELLO_size(hello));
4808 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4810 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4811 memcpy (&chvc[1], hello, hsize);
4812 GNUNET_CONTAINER_DLL_insert (chvc_head,
4815 /* finally, check if HELLO was previously validated
4816 (continuation will then schedule actual validation) */
4817 GNUNET_STATISTICS_update (stats,
4818 gettext_noop ("# peerinfo process hello iterate requests"),
4821 GNUNET_STATISTICS_update (stats,
4822 gettext_noop ("# outstanding peerinfo iterate requests"),
4825 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4827 HELLO_VERIFICATION_TIMEOUT,
4828 &check_hello_validated, chvc);
4834 * The peer specified by the given neighbour has timed-out or a plugin
4835 * has disconnected. We may either need to do nothing (other plugins
4836 * still up), or trigger a full disconnect and clean up. This
4837 * function updates our state and does the necessary notifications.
4838 * Also notifies our clients that the neighbour is now officially
4841 * @param n the neighbour list entry for the peer
4842 * @param check GNUNET_YES to check if ALL addresses for this peer
4843 * are gone, GNUNET_NO to force a disconnect of the peer
4844 * regardless of whether other addresses exist.
4847 disconnect_neighbour (struct NeighbourList *n, int check)
4849 struct ReadyList *rpos;
4850 struct NeighbourList *npos;
4851 struct NeighbourList *nprev;
4852 struct MessageQueue *mq;
4853 struct ForeignAddressList *peer_addresses;
4854 struct ForeignAddressList *peer_pos;
4856 if (GNUNET_YES == n->in_disconnect)
4858 if (GNUNET_YES == check)
4861 while (NULL != rpos)
4863 peer_addresses = rpos->addresses;
4864 while (peer_addresses != NULL)
4866 /* Do not disconnect if: an address is connected or an inbound address exists */
4867 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4871 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4872 GNUNET_i2s (&n->id),
4873 a2s (peer_addresses->ready_list->plugin->short_name,
4874 peer_addresses->addr,
4875 peer_addresses->addrlen));
4877 return; /* still connected */
4879 peer_addresses = peer_addresses->next;
4885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4886 "Disconnecting from `%4s'\n",
4887 GNUNET_i2s (&n->id));
4889 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4891 /* notify all clients about disconnect */
4892 if (GNUNET_YES == n->received_pong)
4894 n->received_pong = GNUNET_NO;
4895 notify_clients_disconnect (&n->id);
4898 ats_modify_problem_state(ats, ATS_MODIFIED);
4900 /* clean up all plugins, cancel connections and pending transmissions */
4901 while (NULL != (rpos = n->plugins))
4903 n->plugins = rpos->next;
4904 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4905 while (rpos->addresses != NULL)
4907 peer_pos = rpos->addresses;
4908 rpos->addresses = peer_pos->next;
4909 if (peer_pos->connected == GNUNET_YES)
4910 GNUNET_STATISTICS_update (stats,
4911 gettext_noop ("# connected addresses"),
4914 if (GNUNET_YES == peer_pos->validated)
4915 GNUNET_STATISTICS_update (stats,
4916 gettext_noop ("# peer addresses considered valid"),
4919 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4921 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4922 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4924 GNUNET_free(peer_pos->ressources);
4925 peer_pos->ressources = NULL;
4926 GNUNET_free(peer_pos->quality);
4927 peer_pos->ressources = NULL;
4928 GNUNET_free(peer_pos);
4933 /* free all messages on the queue */
4934 while (NULL != (mq = n->messages_head))
4936 GNUNET_STATISTICS_update (stats,
4937 gettext_noop ("# bytes in message queue for other peers"),
4938 - (int64_t) mq->message_buf_size,
4940 GNUNET_STATISTICS_update (stats,
4941 gettext_noop ("# bytes discarded due to disconnect"),
4942 mq->message_buf_size,
4944 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4947 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4949 sizeof(struct GNUNET_PeerIdentity)));
4953 while (NULL != (mq = n->cont_head))
4956 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4959 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4961 sizeof(struct GNUNET_PeerIdentity)));
4965 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4967 GNUNET_SCHEDULER_cancel (n->timeout_task);
4968 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4970 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4972 GNUNET_SCHEDULER_cancel (n->retry_task);
4973 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4975 if (n->piter != NULL)
4977 GNUNET_PEERINFO_iterate_cancel (n->piter);
4978 GNUNET_STATISTICS_update (stats,
4979 gettext_noop ("# outstanding peerinfo iterate requests"),
4985 /* remove n from neighbours list */
4988 while ((npos != NULL) && (npos != n))
4993 GNUNET_assert (npos != NULL);
4995 neighbours = n->next;
4997 nprev->next = n->next;
4999 /* finally, free n itself */
5000 GNUNET_STATISTICS_update (stats,
5001 gettext_noop ("# active neighbours"),
5004 GNUNET_free_non_null (n->pre_connect_message_buffer);
5010 * We have received a PING message from someone. Need to send a PONG message
5011 * in response to the peer by any means necessary.
5014 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5015 const struct GNUNET_PeerIdentity *peer,
5016 struct Session *session,
5017 const char *sender_address,
5018 uint16_t sender_address_len)
5020 struct TransportPlugin *plugin = cls;
5021 struct SessionHeader *session_header = (struct SessionHeader*) session;
5022 struct TransportPingMessage *ping;
5023 struct TransportPongMessage *pong;
5024 struct NeighbourList *n;
5025 struct ReadyList *rl;
5026 struct ForeignAddressList *fal;
5027 struct OwnAddressList *oal;
5033 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5035 GNUNET_break_op (0);
5036 return GNUNET_SYSERR;
5039 ping = (struct TransportPingMessage *) message;
5040 if (0 != memcmp (&ping->target,
5041 plugin->env.my_identity,
5042 sizeof (struct GNUNET_PeerIdentity)))
5045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5046 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5048 (sender_address != NULL)
5049 ? a2s (plugin->short_name,
5050 (const struct sockaddr *)sender_address,
5053 GNUNET_i2s (&ping->target));
5055 return GNUNET_SYSERR;
5058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5059 "Processing `%s' from `%s'\n",
5061 (sender_address != NULL)
5062 ? a2s (plugin->short_name,
5063 (const struct sockaddr *)sender_address,
5067 GNUNET_STATISTICS_update (stats,
5068 gettext_noop ("# PING messages received"),
5071 addr = (const char*) &ping[1];
5072 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5073 slen = strlen (plugin->short_name) + 1;
5076 /* peer wants to confirm that we have an outbound connection to him */
5077 if (session == NULL)
5079 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5080 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5082 return GNUNET_SYSERR;
5084 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5085 1) it is NULL when we need to have a real value
5086 2) it is documented to be the address of the sender (source-IP), where
5087 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5091 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5092 a2s (plugin->short_name,
5094 sender_address_len),
5097 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5098 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5099 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5100 pong->purpose.size =
5101 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5103 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5104 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5105 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5106 pong->challenge = ping->challenge;
5107 pong->addrlen = htonl(sender_address_len + slen);
5110 sizeof(struct GNUNET_PeerIdentity));
5114 if ((sender_address!=NULL) && (sender_address_len > 0))
5115 memcpy (&((char*)&pong[1])[slen],
5117 sender_address_len);
5118 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5120 /* create / update cached sig */
5122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5123 "Creating PONG signature to indicate active connection.\n");
5125 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5126 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5127 GNUNET_assert (GNUNET_OK ==
5128 GNUNET_CRYPTO_rsa_sign (my_private_key,
5130 &session_header->pong_signature));
5134 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5136 memcpy (&pong->signature,
5137 &session_header->pong_signature,
5138 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5144 /* peer wants to confirm that this is one of our addresses */
5148 plugin->api->check_address (plugin->api->cls,
5152 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5153 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5154 a2s (plugin->short_name,
5159 oal = plugin->addresses;
5162 if ( (oal->addrlen == alen) &&
5169 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5170 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5171 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5172 pong->purpose.size =
5173 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5175 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5176 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5177 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5178 pong->challenge = ping->challenge;
5179 pong->addrlen = htonl(alen + slen);
5182 sizeof(struct GNUNET_PeerIdentity));
5183 memcpy (&pong[1], plugin->short_name, slen);
5184 memcpy (&((char*)&pong[1])[slen], addr, alen);
5185 if ( (oal != NULL) &&
5186 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5188 /* create / update cached sig */
5190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5191 "Creating PONG signature to indicate ownership.\n");
5193 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5194 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5195 GNUNET_assert (GNUNET_OK ==
5196 GNUNET_CRYPTO_rsa_sign (my_private_key,
5198 &oal->pong_signature));
5199 memcpy (&pong->signature,
5200 &oal->pong_signature,
5201 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5203 else if (oal == NULL)
5205 /* not using cache (typically DV-only) */
5206 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5207 GNUNET_assert (GNUNET_OK ==
5208 GNUNET_CRYPTO_rsa_sign (my_private_key,
5214 /* can used cached version */
5215 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5216 memcpy (&pong->signature,
5217 &oal->pong_signature,
5218 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5221 n = find_neighbour(peer);
5222 GNUNET_assert (n != NULL);
5223 did_pong = GNUNET_NO;
5224 /* first try reliable response transmission */
5228 fal = rl->addresses;
5231 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5234 ntohs (pong->header.size),
5235 TRANSPORT_PONG_PRIORITY,
5236 HELLO_VERIFICATION_TIMEOUT,
5243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5244 "Transmitted PONG to `%s' via reliable mechanism\n",
5247 GNUNET_STATISTICS_update (stats,
5248 gettext_noop ("# PONGs unicast via reliable transport"),
5254 did_pong = GNUNET_YES;
5259 /* no reliable method found, do multicast */
5260 GNUNET_STATISTICS_update (stats,
5261 gettext_noop ("# PONGs multicast to all available addresses"),
5267 fal = rl->addresses;
5270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5271 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5273 a2s (rl->plugin->short_name,
5276 rl->plugin->short_name);
5277 transmit_to_peer(NULL, fal,
5278 TRANSPORT_PONG_PRIORITY,
5279 HELLO_VERIFICATION_TIMEOUT,
5281 ntohs(pong->header.size),
5284 did_pong = GNUNET_YES;
5290 if (GNUNET_YES != did_pong)
5291 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5292 _("Could not send PONG to `%s': no address available\n"),
5299 * Function called by the plugin for each received message. Update
5300 * data volumes, possibly notify plugins about reducing the rate at
5301 * which they read from the socket and generally forward to our
5304 * @param cls the "struct TransportPlugin *" we gave to the plugin
5305 * @param peer (claimed) identity of the other peer
5306 * @param message the message, NULL if we only care about
5307 * learning about the delay until we should receive again
5308 * @param ats_data information for automatic transport selection
5309 * @param ats_count number of elements in ats not including 0-terminator
5310 * @param session identifier used for this session (can be NULL)
5311 * @param sender_address binary address of the sender (if observed)
5312 * @param sender_address_len number of bytes in sender_address
5313 * @return how long in ms the plugin should wait until receiving more data
5314 * (plugins that do not support this, can ignore the return value)
5316 static struct GNUNET_TIME_Relative
5317 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5318 const struct GNUNET_MessageHeader *message,
5319 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5321 struct Session *session,
5322 const char *sender_address,
5323 uint16_t sender_address_len)
5325 struct TransportPlugin *plugin = cls;
5326 struct ReadyList *service_context;
5327 struct ForeignAddressList *peer_address;
5329 struct NeighbourList *n;
5330 struct GNUNET_TIME_Relative ret;
5334 if (0 == memcmp (peer,
5336 sizeof (struct GNUNET_PeerIdentity)))
5338 /* refuse to receive from myself */
5340 return GNUNET_TIME_UNIT_FOREVER_REL;
5342 if (is_blacklisted (peer, plugin))
5343 return GNUNET_TIME_UNIT_FOREVER_REL;
5344 n = find_neighbour (peer);
5346 n = setup_new_neighbour (peer, GNUNET_YES);
5347 service_context = n->plugins;
5348 while ((service_context != NULL) && (plugin != service_context->plugin))
5349 service_context = service_context->next;
5350 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5351 peer_address = NULL;
5354 for (c=0; c<ats_count; c++)
5355 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5356 distance = ntohl(ats_data[c].value);
5359 if (message != NULL)
5361 if ( (session != NULL) ||
5362 (sender_address != NULL) )
5363 peer_address = add_peer_address (n,
5367 sender_address_len);
5368 if (peer_address != NULL)
5370 update_addr_ats(peer_address, ats_data, ats_count);
5371 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5373 peer_address->distance = distance;
5374 if (GNUNET_YES == peer_address->validated)
5376 mark_address_connected (peer_address);
5377 schedule_next_ping (peer_address);
5382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5383 "New address is unvalidated, trying to validate it now\n");
5385 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5387 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5388 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5390 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5393 peer_address->timeout
5394 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5396 /* update traffic received amount ... */
5397 msize = ntohs (message->size);
5399 GNUNET_STATISTICS_update (stats,
5400 gettext_noop ("# bytes received from other peers"),
5403 n->distance = distance;
5405 GNUNET_TIME_relative_to_absolute
5406 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5407 GNUNET_SCHEDULER_cancel (n->timeout_task);
5409 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5410 &neighbour_timeout_task, n);
5411 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5413 /* dropping message due to frequent inbound volume violations! */
5414 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5415 GNUNET_ERROR_TYPE_BULK,
5417 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5418 n->in_tracker.available_bytes_per_s__,
5419 n->quota_violation_count);
5420 GNUNET_STATISTICS_update (stats,
5421 gettext_noop ("# bandwidth quota violations by other peers"),
5424 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5426 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5427 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5430 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5431 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5432 /* Force ressource and quality update */
5433 if ((value == 4) && (ats != NULL))
5434 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5435 /* Force cost update */
5436 if ((value == 3) && (ats != NULL))
5437 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5438 /* Force quality update */
5439 if ((value == 2) && (ats != NULL))
5440 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5441 /* Force full rebuild */
5442 if ((value == 1) && (ats != NULL))
5443 ats_modify_problem_state(ats, ATS_MODIFIED);
5448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5449 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5450 ntohs (message->type),
5451 ntohs (message->size),
5454 switch (ntohs (message->type))
5456 case GNUNET_MESSAGE_TYPE_HELLO:
5457 GNUNET_STATISTICS_update (stats,
5458 gettext_noop ("# HELLO messages received from other peers"),
5461 process_hello (plugin, message);
5463 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5464 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5465 if (GNUNET_YES != n->received_pong)
5466 transmit_plain_ping (n);
5468 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5469 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5471 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5474 handle_payload_message (message, n);
5478 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5479 if (ret.rel_value > 0)
5482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5483 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5484 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5485 (unsigned int) n->in_tracker.available_bytes_per_s__,
5486 (unsigned long long) ret.rel_value);
5488 GNUNET_STATISTICS_update (stats,
5489 gettext_noop ("# ms throttling suggested"),
5490 (int64_t) ret.rel_value,
5497 * Handle START-message. This is the first message sent to us
5498 * by any client which causes us to add it to our list.
5500 * @param cls closure (always NULL)
5501 * @param client identification of the client
5502 * @param message the actual message
5505 handle_start (void *cls,
5506 struct GNUNET_SERVER_Client *client,
5507 const struct GNUNET_MessageHeader *message)
5509 const struct StartMessage *start;
5510 struct TransportClient *c;
5511 struct ConnectInfoMessage * cim;
5512 struct NeighbourList *n;
5516 start = (const struct StartMessage*) message;
5518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5519 "Received `%s' request from client\n", "START");
5524 if (c->client == client)
5526 /* client already on our list! */
5528 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5533 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5534 (0 != memcmp (&start->self,
5536 sizeof (struct GNUNET_PeerIdentity))) )
5538 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5539 _("Rejecting control connection from peer `%s', which is not me!\n"),
5540 GNUNET_i2s (&start->self));
5541 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5544 c = GNUNET_malloc (sizeof (struct TransportClient));
5548 if (our_hello != NULL)
5551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5552 "Sending our own `%s' to new client\n", "HELLO");
5554 transmit_to_client (c,
5555 (const struct GNUNET_MessageHeader *) our_hello,
5557 /* tell new client about all existing connections */
5559 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5560 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5564 cim = GNUNET_malloc (size);
5565 cim->header.size = htons (size);
5566 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5567 cim->ats_count = htonl(ats_count);
5568 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5569 (&(cim->ats))[2].value = htonl (0);
5573 if (GNUNET_YES == n->received_pong)
5575 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5576 (&cim->ats)[0].value = htonl (n->distance);
5577 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5578 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5580 transmit_to_client (c, &cim->header, GNUNET_NO);
5588 #if DEBUG_TRANSPORT_HELLO
5589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5590 "No HELLO created yet, will transmit HELLO to client later!\n");
5594 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5599 * Handle HELLO-message.
5601 * @param cls closure (always NULL)
5602 * @param client identification of the client
5603 * @param message the actual message
5606 handle_hello (void *cls,
5607 struct GNUNET_SERVER_Client *client,
5608 const struct GNUNET_MessageHeader *message)
5612 GNUNET_STATISTICS_update (stats,
5613 gettext_noop ("# HELLOs received from clients"),
5616 ret = process_hello (NULL, message);
5617 GNUNET_SERVER_receive_done (client, ret);
5622 * Closure for 'transmit_client_message'; followed by
5623 * 'msize' bytes of the actual message.
5625 struct TransmitClientMessageContext
5628 * Client on whom's behalf we are sending.
5630 struct GNUNET_SERVER_Client *client;
5633 * Timeout for the transmission.
5635 struct GNUNET_TIME_Absolute timeout;
5643 * Size of the message in bytes.
5650 * Schedule transmission of a message we got from a client to a peer.
5652 * @param cls the 'struct TransmitClientMessageContext*'
5653 * @param n destination, or NULL on error (in that case, drop the message)
5656 transmit_client_message (void *cls,
5657 struct NeighbourList *n)
5659 struct TransmitClientMessageContext *tcmc = cls;
5660 struct TransportClient *tc;
5663 while ((tc != NULL) && (tc->client != tcmc->client))
5668 transmit_to_peer (tc, NULL, tcmc->priority,
5669 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5671 tcmc->msize, GNUNET_NO, n);
5673 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5674 GNUNET_SERVER_client_drop (tcmc->client);
5680 * Handle SEND-message.
5682 * @param cls closure (always NULL)
5683 * @param client identification of the client
5684 * @param message the actual message
5687 handle_send (void *cls,
5688 struct GNUNET_SERVER_Client *client,
5689 const struct GNUNET_MessageHeader *message)
5691 const struct OutboundMessage *obm;
5692 const struct GNUNET_MessageHeader *obmm;
5693 struct TransmitClientMessageContext *tcmc;
5697 size = ntohs (message->size);
5699 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5702 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5705 GNUNET_STATISTICS_update (stats,
5706 gettext_noop ("# payload received for other peers"),
5709 obm = (const struct OutboundMessage *) message;
5710 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5711 msize = size - sizeof (struct OutboundMessage);
5713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5714 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5715 "SEND", GNUNET_i2s (&obm->peer),
5719 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5720 tcmc->client = client;
5721 tcmc->priority = ntohl (obm->priority);
5722 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5723 tcmc->msize = msize;
5724 /* FIXME: this memcpy can be up to 7% of our total runtime */
5725 memcpy (&tcmc[1], obmm, msize);
5726 GNUNET_SERVER_client_keep (client);
5727 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5728 &transmit_client_message,
5734 * Handle request connect message
5736 * @param cls closure (always NULL)
5737 * @param client identification of the client
5738 * @param message the actual message
5741 handle_request_connect (void *cls,
5742 struct GNUNET_SERVER_Client *client,
5743 const struct GNUNET_MessageHeader *message)
5745 const struct TransportRequestConnectMessage *trcm =
5746 (const struct TransportRequestConnectMessage *) message;
5748 GNUNET_STATISTICS_update (stats,
5749 gettext_noop ("# REQUEST CONNECT messages received"),
5753 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5754 "Received a request connect message for peer `%s'\n",
5755 GNUNET_i2s(&trcm->peer));
5757 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5759 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5764 * Handle SET_QUOTA-message.
5766 * @param cls closure (always NULL)
5767 * @param client identification of the client
5768 * @param message the actual message
5771 handle_set_quota (void *cls,
5772 struct GNUNET_SERVER_Client *client,
5773 const struct GNUNET_MessageHeader *message)
5775 const struct QuotaSetMessage *qsm =
5776 (const struct QuotaSetMessage *) message;
5777 struct NeighbourList *n;
5779 GNUNET_STATISTICS_update (stats,
5780 gettext_noop ("# SET QUOTA messages received"),
5783 n = find_neighbour (&qsm->peer);
5786 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5787 GNUNET_STATISTICS_update (stats,
5788 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5795 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5797 (unsigned int) ntohl (qsm->quota.value__),
5798 (unsigned int) n->in_tracker.available_bytes_per_s__,
5799 GNUNET_i2s (&qsm->peer));
5801 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5803 if (0 == ntohl (qsm->quota.value__))
5806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5807 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5810 GNUNET_STATISTICS_update (stats,
5811 gettext_noop ("# disconnects due to quota of 0"),
5814 disconnect_neighbour (n, GNUNET_NO);
5816 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5821 * Take the given address and append it to the set of results sent back to
5824 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5825 * @param address the resolved name, NULL to indicate the last response
5828 transmit_address_to_client (void *cls, const char *address)
5830 struct GNUNET_SERVER_TransmitContext *tc = cls;
5833 if (NULL != address)
5835 slen = strlen (address) + 1;
5836 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5837 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5841 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5847 * Handle AddressLookup-message.
5849 * @param cls closure (always NULL)
5850 * @param client identification of the client
5851 * @param message the actual message
5854 handle_address_lookup (void *cls,
5855 struct GNUNET_SERVER_Client *client,
5856 const struct GNUNET_MessageHeader *message)
5858 const struct AddressLookupMessage *alum;
5859 struct TransportPlugin *lsPlugin;
5860 const char *nameTransport;
5861 const char *address;
5863 struct GNUNET_SERVER_TransmitContext *tc;
5864 struct GNUNET_TIME_Absolute timeout;
5865 struct GNUNET_TIME_Relative rtimeout;
5868 size = ntohs (message->size);
5869 if (size < sizeof (struct AddressLookupMessage))
5871 GNUNET_break_op (0);
5872 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5875 alum = (const struct AddressLookupMessage *) message;
5876 uint32_t addressLen = ntohl (alum->addrlen);
5877 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5879 GNUNET_break_op (0);
5880 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5883 address = (const char *) &alum[1];
5884 nameTransport = (const char *) &address[addressLen];
5886 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5888 GNUNET_break_op (0);
5889 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5892 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5893 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5894 numeric = ntohl (alum->numeric_only);
5895 lsPlugin = find_transport (nameTransport);
5896 if (NULL == lsPlugin)
5898 tc = GNUNET_SERVER_transmit_context_create (client);
5899 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5900 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5901 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5904 GNUNET_SERVER_disable_receive_done_warning (client);
5905 tc = GNUNET_SERVER_transmit_context_create (client);
5906 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5908 address, addressLen,
5911 &transmit_address_to_client, tc);
5915 * Handle PeerAddressLookupMessage.
5917 * @param cls closure (always NULL)
5918 * @param client identification of the client
5919 * @param message the actual message
5922 handle_peer_address_lookup (void *cls,
5923 struct GNUNET_SERVER_Client *client,
5924 const struct GNUNET_MessageHeader *message)
5926 const struct PeerAddressLookupMessage *peer_address_lookup;
5927 struct NeighbourList *neighbor_iterator;
5928 struct ReadyList *ready_iterator;
5929 struct ForeignAddressList *foreign_address_iterator;
5930 struct TransportPlugin *transport_plugin;
5933 struct GNUNET_SERVER_TransmitContext *tc;
5934 struct GNUNET_TIME_Absolute timeout;
5935 struct GNUNET_TIME_Relative rtimeout;
5938 size = ntohs (message->size);
5939 if (size < sizeof (struct PeerAddressLookupMessage))
5941 GNUNET_break_op (0);
5942 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5945 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5947 timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5948 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5950 neighbor_iterator = neighbours;
5951 while (neighbor_iterator != NULL)
5953 if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5955 neighbor_iterator = neighbor_iterator->next;
5958 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5959 if (neighbor_iterator == NULL)
5962 tc = GNUNET_SERVER_transmit_context_create (client);
5963 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5964 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5965 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5969 ready_iterator = neighbor_iterator->plugins;
5970 GNUNET_SERVER_disable_receive_done_warning (client);
5971 tc = GNUNET_SERVER_transmit_context_create (client);
5972 while(ready_iterator != NULL)
5974 foreign_address_iterator = ready_iterator->addresses;
5975 while (foreign_address_iterator != NULL)
5977 transport_plugin = foreign_address_iterator->ready_list->plugin;
5978 if (foreign_address_iterator->addr != NULL)
5980 GNUNET_asprintf (&addr_buf, "%s --- %s",
5981 a2s (transport_plugin->short_name,
5982 foreign_address_iterator->addr,
5983 foreign_address_iterator->addrlen),
5984 (foreign_address_iterator->connected
5985 == GNUNET_YES) ? "CONNECTED"
5987 (foreign_address_iterator->validated
5988 == GNUNET_YES) ? "VALIDATED"
5990 transmit_address_to_client(tc, addr_buf);
5991 GNUNET_free(addr_buf);
5993 else if (foreign_address_iterator->addrlen == 0)
5995 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5996 (foreign_address_iterator->connected
5997 == GNUNET_YES) ? "CONNECTED"
5999 (foreign_address_iterator->validated
6000 == GNUNET_YES) ? "VALIDATED"
6002 transmit_address_to_client (tc, addr_buf);
6003 GNUNET_free(addr_buf);
6006 foreign_address_iterator = foreign_address_iterator->next;
6008 ready_iterator = ready_iterator->next;
6010 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6011 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6012 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6016 * Handle AddressIterateMessage
6018 * @param cls closure (always NULL)
6019 * @param client identification of the client
6020 * @param message the actual message
6023 handle_address_iterate (void *cls,
6024 struct GNUNET_SERVER_Client *client,
6025 const struct GNUNET_MessageHeader *message)
6027 struct NeighbourList *neighbor_iterator;
6028 struct ReadyList *ready_iterator;
6029 struct ForeignAddressList *foreign_address_iterator;
6030 struct TransportPlugin *transport_plugin;
6033 struct GNUNET_SERVER_TransmitContext *tc;
6036 size = ntohs (message->size);
6037 if (size < sizeof (struct AddressIterateMessage))
6039 GNUNET_break_op (0);
6040 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6043 GNUNET_SERVER_disable_receive_done_warning (client);
6044 tc = GNUNET_SERVER_transmit_context_create (client);
6046 neighbor_iterator = neighbours;
6047 while (neighbor_iterator != NULL)
6049 ready_iterator = neighbor_iterator->plugins;
6050 while (ready_iterator != NULL)
6052 foreign_address_iterator = ready_iterator->addresses;
6053 while (foreign_address_iterator != NULL)
6055 transport_plugin = foreign_address_iterator->ready_list->plugin;
6056 if (foreign_address_iterator->addr != NULL)
6058 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6059 GNUNET_i2s(&neighbor_iterator->id),
6060 a2s (transport_plugin->short_name,
6061 foreign_address_iterator->addr,
6062 foreign_address_iterator->addrlen),
6063 (foreign_address_iterator->connected
6064 == GNUNET_YES) ? "CONNECTED"
6066 (foreign_address_iterator->validated
6067 == GNUNET_YES) ? "VALIDATED"
6069 transmit_address_to_client (tc, addr_buf);
6070 GNUNET_free(addr_buf);
6072 else if (foreign_address_iterator->addrlen == 0)
6074 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6075 GNUNET_i2s (&neighbor_iterator->id),
6077 (foreign_address_iterator->connected
6078 == GNUNET_YES) ? "CONNECTED"
6080 (foreign_address_iterator->validated
6081 == GNUNET_YES) ? "VALIDATED"
6083 transmit_address_to_client (tc, addr_buf);
6084 GNUNET_free(addr_buf);
6087 foreign_address_iterator = foreign_address_iterator->next;
6089 ready_iterator = ready_iterator->next;
6091 neighbor_iterator = neighbor_iterator->next;
6094 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6095 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6096 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6101 * Setup the environment for this plugin.
6104 create_environment (struct TransportPlugin *plug)
6106 plug->env.cfg = cfg;
6107 plug->env.my_identity = &my_identity;
6108 plug->env.our_hello = &our_hello;
6109 plug->env.cls = plug;
6110 plug->env.receive = &plugin_env_receive;
6111 plug->env.notify_address = &plugin_env_notify_address;
6112 plug->env.session_end = &plugin_env_session_end;
6113 plug->env.max_connections = max_connect_per_transport;
6114 plug->env.stats = stats;
6119 * Start the specified transport (load the plugin).
6122 start_transport (struct GNUNET_SERVER_Handle *server,
6125 struct TransportPlugin *plug;
6128 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6129 _("Loading `%s' transport plugin\n"), name);
6130 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6131 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6132 create_environment (plug);
6133 plug->short_name = GNUNET_strdup (name);
6134 plug->lib_name = libname;
6135 plug->next = plugins;
6137 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6138 if (plug->api == NULL)
6140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6141 _("Failed to load transport plugin for `%s'\n"), name);
6142 GNUNET_free (plug->short_name);
6143 plugins = plug->next;
6144 GNUNET_free (libname);
6151 * Called whenever a client is disconnected. Frees our
6152 * resources associated with that client.
6154 * @param cls closure
6155 * @param client identification of the client
6158 client_disconnect_notification (void *cls,
6159 struct GNUNET_SERVER_Client *client)
6161 struct TransportClient *pos;
6162 struct TransportClient *prev;
6163 struct ClientMessageQueueEntry *mqe;
6164 struct Blacklisters *bl;
6165 struct BlacklistCheck *bc;
6166 struct NeighbourList *n;
6167 struct MessageQueue *mq;
6172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6173 "Client disconnected, cleaning up.\n");
6175 /* clean up blacklister */
6179 if (bl->client == client)
6184 if (bc->bl_pos == bl)
6186 bc->bl_pos = bl->next;
6189 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6192 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6193 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6199 GNUNET_CONTAINER_DLL_remove (bl_head,
6202 GNUNET_SERVER_client_drop (bl->client);
6208 /* clean up 'normal' clients */
6211 while ((pos != NULL) && (pos->client != client))
6218 while (NULL != (mqe = pos->message_queue_head))
6220 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6221 pos->message_queue_tail,
6223 pos->message_count--;
6226 for (n = neighbours; n != NULL; n = n->next)
6228 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6230 if (mq->client == pos)
6231 mq->client = NULL; /* do not use anymore! */
6235 clients = pos->next;
6237 prev->next = pos->next;
6238 if (GNUNET_YES == pos->tcs_pending)
6243 if (pos->th != NULL)
6245 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6248 GNUNET_break (0 == pos->message_count);
6254 * Function called when the service shuts down. Unloads our plugins
6255 * and cancels pending validations.
6257 * @param cls closure, unused
6258 * @param tc task context (unused)
6261 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6263 struct TransportPlugin *plug;
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");
6281 while (NULL != (plug = plugins))
6283 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6285 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6286 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6288 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6289 GNUNET_free (plug->lib_name);
6290 GNUNET_free (plug->short_name);
6291 while (NULL != (al = plug->addresses))
6293 plug->addresses = al->next;
6296 plugins = plug->next;
6299 if (my_private_key != NULL)
6300 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6301 GNUNET_free_non_null (our_hello);
6303 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6306 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6307 validation_map = NULL;
6310 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6312 GNUNET_SCHEDULER_cancel(ats_task);
6313 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");
6370 create_ats_information ( struct ATS_peer **p,
6372 struct ATS_mechanism ** m,
6376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6377 "ATS requires clean address information\n");
6379 struct ATS_mechanism * mechanisms;
6380 struct ATS_peer *peers;
6382 int connected_addresses = 0;
6385 struct NeighbourList *next = neighbours;
6389 int found_addresses = GNUNET_NO;
6390 struct ReadyList *r_next = next->plugins;
6391 while (r_next != NULL)
6393 struct ForeignAddressList * a_next = r_next->addresses;
6394 while (a_next != NULL)
6397 found_addresses = GNUNET_YES;
6398 a_next = a_next->next;
6400 r_next = r_next->next;
6402 if (found_addresses) c_peers++;
6407 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6408 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6411 if ((c_peers == 0) && (c_mechs == 0))
6420 mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6421 peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6429 int found_addresses = GNUNET_NO;
6430 struct ReadyList *r_next = next->plugins;
6431 while (r_next != NULL)
6433 struct ForeignAddressList * a_next = r_next->addresses;
6434 while (a_next != NULL)
6436 if (a_next->connected == GNUNET_YES)
6437 connected_addresses ++;
6438 if (found_addresses == GNUNET_NO)
6440 peers[c_peers].peer = next->id;
6441 peers[c_peers].m_head = NULL;
6442 peers[c_peers].m_tail = NULL;
6443 peers[c_peers].f = 1.0 / c_mechs;
6446 mechanisms[c_mechs].addr = a_next;
6447 mechanisms[c_mechs].col_index = c_mechs;
6448 mechanisms[c_mechs].peer = &peers[c_peers];
6449 mechanisms[c_mechs].next = NULL;
6450 mechanisms[c_mechs].plugin = r_next->plugin;
6451 mechanisms[c_mechs].ressources = a_next->ressources;
6452 mechanisms[c_mechs].quality = a_next->quality;
6454 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6455 peers[c_peers].m_tail,
6456 &mechanisms[c_mechs]);
6457 found_addresses = GNUNET_YES;
6460 a_next = a_next->next;
6462 r_next = r_next->next;
6464 if (found_addresses == GNUNET_YES)
6475 GNUNET_STATISTICS_set(stats,
6476 gettext_noop ("# connected addresses"),
6477 connected_addresses,
6482 schedule_ats (void *cls,
6483 const struct GNUNET_SCHEDULER_TaskContext *tc)
6485 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6489 ats_task = GNUNET_SCHEDULER_NO_TASK;
6490 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6493 if (shutdown_in_progress == GNUNET_YES)
6496 struct GNUNET_TIME_Relative delta =
6497 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6498 if (delta.rel_value < ats_minimum_interval.rel_value)
6501 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6502 "Minimum time between cycles not reached\n");
6508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6511 ats_calculate_bandwidth_distribution (ats);
6513 last_ats_execution = GNUNET_TIME_absolute_get();
6515 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6516 &schedule_ats, ats);
6519 struct ForeignAddressList * get_preferred_ats_address (
6520 struct NeighbourList *n)
6522 // TODO get ATS prefered address
6523 return find_ready_address(n);
6527 * Initiate transport service.
6529 * @param cls closure
6530 * @param server the initialized server
6531 * @param c configuration to use
6535 struct GNUNET_SERVER_Handle *server,
6536 const struct GNUNET_CONFIGURATION_Handle *c)
6538 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6539 {&handle_start, NULL,
6540 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6541 {&handle_hello, NULL,
6542 GNUNET_MESSAGE_TYPE_HELLO, 0},
6543 {&handle_send, NULL,
6544 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6545 {&handle_request_connect, NULL,
6546 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6547 {&handle_set_quota, NULL,
6548 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6549 {&handle_address_lookup, NULL,
6550 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6552 {&handle_peer_address_lookup, NULL,
6553 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6555 {&handle_address_iterate, NULL,
6556 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6558 {&handle_blacklist_init, NULL,
6559 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6560 {&handle_blacklist_reply, NULL,
6561 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6567 unsigned long long tneigh;
6570 shutdown_in_progress = GNUNET_NO;
6572 stats = GNUNET_STATISTICS_create ("transport", cfg);
6573 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6574 /* parse configuration */
6576 GNUNET_CONFIGURATION_get_value_number (c,
6581 GNUNET_CONFIGURATION_get_value_filename (c,
6583 "HOSTKEY", &keyfile)))
6585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6587 ("Transport service is lacking key configuration settings. Exiting.\n"));
6588 GNUNET_SCHEDULER_shutdown ();
6591 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6594 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6595 validation_map = NULL;
6599 max_connect_per_transport = (uint32_t) tneigh;
6600 peerinfo = GNUNET_PEERINFO_connect (cfg);
6601 if (peerinfo == NULL)
6603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6604 _("Could not access PEERINFO service. Exiting.\n"));
6605 GNUNET_SCHEDULER_shutdown ();
6608 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6611 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6612 validation_map = NULL;
6613 GNUNET_free (keyfile);
6616 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6617 GNUNET_free (keyfile);
6618 if (my_private_key == NULL)
6620 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6622 ("Transport service could not access hostkey. Exiting.\n"));
6623 GNUNET_SCHEDULER_shutdown ();
6626 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6629 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6630 validation_map = NULL;
6633 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6634 GNUNET_CRYPTO_hash (&my_public_key,
6635 sizeof (my_public_key), &my_identity.hashPubKey);
6636 /* setup notification */
6637 GNUNET_SERVER_disconnect_notify (server,
6638 &client_disconnect_notification, NULL);
6639 /* load plugins... */
6642 GNUNET_CONFIGURATION_get_value_string (c,
6643 "TRANSPORT", "PLUGINS", &plugs))
6645 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6646 _("Starting transport plugins `%s'\n"), plugs);
6647 pos = strtok (plugs, " ");
6650 start_transport (server, pos);
6652 pos = strtok (NULL, " ");
6654 GNUNET_free (plugs);
6656 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6657 &shutdown_task, NULL);
6661 /* Initializing ATS */
6664 unsigned long long value;
6669 int v_b_min = 64000;
6673 ats_minimum_interval = ATS_MIN_INTERVAL;
6674 ats_regular_interval = ATS_EXEC_INTERVAL;
6676 /* loading cost ressources */
6677 for (co=0; co<available_ressources; co++)
6679 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6680 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6682 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6688 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6689 "Found ressource cost: [%s] = %llu\n",
6692 ressources[co].c_max = value;
6695 GNUNET_free (section);
6696 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6697 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6699 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6705 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6706 "Found ressource cost: [%s] = %llu\n",
6709 ressources[co].c_min = value;
6712 GNUNET_free (section);
6715 ats = ats_init (D, U, R, v_b_min, v_n_min,
6716 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6717 create_ats_information,
6721 int log_problem = GNUNET_NO;
6722 int log_solution = GNUNET_NO;
6723 int overwrite_dump = GNUNET_NO;
6724 int minimum_peers = 0;
6725 int minimum_addresses = 0;
6727 log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6730 log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6733 overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6737 GNUNET_CONFIGURATION_get_value_number(cfg,
6741 minimum_peers = (int) value;
6743 GNUNET_CONFIGURATION_get_value_number(cfg,
6747 minimum_addresses = (int) value;
6748 GNUNET_break (GNUNET_OK ==
6749 GNUNET_CONFIGURATION_get_value_time (cfg,
6751 "ATS_EXEC_INTERVAL",
6752 &ats_regular_interval));
6753 GNUNET_break (GNUNET_OK ==
6754 GNUNET_CONFIGURATION_get_value_time (cfg,
6757 &ats_minimum_interval));
6759 ats_set_logging_options (ats,
6768 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6774 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6775 _("Transport service ready.\n"));
6777 /* If we have a blacklist file, read from it */
6778 read_blacklist_file(cfg);
6779 /* process client requests */
6780 GNUNET_SERVER_add_handlers (server, handlers);
6785 * The main function for the transport service.
6787 * @param argc number of arguments from the command line
6788 * @param argv command line arguments
6789 * @return 0 ok, 1 on error
6792 main (int argc, char *const *argv)
6794 a2s (NULL, NULL, 0); /* make compiler happy */
6795 return (GNUNET_OK ==
6796 GNUNET_SERVICE_run (argc,
6799 GNUNET_SERVICE_OPTION_NONE,
6800 &run, NULL)) ? 0 : 1;
6803 /* end of gnunet-service-transport.c */