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_YES)
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;
1942 GNUNET_assert (GNUNET_YES == fal->validated);
1943 if (fal->connected == GNUNET_YES)
1944 return; /* nothing to do */
1948 pos = fal->ready_list->addresses;
1951 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1952 if ( (GNUNET_YES == pos->connected) &&
1953 (0 == pos->addrlen) &&
1954 (0 == fal->addrlen) )
1956 if ( (0 == pos->addrlen) &&
1957 (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) &&
1967 (0 < pos->addrlen) &&
1968 (0 < fal->addrlen) )
1970 if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
1976 if (inbound != NULL)
1977 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1978 if (outbound != NULL)
1979 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1982 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1983 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1984 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1985 &my_identity.hashPubKey, &null_hash)))
1988 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1992 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1993 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1994 &my_identity.hashPubKey, &null_hash))))
1997 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
2002 pos = fal->ready_list->addresses;
2005 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2008 GNUNET_log (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,
2015 "Peer: %s, setting %s connection to disconnected.\n",
2016 GNUNET_i2s(&my_identity),
2017 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2019 pos->connected = GNUNET_NO;
2020 GNUNET_STATISTICS_update (stats,
2021 gettext_noop ("# connected addresses"), -1,
2026 GNUNET_assert (GNUNET_NO == fal->connected);
2027 fal->connected = GNUNET_YES;
2028 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2034 * Find an address in any of the available transports for
2035 * the given neighbour that would be good for message
2036 * transmission. This is essentially the transport selection
2039 * @param neighbour for whom to select an address
2040 * @return selected address, NULL if we have none
2042 struct ForeignAddressList *
2043 find_ready_address(struct NeighbourList *neighbour)
2045 struct ReadyList *head = neighbour->plugins;
2046 struct ForeignAddressList *addresses;
2047 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2048 struct ForeignAddressList *best_address;
2050 /* Hack to prefer unix domain sockets */
2051 struct ForeignAddressList *unix_address = NULL;
2053 best_address = NULL;
2054 while (head != NULL)
2056 addresses = head->addresses;
2057 while (addresses != NULL)
2059 if ( (addresses->timeout.abs_value < now.abs_value) &&
2060 (addresses->connected == GNUNET_YES) )
2063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2064 "Marking long-time inactive connection to `%4s' as down.\n",
2065 GNUNET_i2s (&neighbour->id));
2067 GNUNET_STATISTICS_update (stats,
2068 gettext_noop ("# connected addresses"),
2071 addresses->connected = GNUNET_NO;
2073 addresses = addresses->next;
2076 addresses = head->addresses;
2077 while (addresses != NULL)
2080 if (addresses->addr != NULL)
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2083 a2s (head->plugin->short_name,
2085 addresses->addrlen),
2086 GNUNET_i2s (&neighbour->id),
2087 addresses->connected,
2088 addresses->in_transmit,
2089 addresses->validated,
2090 addresses->connect_attempts,
2091 (unsigned long long) addresses->timeout.abs_value,
2092 (unsigned int) addresses->distance);
2094 if (0==strcmp(head->plugin->short_name,"unix"))
2096 if ( (unix_address == NULL) ||
2097 ( (unix_address != NULL) &&
2098 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2099 unix_address = addresses;
2101 if ( ( (best_address == NULL) ||
2102 (addresses->connected == GNUNET_YES) ||
2103 (best_address->connected == GNUNET_NO) ) &&
2104 (addresses->in_transmit == GNUNET_NO) &&
2105 ( (best_address == NULL) ||
2106 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2107 best_address = addresses;
2108 /* FIXME: also give lower-latency addresses that are not
2109 connected a chance some times... */
2110 addresses = addresses->next;
2112 if (unix_address != NULL)
2116 if (unix_address != NULL)
2118 best_address = unix_address;
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Found UNIX address, forced this address\n");
2124 if (best_address != NULL)
2127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2128 "Best address found (`%s') has latency of %llu ms.\n",
2129 (best_address->addrlen > 0)
2130 ? a2s (best_address->ready_list->plugin->short_name,
2132 best_address->addrlen)
2134 best_address->latency.rel_value);
2139 GNUNET_STATISTICS_update (stats,
2140 gettext_noop ("# transmission attempts failed (no address)"),
2145 return best_address;
2152 struct GeneratorContext
2154 struct TransportPlugin *plug_pos;
2155 struct OwnAddressList *addr_pos;
2156 struct GNUNET_TIME_Absolute expiration;
2164 address_generator (void *cls, size_t max, void *buf)
2166 struct GeneratorContext *gc = cls;
2169 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2171 gc->plug_pos = gc->plug_pos->next;
2172 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2174 if (NULL == gc->plug_pos)
2179 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2182 gc->addr_pos->addrlen, buf, max);
2183 gc->addr_pos = gc->addr_pos->next;
2189 * Construct our HELLO message from all of the addresses of
2190 * all of the transports.
2193 * @param tc scheduler context
2196 refresh_hello_task (void *cls,
2197 const struct GNUNET_SCHEDULER_TaskContext *tc)
2199 struct GNUNET_HELLO_Message *hello;
2200 struct TransportClient *cpos;
2201 struct NeighbourList *npos;
2202 struct GeneratorContext gc;
2204 hello_task = GNUNET_SCHEDULER_NO_TASK;
2205 gc.plug_pos = plugins;
2206 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2207 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2208 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2211 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2213 GNUNET_STATISTICS_update (stats,
2214 gettext_noop ("# refreshed my HELLO"),
2218 while (cpos != NULL)
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221 "Transmitting my HELLO to client!\n");
2222 transmit_to_client (cpos,
2223 (const struct GNUNET_MessageHeader *) hello,
2228 GNUNET_free_non_null (our_hello);
2230 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2231 for (npos = neighbours; npos != NULL; npos = npos->next)
2233 if (GNUNET_YES != npos->received_pong)
2236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2237 "Transmitting updated `%s' to neighbour `%4s'\n",
2238 "HELLO", GNUNET_i2s (&npos->id));
2240 GNUNET_STATISTICS_update (stats,
2241 gettext_noop ("# transmitted my HELLO to other peers"),
2244 transmit_to_peer (NULL, NULL, 0,
2245 HELLO_ADDRESS_EXPIRATION,
2246 (const char *) our_hello,
2247 GNUNET_HELLO_size(our_hello),
2254 * Schedule task to refresh hello (unless such a
2255 * task exists already).
2260 #if DEBUG_TRANSPORT_HELLO
2261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2262 "refresh_hello() called!\n");
2264 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2267 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2273 * Iterator over hash map entries that NULLs the session of validation
2274 * entries that match the given session.
2276 * @param cls closure (the 'struct Session*' to match against)
2277 * @param key current key code (peer ID, not used)
2278 * @param value value in the hash map ('struct ValidationEntry*')
2279 * @return GNUNET_YES (we should continue to iterate)
2282 remove_session_validations (void *cls,
2283 const GNUNET_HashCode * key,
2286 struct Session *session = cls;
2287 struct ValidationEntry *ve = value;
2289 if (session == ve->session)
2296 * We've been disconnected from the other peer (for some
2297 * connection-oriented transport). Either quickly
2298 * re-establish the connection or signal the disconnect
2301 * Only signal CORE level disconnect if ALL addresses
2302 * for the peer are exhausted.
2304 * @param p overall plugin context
2305 * @param nl neighbour that was disconnected
2308 try_fast_reconnect (struct TransportPlugin *p,
2309 struct NeighbourList *nl)
2311 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2313 "try_fast_reconnect not implemented!\n");
2314 /* Note: the idea here is to hide problems with transports (or
2315 switching between plugins) from the core to eliminate the need to
2316 re-negotiate session keys and the like; OTOH, we should tell core
2317 quickly (much faster than timeout) `if a connection was lost and
2318 could not be re-established (i.e. other peer went down or is
2319 unable / refuses to communicate);
2321 So we should consider:
2322 1) ideally: our own willingness / need to connect
2323 2) prior failures to connect to this peer (by plugin)
2324 3) ideally: reasons why other peer terminated (as far as knowable)
2326 Most importantly, it must be POSSIBLE for another peer to terminate
2327 a connection for a while (without us instantly re-establishing it).
2328 Similarly, if another peer is gone we should quickly notify CORE.
2329 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2330 on the other end), we should reconnect in such a way that BOTH CORE
2331 services never even notice.
2332 Furthermore, the same mechanism (or small variation) could be used
2333 to switch to a better-performing plugin (ATS).
2335 Finally, this needs to be tested throughly... */
2338 * GNUNET_NO in the call below makes transport disconnect the peer,
2339 * even if only a single address (out of say, six) went away. This
2340 * function must be careful to ONLY disconnect if the peer is gone,
2341 * not just a specific address.
2343 * More specifically, half the places it was used had it WRONG.
2346 /* No reconnect, signal disconnect instead! */
2349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2350 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2351 "try_fast_reconnect");
2353 GNUNET_STATISTICS_update (stats,
2354 gettext_noop ("# disconnects due to try_fast_reconnect"),
2358 disconnect_neighbour (nl, GNUNET_YES);
2364 * Function that will be called whenever the plugin internally
2365 * cleans up a session pointer and hence the service needs to
2366 * discard all of those sessions as well. Plugins that do not
2367 * use sessions can simply omit calling this function and always
2368 * use NULL wherever a session pointer is needed.
2370 * @param cls closure
2371 * @param peer which peer was the session for
2372 * @param session which session is being destoyed
2375 plugin_env_session_end (void *cls,
2376 const struct GNUNET_PeerIdentity *peer,
2377 struct Session *session)
2379 struct TransportPlugin *p = cls;
2380 struct NeighbourList *nl;
2381 struct ReadyList *rl;
2382 struct ForeignAddressList *pos;
2383 struct ForeignAddressList *prev;
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Session ended with peer `%4s', %s\n",
2389 "plugin_env_session_end");
2391 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2392 &remove_session_validations,
2394 nl = find_neighbour (peer);
2398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399 "No neighbour record found for peer `%4s'\n",
2402 return; /* was never marked as connected */
2407 if (rl->plugin == p)
2414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2415 "Plugin was associated with peer `%4s'\n",
2418 GNUNET_STATISTICS_update (stats,
2419 gettext_noop ("# disconnects due to session end"),
2422 disconnect_neighbour (nl, GNUNET_YES);
2426 pos = rl->addresses;
2427 while ( (pos != NULL) &&
2428 (pos->session != session) )
2436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2437 "Session was never marked as ready for peer `%4s'\n",
2441 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2443 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2444 if (validations_pending ==GNUNET_YES)
2447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2448 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2453 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2454 GNUNET_STATISTICS_update (stats,
2455 gettext_noop ("# disconnects due to unready session"),
2459 disconnect_neighbour (nl, GNUNET_YES);
2460 return; /* was never marked as connected */
2462 pos->session = NULL;
2463 if (GNUNET_YES == pos->connected)
2465 pos->connected = GNUNET_NO;
2466 GNUNET_STATISTICS_update (stats,
2467 gettext_noop ("# connected addresses"),
2471 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2473 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2474 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2477 if (pos->addrlen != 0)
2479 if (nl->received_pong != GNUNET_NO)
2481 GNUNET_STATISTICS_update (stats,
2482 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2485 if (GNUNET_YES == pos->connected)
2486 try_fast_reconnect (p, nl);
2490 GNUNET_STATISTICS_update (stats,
2491 gettext_noop ("# disconnects due to missing pong"),
2494 /* FIXME this is never true?! See: line 2416*/
2495 if (GNUNET_YES == pos->connected)
2496 disconnect_neighbour (nl, GNUNET_YES);
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... */
2522 pos->connected = GNUNET_NO;
2523 GNUNET_STATISTICS_update (stats,
2524 gettext_noop ("# connected addresses"),
2529 if (nl->received_pong == GNUNET_NO)
2531 GNUNET_STATISTICS_update (stats,
2532 gettext_noop ("# disconnects due to NO pong"),
2535 disconnect_neighbour (nl, GNUNET_YES);
2536 return; /* nothing to do, never connected... */
2538 /* check if we have any validated addresses left */
2539 pos = rl->addresses;
2542 if (GNUNET_YES == pos->validated)
2544 GNUNET_STATISTICS_update (stats,
2545 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2548 try_fast_reconnect (p, nl);
2553 /* no valid addresses left, signal disconnect! */
2556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2557 "Disconnecting peer `%4s', %s\n",
2559 "plugin_env_session_end");
2561 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2562 * it means there aren't any left for this PLUGIN/PEER combination! So
2563 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2564 * when it isn't necessary. Using GNUNET_YES at least checks to see
2565 * if there are any addresses that work first, so as not to overdo it.
2568 GNUNET_STATISTICS_update (stats,
2569 gettext_noop ("# disconnects due to plugin_env_session_end"),
2572 disconnect_neighbour (nl, GNUNET_YES);
2577 * Function that must be called by each plugin to notify the
2578 * transport service about the addresses under which the transport
2579 * provided by the plugin can be reached.
2581 * @param cls closure
2582 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2583 * @param addr one of the addresses of the host, NULL for the last address
2584 * the specific address format depends on the transport
2585 * @param addrlen length of the address
2588 plugin_env_notify_address (void *cls,
2593 struct TransportPlugin *p = cls;
2594 struct OwnAddressList *al;
2595 struct OwnAddressList *prev;
2597 GNUNET_assert (p->api != NULL);
2599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2600 (add_remove == GNUNET_YES)
2601 ? "Adding `%s':%s to the set of our addresses\n"
2602 : "Removing `%s':%s from the set of our addresses\n",
2607 GNUNET_assert (addr != NULL);
2608 if (GNUNET_NO == add_remove)
2614 if ( (addrlen == al->addrlen) &&
2615 (0 == memcmp (addr, &al[1], addrlen)) )
2618 p->addresses = al->next;
2620 prev->next = al->next;
2631 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2632 al->next = p->addresses;
2634 al->addrlen = addrlen;
2635 memcpy (&al[1], addr, addrlen);
2641 * Notify all of our clients about a peer connecting.
2644 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2645 struct GNUNET_TIME_Relative latency,
2648 struct ConnectInfoMessage * cim;
2649 struct TransportClient *cpos;
2653 if (0 == memcmp (peer,
2655 sizeof (struct GNUNET_PeerIdentity)))
2661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2662 "Notifying clients about connection with `%s'\n",
2665 GNUNET_STATISTICS_update (stats,
2666 gettext_noop ("# peers connected"),
2671 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2672 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2673 cim = GNUNET_malloc (size);
2674 cim->header.size = htons (size);
2675 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2676 cim->ats_count = htonl(2);
2677 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2678 (&cim->ats)[0].value = htonl (distance);
2679 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2680 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2681 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2682 (&cim->ats)[2].value = htonl (0);
2683 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2685 /* notify ats about connecting peer */
2686 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2689 ats_modify_problem_state(ats, ATS_MODIFIED);
2690 ats_calculate_bandwidth_distribution (ats);
2694 while (cpos != NULL)
2696 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2704 * Notify all of our clients about a peer disconnecting.
2707 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2709 struct DisconnectInfoMessage dim;
2710 struct TransportClient *cpos;
2712 if (0 == memcmp (peer,
2714 sizeof (struct GNUNET_PeerIdentity)))
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "Notifying clients about lost connection to `%s'\n",
2724 GNUNET_STATISTICS_update (stats,
2725 gettext_noop ("# peers connected"),
2728 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2729 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2730 dim.reserved = htonl (0);
2731 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2733 /* notify ats about connecting peer */
2734 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2737 ats_modify_problem_state(ats, ATS_MODIFIED);
2738 ats_calculate_bandwidth_distribution (ats);
2743 while (cpos != NULL)
2745 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2752 * Find a ForeignAddressList entry for the given neighbour
2753 * that matches the given address and transport.
2755 * @param neighbour which peer we care about
2756 * @param tname name of the transport plugin
2757 * @param session session to look for, NULL for 'any'; otherwise
2758 * can be used for the service to "learn" this session ID
2760 * @param addr binary address
2761 * @param addrlen length of addr
2762 * @return NULL if no such entry exists
2764 static struct ForeignAddressList *
2765 find_peer_address(struct NeighbourList *neighbour,
2767 struct Session *session,
2771 struct ReadyList *head;
2772 struct ForeignAddressList *pos;
2774 head = neighbour->plugins;
2775 while (head != NULL)
2777 if (0 == strcmp (tname, head->plugin->short_name))
2783 pos = head->addresses;
2784 while ( (pos != NULL) &&
2785 ( (pos->addrlen != addrlen) ||
2786 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2788 if ( (session != NULL) &&
2789 (pos->session == session) )
2793 if ( (session != NULL) && (pos != NULL) )
2794 pos->session = session; /* learn it! */
2800 * Get the peer address struct for the given neighbour and
2801 * address. If it doesn't yet exist, create it.
2803 * @param neighbour which peer we care about
2804 * @param tname name of the transport plugin
2805 * @param session session of the plugin, or NULL for none
2806 * @param addr binary address
2807 * @param addrlen length of addr
2808 * @return NULL if we do not have a transport plugin for 'tname'
2810 static struct ForeignAddressList *
2811 add_peer_address (struct NeighbourList *neighbour,
2813 struct Session *session,
2817 struct ReadyList *head;
2818 struct ForeignAddressList *ret;
2821 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2824 head = neighbour->plugins;
2826 while (head != NULL)
2828 if (0 == strcmp (tname, head->plugin->short_name))
2834 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2835 ret->session = session;
2836 if ((addrlen > 0) && (addr != NULL))
2838 ret->addr = (const char*) &ret[1];
2839 memcpy (&ret[1], addr, addrlen);
2846 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2847 for (c=0; c<available_ressources; c++)
2849 struct ATS_ressource_entry *r = ret->ressources;
2851 r[c].atis_index = ressources[c].atis_index;
2852 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2854 r[c].c = ressources[c].c_unix;
2856 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2858 r[c].c = ressources[c].c_udp;
2860 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2862 r[c].c = ressources[c].c_tcp;
2864 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2866 r[c].c = ressources[c].c_http;
2868 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2870 r[c].c = ressources[c].c_https;
2872 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2874 r[c].c = ressources[c].c_wlan;
2878 r[c].c = ressources[c].c_default;
2879 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2880 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2881 GNUNET_i2s(&neighbour->id),
2882 neighbour->plugins->plugin->short_name);
2886 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2887 ret->addrlen = addrlen;
2888 ret->expires = GNUNET_TIME_relative_to_absolute
2889 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2890 ret->latency = GNUNET_TIME_relative_get_forever();
2892 ret->timeout = GNUNET_TIME_relative_to_absolute
2893 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2894 ret->ready_list = head;
2895 ret->next = head->addresses;
2896 head->addresses = ret;
2902 * Closure for 'add_validated_address'.
2904 struct AddValidatedAddressContext
2907 * Entry that has been validated.
2909 const struct ValidationEntry *ve;
2912 * Flag set after we have added the address so
2913 * that we terminate the iteration next time.
2920 * Callback function used to fill a buffer of max bytes with a list of
2921 * addresses in the format used by HELLOs. Should use
2922 * "GNUNET_HELLO_add_address" as a helper function.
2924 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2925 * @param max maximum number of bytes that can be written to buf
2926 * @param buf where to write the address information
2927 * @return number of bytes written, 0 to signal the
2928 * end of the iteration.
2931 add_validated_address (void *cls,
2932 size_t max, void *buf)
2934 struct AddValidatedAddressContext *avac = cls;
2935 const struct ValidationEntry *ve = avac->ve;
2937 if (GNUNET_YES == avac->done)
2939 avac->done = GNUNET_YES;
2940 return GNUNET_HELLO_add_address (ve->transport_name,
2941 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2951 * Closure for 'check_address_exists'.
2953 struct CheckAddressExistsClosure
2956 * Address to check for.
2961 * Name of the transport.
2968 struct Session *session;
2971 * Set to GNUNET_YES if the address exists.
2984 * Iterator over hash map entries. Checks if the given
2985 * validation entry is for the same address as what is given
2988 * @param cls the 'struct CheckAddressExistsClosure*'
2989 * @param key current key code (ignored)
2990 * @param value value in the hash map ('struct ValidationEntry')
2991 * @return GNUNET_YES if we should continue to
2992 * iterate (mismatch), GNUNET_NO if not (entry matched)
2995 check_address_exists (void *cls,
2996 const GNUNET_HashCode * key,
2999 struct CheckAddressExistsClosure *caec = cls;
3000 struct ValidationEntry *ve = value;
3002 if ( (0 == strcmp (caec->tname,
3003 ve->transport_name)) &&
3004 (caec->addrlen == ve->addrlen) &&
3005 (0 == memcmp (caec->addr,
3009 caec->exists = GNUNET_YES;
3012 if ( (ve->session != NULL) &&
3013 (caec->session == ve->session) )
3015 caec->exists = GNUNET_YES;
3023 neighbour_timeout_task (void *cls,
3024 const struct GNUNET_SCHEDULER_TaskContext *tc)
3026 struct NeighbourList *n = cls;
3029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3030 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3032 GNUNET_STATISTICS_update (stats,
3033 gettext_noop ("# disconnects due to timeout"),
3036 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3037 disconnect_neighbour (n, GNUNET_NO);
3042 * Schedule the job that will cause us to send a PING to the
3043 * foreign address to evaluate its validity and latency.
3045 * @param fal address to PING
3048 schedule_next_ping (struct ForeignAddressList *fal);
3052 * Add the given address to the list of foreign addresses
3053 * available for the given peer (check for duplicates).
3055 * @param cls the respective 'struct NeighbourList' to update
3056 * @param tname name of the transport
3057 * @param expiration expiration time
3058 * @param addr the address
3059 * @param addrlen length of the address
3060 * @return GNUNET_OK (always)
3063 add_to_foreign_address_list (void *cls,
3065 struct GNUNET_TIME_Absolute expiration,
3069 struct NeighbourList *n = cls;
3070 struct ForeignAddressList *fal;
3073 GNUNET_STATISTICS_update (stats,
3074 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3078 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3081 #if DEBUG_TRANSPORT_HELLO
3082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3083 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3084 a2s (tname, addr, addrlen),
3086 GNUNET_i2s (&n->id),
3087 expiration.abs_value);
3089 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3092 GNUNET_STATISTICS_update (stats,
3093 gettext_noop ("# previously validated addresses lacking transport"),
3099 fal->expires = GNUNET_TIME_absolute_max (expiration,
3101 schedule_next_ping (fal);
3107 fal->expires = GNUNET_TIME_absolute_max (expiration,
3113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3114 "Failed to add new address for `%4s'\n",
3115 GNUNET_i2s (&n->id));
3119 if (fal->validated == GNUNET_NO)
3121 fal->validated = GNUNET_YES;
3122 GNUNET_STATISTICS_update (stats,
3123 gettext_noop ("# peer addresses considered valid"),
3127 if (try == GNUNET_YES)
3130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3131 "Have new addresses, will try to trigger transmissions.\n");
3133 try_transmission_to_peer (n);
3140 * Add addresses in validated HELLO "h" to the set of addresses
3141 * we have for this peer.
3143 * @param cls closure ('struct NeighbourList*')
3144 * @param peer id of the peer, NULL for last call
3145 * @param h hello message for the peer (can be NULL)
3146 * @param err_msg NULL if successful, otherwise contains error message
3149 add_hello_for_peer (void *cls,
3150 const struct GNUNET_PeerIdentity *peer,
3151 const struct GNUNET_HELLO_Message *h,
3152 const char *err_msg)
3154 struct NeighbourList *n = cls;
3156 if (err_msg != NULL)
3159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3160 _("Error in communication with PEERINFO service: %s\n"),
3167 GNUNET_STATISTICS_update (stats,
3168 gettext_noop ("# outstanding peerinfo iterate requests"),
3175 return; /* no HELLO available */
3177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3178 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3182 if (GNUNET_YES != n->public_key_valid)
3184 GNUNET_HELLO_get_key (h, &n->publicKey);
3185 n->public_key_valid = GNUNET_YES;
3187 GNUNET_HELLO_iterate_addresses (h,
3189 &add_to_foreign_address_list,
3195 * Create a fresh entry in our neighbour list for the given peer.
3196 * Will try to transmit our current HELLO to the new neighbour.
3197 * Do not call this function directly, use 'setup_peer_check_blacklist.
3199 * @param peer the peer for which we create the entry
3200 * @param do_hello should we schedule transmitting a HELLO
3201 * @return the new neighbour list entry
3203 static struct NeighbourList *
3204 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3207 struct NeighbourList *n;
3208 struct TransportPlugin *tp;
3209 struct ReadyList *rl;
3211 GNUNET_assert (0 != memcmp (peer,
3213 sizeof (struct GNUNET_PeerIdentity)));
3215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3216 "Setting up state for neighbour `%4s'\n",
3219 GNUNET_STATISTICS_update (stats,
3220 gettext_noop ("# active neighbours"),
3223 n = GNUNET_malloc (sizeof (struct NeighbourList));
3224 n->next = neighbours;
3228 GNUNET_TIME_relative_to_absolute
3229 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3230 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3231 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3232 MAX_BANDWIDTH_CARRY_S);
3236 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3238 rl = GNUNET_malloc (sizeof (struct ReadyList));
3240 rl->next = n->plugins;
3243 rl->addresses = NULL;
3247 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3249 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3250 &neighbour_timeout_task, n);
3253 GNUNET_STATISTICS_update (stats,
3254 gettext_noop ("# peerinfo new neighbor iterate requests"),
3257 GNUNET_STATISTICS_update (stats,
3258 gettext_noop ("# outstanding peerinfo iterate requests"),
3261 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3262 GNUNET_TIME_UNIT_FOREVER_REL,
3263 &add_hello_for_peer, n);
3265 GNUNET_STATISTICS_update (stats,
3266 gettext_noop ("# HELLO's sent to new neighbors"),
3269 if (NULL != our_hello)
3270 transmit_to_peer (NULL, NULL, 0,
3271 HELLO_ADDRESS_EXPIRATION,
3272 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3280 * Function called after we have checked if communicating
3281 * with a given peer is acceptable.
3283 * @param cls closure
3284 * @param n NULL if communication is not acceptable
3286 typedef void (*SetupContinuation)(void *cls,
3287 struct NeighbourList *n);
3291 * Information kept for each client registered to perform
3297 * This is a linked list.
3299 struct Blacklisters *next;
3302 * This is a linked list.
3304 struct Blacklisters *prev;
3307 * Client responsible for this entry.
3309 struct GNUNET_SERVER_Client *client;
3312 * Blacklist check that we're currently performing.
3314 struct BlacklistCheck *bc;
3320 * Head of DLL of blacklisting clients.
3322 static struct Blacklisters *bl_head;
3325 * Tail of DLL of blacklisting clients.
3327 static struct Blacklisters *bl_tail;
3331 * Context we use when performing a blacklist check.
3333 struct BlacklistCheck
3337 * This is a linked list.
3339 struct BlacklistCheck *next;
3342 * This is a linked list.
3344 struct BlacklistCheck *prev;
3347 * Peer being checked.
3349 struct GNUNET_PeerIdentity peer;
3352 * Option for setup neighbour afterwards.
3357 * Continuation to call with the result.
3359 SetupContinuation cont;
3367 * Current transmission request handle for this client, or NULL if no
3368 * request is pending.
3370 struct GNUNET_CONNECTION_TransmitHandle *th;
3373 * Our current position in the blacklisters list.
3375 struct Blacklisters *bl_pos;
3378 * Current task performing the check.
3380 GNUNET_SCHEDULER_TaskIdentifier task;
3385 * Head of DLL of active blacklisting queries.
3387 static struct BlacklistCheck *bc_head;
3390 * Tail of DLL of active blacklisting queries.
3392 static struct BlacklistCheck *bc_tail;
3396 * Perform next action in the blacklist check.
3398 * @param cls the 'struct BlacklistCheck*'
3402 do_blacklist_check (void *cls,
3403 const struct GNUNET_SCHEDULER_TaskContext *tc);
3406 * Transmit blacklist query to the client.
3408 * @param cls the 'struct BlacklistCheck'
3409 * @param size number of bytes allowed
3410 * @param buf where to copy the message
3411 * @return number of bytes copied to buf
3414 transmit_blacklist_message (void *cls,
3418 struct BlacklistCheck *bc = cls;
3419 struct Blacklisters *bl;
3420 struct BlacklistMessage bm;
3425 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3426 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3428 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3429 "Failed to send blacklist test for peer `%s' to client\n",
3430 GNUNET_i2s (&bc->peer));
3434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3435 "Sending blacklist test for peer `%s' to client\n",
3436 GNUNET_i2s (&bc->peer));
3439 bm.header.size = htons (sizeof (struct BlacklistMessage));
3440 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3441 bm.is_allowed = htonl (0);
3443 memcpy (buf, &bm, sizeof (bm));
3444 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3450 * Perform next action in the blacklist check.
3452 * @param cls the 'struct BlacklistCheck*'
3456 do_blacklist_check (void *cls,
3457 const struct GNUNET_SCHEDULER_TaskContext *tc)
3459 struct BlacklistCheck *bc = cls;
3460 struct Blacklisters *bl;
3462 bc->task = GNUNET_SCHEDULER_NO_TASK;
3467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3468 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3469 GNUNET_i2s (&bc->peer));
3471 bc->cont (bc->cont_cls,
3472 setup_new_neighbour (&bc->peer, bc->do_hello));
3479 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3480 sizeof (struct BlacklistMessage),
3481 GNUNET_TIME_UNIT_FOREVER_REL,
3482 &transmit_blacklist_message,
3489 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3490 * does not yet exist, check the blacklist. If the blacklist says creating
3491 * one is acceptable, create one and call the continuation; otherwise
3492 * call the continuation with NULL.
3494 * @param peer peer to setup or look up a struct NeighbourList for
3495 * @param do_hello should we also schedule sending our HELLO to the peer
3496 * if this is a new record
3497 * @param cont function to call with the 'struct NeigbhbourList*'
3498 * @param cont_cls closure for cont
3501 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3503 SetupContinuation cont,
3506 struct NeighbourList *n;
3507 struct BlacklistCheck *bc;
3509 n = find_neighbour(peer);
3513 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3514 "Neighbour record exists for peer `%s'\n",
3521 if (bl_head == NULL)
3524 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3526 setup_new_neighbour(peer, do_hello);
3529 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3530 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3532 bc->do_hello = do_hello;
3534 bc->cont_cls = cont_cls;
3535 bc->bl_pos = bl_head;
3536 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3542 * Function called with the result of querying a new blacklister about
3543 * it being allowed (or not) to continue to talk to an existing neighbour.
3545 * @param cls the original 'struct NeighbourList'
3546 * @param n NULL if we need to disconnect
3549 confirm_or_drop_neighbour (void *cls,
3550 struct NeighbourList *n)
3552 struct NeighbourList * orig = cls;
3557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3558 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3559 "confirm_or_drop_neighboUr");
3561 GNUNET_STATISTICS_update (stats,
3562 gettext_noop ("# disconnects due to blacklist"),
3565 disconnect_neighbour (orig, GNUNET_NO);
3571 * Handle a request to start a blacklist.
3573 * @param cls closure (always NULL)
3574 * @param client identification of the client
3575 * @param message the actual message
3578 handle_blacklist_init (void *cls,
3579 struct GNUNET_SERVER_Client *client,
3580 const struct GNUNET_MessageHeader *message)
3582 struct Blacklisters *bl;
3583 struct BlacklistCheck *bc;
3584 struct NeighbourList *n;
3589 if (bl->client == client)
3592 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3597 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3598 bl->client = client;
3599 GNUNET_SERVER_client_keep (client);
3600 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3601 /* confirm that all existing connections are OK! */
3605 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3606 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3608 bc->do_hello = GNUNET_NO;
3609 bc->cont = &confirm_or_drop_neighbour;
3612 if (n == neighbours) /* all would wait for the same client, no need to
3613 create more than just the first task right now */
3614 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3622 * Handle a request to blacklist a peer.
3624 * @param cls closure (always NULL)
3625 * @param client identification of the client
3626 * @param message the actual message
3629 handle_blacklist_reply (void *cls,
3630 struct GNUNET_SERVER_Client *client,
3631 const struct GNUNET_MessageHeader *message)
3633 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3634 struct Blacklisters *bl;
3635 struct BlacklistCheck *bc;
3638 while ( (bl != NULL) &&
3639 (bl->client != client) )
3644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3645 "Blacklist client disconnected\n");
3647 /* FIXME: other error handling here!? */
3648 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3653 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3657 "Blacklist check failed, peer not allowed\n");
3659 bc->cont (bc->cont_cls, NULL);
3660 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3667 "Blacklist check succeeded, continuing with checks\n");
3669 bc->bl_pos = bc->bl_pos->next;
3670 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3673 /* check if any other bc's are waiting for this blacklister */
3677 if ( (bc->bl_pos == bl) &&
3678 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3679 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3687 * Send periodic PING messages to a given foreign address.
3689 * @param cls our 'struct PeriodicValidationContext*'
3690 * @param tc task context
3693 send_periodic_ping (void *cls,
3694 const struct GNUNET_SCHEDULER_TaskContext *tc)
3696 struct ForeignAddressList *peer_address = cls;
3697 struct TransportPlugin *tp;
3698 struct ValidationEntry *va;
3699 struct NeighbourList *neighbour;
3700 struct TransportPingMessage ping;
3701 struct CheckAddressExistsClosure caec;
3703 uint16_t hello_size;
3707 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3708 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3710 GNUNET_assert (peer_address != NULL);
3711 tp = peer_address->ready_list->plugin;
3712 neighbour = peer_address->ready_list->neighbour;
3713 if (GNUNET_YES != neighbour->public_key_valid)
3715 /* no public key yet, try again later */
3716 schedule_next_ping (peer_address);
3719 caec.addr = peer_address->addr;
3720 caec.addrlen = peer_address->addrlen;
3721 caec.tname = tp->short_name;
3722 caec.session = peer_address->session;
3723 caec.exists = GNUNET_NO;
3725 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3726 &check_address_exists,
3728 if (caec.exists == GNUNET_YES)
3730 /* During validation attempts we will likely trigger the other
3731 peer trying to validate our address which in turn will cause
3732 it to send us its HELLO, so we expect to hit this case rather
3733 frequently. Only print something if we are very verbose. */
3734 #if DEBUG_TRANSPORT > 1
3735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3736 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3737 (peer_address->addr != NULL)
3738 ? a2s (tp->short_name,
3740 peer_address->addrlen)
3743 GNUNET_i2s (&neighbour->id));
3745 schedule_next_ping (peer_address);
3748 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3749 va->transport_name = GNUNET_strdup (tp->short_name);
3750 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3752 va->send_time = GNUNET_TIME_absolute_get();
3753 va->session = peer_address->session;
3754 if (peer_address->addr != NULL)
3756 va->addr = (const void*) &va[1];
3757 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3758 va->addrlen = peer_address->addrlen;
3760 memcpy(&va->publicKey,
3761 &neighbour->publicKey,
3762 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3764 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3765 &timeout_hello_validation,
3767 GNUNET_CONTAINER_multihashmap_put (validation_map,
3768 &neighbour->id.hashPubKey,
3770 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3772 if (peer_address->validated != GNUNET_YES)
3773 hello_size = GNUNET_HELLO_size(our_hello);
3777 tsize = sizeof(struct TransportPingMessage) + hello_size;
3779 if (peer_address->addr != NULL)
3781 slen = strlen (tp->short_name) + 1;
3782 tsize += slen + peer_address->addrlen;
3786 slen = 0; /* make gcc happy */
3788 message_buf = GNUNET_malloc(tsize);
3789 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3790 ping.challenge = htonl(va->challenge);
3791 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3792 if (peer_address->validated != GNUNET_YES)
3794 memcpy(message_buf, our_hello, hello_size);
3797 if (peer_address->addr != NULL)
3799 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3800 peer_address->addrlen +
3802 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3805 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3807 peer_address->addrlen);
3811 ping.header.size = htons(sizeof(struct TransportPingMessage));
3814 memcpy(&message_buf[hello_size],
3816 sizeof(struct TransportPingMessage));
3818 #if DEBUG_TRANSPORT_REVALIDATION
3819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3820 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3821 (peer_address->addr != NULL)
3822 ? a2s (peer_address->plugin->short_name,
3824 peer_address->addrlen)
3827 GNUNET_i2s (&neighbour->id),
3828 "HELLO", hello_size,
3831 if (peer_address->validated != GNUNET_YES)
3832 GNUNET_STATISTICS_update (stats,
3833 gettext_noop ("# PING with HELLO messages sent"),
3837 GNUNET_STATISTICS_update (stats,
3838 gettext_noop ("# PING without HELLO messages sent"),
3841 GNUNET_STATISTICS_update (stats,
3842 gettext_noop ("# PING messages sent for re-validation"),
3845 transmit_to_peer (NULL, peer_address,
3846 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3847 HELLO_VERIFICATION_TIMEOUT,
3849 GNUNET_YES, neighbour);
3850 GNUNET_free (message_buf);
3851 schedule_next_ping (peer_address);
3856 * Schedule the job that will cause us to send a PING to the
3857 * foreign address to evaluate its validity and latency.
3859 * @param fal address to PING
3862 schedule_next_ping (struct ForeignAddressList *fal)
3864 struct GNUNET_TIME_Relative delay;
3866 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3868 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3869 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3871 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3872 delay.rel_value /= 2; /* do before expiration */
3873 delay = GNUNET_TIME_relative_min (delay,
3874 LATENCY_EVALUATION_MAX_DELAY);
3875 if (GNUNET_YES != fal->estimated)
3877 delay = GNUNET_TIME_UNIT_ZERO;
3878 fal->estimated = GNUNET_YES;
3881 if (GNUNET_YES == fal->connected)
3883 delay = GNUNET_TIME_relative_min (delay,
3884 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3886 /* FIXME: also adjust delay based on how close the last
3887 observed latency is to the latency of the best alternative */
3888 /* bound how fast we can go */
3889 delay = GNUNET_TIME_relative_max (delay,
3890 GNUNET_TIME_UNIT_SECONDS);
3891 /* randomize a bit (to avoid doing all at the same time) */
3892 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3894 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3895 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3896 &send_periodic_ping,
3904 * Function that will be called if we receive some payload
3905 * from another peer.
3907 * @param message the payload
3908 * @param n peer who claimed to be the sender
3911 handle_payload_message (const struct GNUNET_MessageHeader *message,
3912 struct NeighbourList *n)
3914 struct InboundMessage *im;
3915 struct TransportClient *cpos;
3918 msize = ntohs (message->size);
3919 if (n->received_pong == GNUNET_NO)
3922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3923 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3924 ntohs (message->type),
3925 ntohs (message->size),
3926 GNUNET_i2s (&n->id));
3928 GNUNET_free_non_null (n->pre_connect_message_buffer);
3929 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3930 memcpy (n->pre_connect_message_buffer, message, msize);
3935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3936 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3937 ntohs (message->type),
3938 ntohs (message->size),
3939 GNUNET_i2s (&n->id));
3941 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3944 n->quota_violation_count++;
3946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3947 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3948 n->in_tracker.available_bytes_per_s__,
3949 n->quota_violation_count);
3951 /* Discount 32k per violation */
3952 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3957 if (n->quota_violation_count > 0)
3959 /* try to add 32k back */
3960 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3962 n->quota_violation_count--;
3965 GNUNET_STATISTICS_update (stats,
3966 gettext_noop ("# payload received from other peers"),
3969 /* transmit message to all clients */
3970 uint32_t ats_count = 2;
3971 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3972 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3975 im = GNUNET_malloc (size);
3976 im->header.size = htons (size);
3977 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3979 im->ats_count = htonl(ats_count);
3980 /* Setting ATS data */
3981 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3982 (&(im->ats))[0].value = htonl (n->distance);
3983 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3984 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3985 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3986 (&(im->ats))[ats_count].value = htonl (0);
3988 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3990 while (cpos != NULL)
3992 transmit_to_client (cpos, &im->header, GNUNET_YES);
4000 * Iterator over hash map entries. Checks if the given validation
4001 * entry is for the same challenge as what is given in the PONG.
4003 * @param cls the 'struct TransportPongMessage*'
4004 * @param key peer identity
4005 * @param value value in the hash map ('struct ValidationEntry')
4006 * @return GNUNET_YES if we should continue to
4007 * iterate (mismatch), GNUNET_NO if not (entry matched)
4010 check_pending_validation (void *cls,
4011 const GNUNET_HashCode * key,
4014 const struct TransportPongMessage *pong = cls;
4015 struct ValidationEntry *ve = value;
4016 struct AddValidatedAddressContext avac;
4017 unsigned int challenge = ntohl(pong->challenge);
4018 struct GNUNET_HELLO_Message *hello;
4019 struct GNUNET_PeerIdentity target;
4020 struct NeighbourList *n;
4021 struct ForeignAddressList *fal;
4022 struct OwnAddressList *oal;
4023 struct TransportPlugin *tp;
4024 struct GNUNET_MessageHeader *prem;
4030 ps = ntohs (pong->header.size);
4031 if (ps < sizeof (struct TransportPongMessage))
4033 GNUNET_break_op (0);
4036 addr = (const char*) &pong[1];
4037 slen = strlen (ve->transport_name) + 1;
4038 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4039 (ve->challenge != challenge) ||
4040 (addr[slen-1] != '\0') ||
4041 (0 != strcmp (addr, ve->transport_name)) ||
4042 (ntohl (pong->purpose.size)
4043 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4045 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4046 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4051 alen = ps - sizeof (struct TransportPongMessage) - slen;
4052 switch (ntohl (pong->purpose.purpose))
4054 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4055 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4056 (0 != memcmp (&addr[slen],
4060 return GNUNET_YES; /* different entry, keep trying! */
4062 if (0 != memcmp (&pong->pid,
4064 sizeof (struct GNUNET_PeerIdentity)))
4066 GNUNET_break_op (0);
4070 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4075 GNUNET_break_op (0);
4080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4081 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4083 a2s (ve->transport_name,
4084 (const struct sockaddr *) ve->addr,
4086 ve->transport_name);
4089 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4090 if (0 != memcmp (&pong->pid,
4092 sizeof (struct GNUNET_PeerIdentity)))
4096 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4099 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4100 GNUNET_i2s (&my_identity),
4106 if (ve->addrlen != 0)
4108 /* must have been for a different validation entry */
4111 tp = find_transport (ve->transport_name);
4117 oal = tp->addresses;
4120 if ( (oal->addrlen == alen) &&
4121 (0 == memcmp (&oal[1],
4129 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4130 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4131 GNUNET_i2s (&pong->pid),
4132 a2s (ve->transport_name,
4135 /* FIXME: since the sender of the PONG currently uses the
4136 wrong address (see FIMXE there!), we cannot run a
4137 proper check here... */
4143 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4148 GNUNET_break_op (0);
4153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4154 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4156 a2s (ve->transport_name,
4159 ve->transport_name);
4163 GNUNET_break_op (0);
4166 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4168 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4169 _("Received expired signature. Check system time.\n"));
4172 GNUNET_STATISTICS_update (stats,
4173 gettext_noop ("# address validation successes"),
4176 /* create the updated HELLO */
4177 GNUNET_CRYPTO_hash (&ve->publicKey,
4178 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4179 &target.hashPubKey);
4180 if (ve->addr != NULL)
4182 avac.done = GNUNET_NO;
4184 hello = GNUNET_HELLO_create (&ve->publicKey,
4185 &add_validated_address,
4187 GNUNET_PEERINFO_add_peer (peerinfo,
4189 GNUNET_free (hello);
4191 n = find_neighbour (&target);
4194 n->publicKey = ve->publicKey;
4195 n->public_key_valid = GNUNET_YES;
4196 fal = add_peer_address (n,
4201 GNUNET_assert (fal != NULL);
4202 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4203 fal->validated = GNUNET_YES;
4204 mark_address_connected (fal);
4205 GNUNET_STATISTICS_update (stats,
4206 gettext_noop ("# peer addresses considered valid"),
4209 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4210 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4212 schedule_next_ping (fal);
4213 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4214 n->latency = fal->latency;
4216 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4218 n->distance = fal->distance;
4219 if (GNUNET_NO == n->received_pong)
4221 n->received_pong = GNUNET_YES;
4222 notify_clients_connect (&target, n->latency, n->distance);
4223 if (NULL != (prem = n->pre_connect_message_buffer))
4225 n->pre_connect_message_buffer = NULL;
4226 handle_payload_message (prem, n);
4230 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4232 GNUNET_SCHEDULER_cancel (n->retry_task);
4233 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4234 try_transmission_to_peer (n);
4238 /* clean up validation entry */
4239 GNUNET_assert (GNUNET_YES ==
4240 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4243 abort_validation (NULL, NULL, ve);
4249 * Function that will be called if we receive a validation
4250 * of an address challenge that we transmitted to another
4251 * peer. Note that the validation should only be considered
4252 * acceptable if the challenge matches AND if the sender
4253 * address is at least a plausible address for this peer
4254 * (otherwise we may be seeing a MiM attack).
4256 * @param cls closure
4257 * @param message the pong message
4258 * @param peer who responded to our challenge
4259 * @param sender_address string describing our sender address (as observed
4260 * by the other peer in binary format)
4261 * @param sender_address_len number of bytes in 'sender_address'
4264 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4265 const struct GNUNET_PeerIdentity *peer,
4266 const char *sender_address,
4267 size_t sender_address_len)
4269 if (0 == memcmp (peer,
4271 sizeof (struct GNUNET_PeerIdentity)))
4273 /* PONG send to self, ignore */
4274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4275 "Receiving `%s' message from myself\n",
4279 #if DEBUG_TRANSPORT > 1
4280 /* we get tons of these that just get discarded, only log
4281 if we are quite verbose */
4282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4283 "Receiving `%s' message from `%4s'.\n", "PONG",
4286 GNUNET_STATISTICS_update (stats,
4287 gettext_noop ("# PONG messages received"),
4290 if (GNUNET_SYSERR !=
4291 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4293 &check_pending_validation,
4296 /* This is *expected* to happen a lot since we send
4297 PONGs to *all* known addresses of the sender of
4298 the PING, so most likely we get multiple PONGs
4299 per PING, and all but the first PONG will end up
4300 here. So really we should not print anything here
4301 unless we want to be very, very verbose... */
4302 #if DEBUG_TRANSPORT > 2
4303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4304 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4316 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4318 * @param cls the 'struct ValidationEntry*'
4319 * @param neighbour neighbour to validate, NULL if validation failed
4322 transmit_hello_and_ping (void *cls,
4323 struct NeighbourList *neighbour)
4325 struct ValidationEntry *va = cls;
4326 struct ForeignAddressList *peer_address;
4327 struct TransportPingMessage ping;
4328 uint16_t hello_size;
4331 struct GNUNET_PeerIdentity id;
4334 GNUNET_CRYPTO_hash (&va->publicKey,
4335 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4337 if (neighbour == NULL)
4339 /* FIXME: stats... */
4340 GNUNET_break (GNUNET_OK ==
4341 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4344 abort_validation (NULL, NULL, va);
4347 neighbour->publicKey = va->publicKey;
4348 neighbour->public_key_valid = GNUNET_YES;
4349 peer_address = add_peer_address (neighbour,
4350 va->transport_name, NULL,
4351 (const void*) &va[1],
4353 if (peer_address == NULL)
4355 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4356 "Failed to add peer `%4s' for plugin `%s'\n",
4357 GNUNET_i2s (&neighbour->id),
4358 va->transport_name);
4359 GNUNET_break (GNUNET_OK ==
4360 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4363 abort_validation (NULL, NULL, va);
4366 if (NULL == our_hello)
4367 refresh_hello_task (NULL, NULL);
4368 hello_size = GNUNET_HELLO_size(our_hello);
4369 slen = strlen(va->transport_name) + 1;
4370 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4371 message_buf = GNUNET_malloc(tsize);
4372 ping.challenge = htonl(va->challenge);
4373 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4374 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4375 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4376 memcpy(message_buf, our_hello, hello_size);
4377 memcpy(&message_buf[hello_size],
4379 sizeof(struct TransportPingMessage));
4380 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4383 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4388 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4391 : a2s (va->transport_name,
4392 (const void*) &va[1], va->addrlen),
4394 GNUNET_i2s (&neighbour->id),
4395 "HELLO", hello_size,
4396 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4399 GNUNET_STATISTICS_update (stats,
4400 gettext_noop ("# PING messages sent for initial validation"),
4403 transmit_to_peer (NULL, peer_address,
4404 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4405 HELLO_VERIFICATION_TIMEOUT,
4407 GNUNET_YES, neighbour);
4408 GNUNET_free (message_buf);
4413 * Check if the given address is already being validated; if not,
4414 * append the given address to the list of entries that are being be
4415 * validated and initiate validation.
4417 * @param cls closure ('struct CheckHelloValidatedContext *')
4418 * @param tname name of the transport
4419 * @param expiration expiration time
4420 * @param addr the address
4421 * @param addrlen length of the address
4422 * @return GNUNET_OK (always)
4425 run_validation (void *cls,
4427 struct GNUNET_TIME_Absolute expiration,
4431 struct CheckHelloValidatedContext *chvc = cls;
4432 struct GNUNET_PeerIdentity id;
4433 struct TransportPlugin *tp;
4434 struct ValidationEntry *va;
4435 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4436 struct CheckAddressExistsClosure caec;
4437 struct OwnAddressList *oal;
4439 GNUNET_assert (addr != NULL);
4441 GNUNET_STATISTICS_update (stats,
4442 gettext_noop ("# peer addresses scheduled for validation"),
4445 tp = find_transport (tname);
4448 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4449 GNUNET_ERROR_TYPE_BULK,
4451 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4453 GNUNET_STATISTICS_update (stats,
4454 gettext_noop ("# peer addresses not validated (plugin not available)"),
4459 /* check if this is one of our own addresses */
4460 oal = tp->addresses;
4463 if ( (oal->addrlen == addrlen) &&
4464 (0 == memcmp (&oal[1],
4468 /* not plausible, this address is equivalent to our own address! */
4469 GNUNET_STATISTICS_update (stats,
4470 gettext_noop ("# peer addresses not validated (loopback)"),
4477 GNUNET_HELLO_get_key (chvc->hello, &pk);
4478 GNUNET_CRYPTO_hash (&pk,
4480 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4483 if (is_blacklisted(&id, tp))
4486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4487 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4495 caec.addrlen = addrlen;
4496 caec.session = NULL;
4498 caec.exists = GNUNET_NO;
4499 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4500 &check_address_exists,
4502 if (caec.exists == GNUNET_YES)
4504 /* During validation attempts we will likely trigger the other
4505 peer trying to validate our address which in turn will cause
4506 it to send us its HELLO, so we expect to hit this case rather
4507 frequently. Only print something if we are very verbose. */
4508 #if DEBUG_TRANSPORT > 1
4509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4510 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4511 a2s (tname, addr, addrlen),
4515 GNUNET_STATISTICS_update (stats,
4516 gettext_noop ("# peer addresses not validated (in progress)"),
4521 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4524 va->transport_name = GNUNET_strdup (tname);
4525 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4527 va->send_time = GNUNET_TIME_absolute_get();
4528 va->addr = (const void*) &va[1];
4529 memcpy (&va[1], addr, addrlen);
4530 va->addrlen = addrlen;
4531 GNUNET_HELLO_get_key (chvc->hello,
4533 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4534 &timeout_hello_validation,
4536 GNUNET_CONTAINER_multihashmap_put (validation_map,
4539 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4540 setup_peer_check_blacklist (&id, GNUNET_NO,
4541 &transmit_hello_and_ping,
4548 * Check if addresses in validated hello "h" overlap with
4549 * those in "chvc->hello" and validate the rest.
4551 * @param cls closure
4552 * @param peer id of the peer, NULL for last call
4553 * @param h hello message for the peer (can be NULL)
4554 * @param err_msg NULL if successful, otherwise contains error message
4557 check_hello_validated (void *cls,
4558 const struct GNUNET_PeerIdentity *peer,
4559 const struct GNUNET_HELLO_Message *h,
4560 const char *err_msg)
4562 struct CheckHelloValidatedContext *chvc = cls;
4563 struct GNUNET_HELLO_Message *plain_hello;
4564 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4565 struct GNUNET_PeerIdentity target;
4566 struct NeighbourList *n;
4568 if (err_msg != NULL)
4571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4572 _("Error in communication with PEERINFO service: %s\n"),
4580 GNUNET_STATISTICS_update (stats,
4581 gettext_noop ("# outstanding peerinfo iterate requests"),
4585 if (GNUNET_NO == chvc->hello_known)
4587 /* notify PEERINFO about the peer now, so that we at least
4588 have the public key if some other component needs it */
4589 GNUNET_HELLO_get_key (chvc->hello, &pk);
4590 GNUNET_CRYPTO_hash (&pk,
4591 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4592 &target.hashPubKey);
4593 plain_hello = GNUNET_HELLO_create (&pk,
4596 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4597 GNUNET_free (plain_hello);
4598 #if DEBUG_TRANSPORT_HELLO
4599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4600 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4602 GNUNET_i2s (&target));
4604 GNUNET_STATISTICS_update (stats,
4605 gettext_noop ("# new HELLOs requiring full validation"),
4608 GNUNET_HELLO_iterate_addresses (chvc->hello,
4615 GNUNET_STATISTICS_update (stats,
4616 gettext_noop ("# duplicate HELLO (peer known)"),
4621 if (chvc->ve_count == 0)
4623 GNUNET_CONTAINER_DLL_remove (chvc_head,
4632 #if DEBUG_TRANSPORT_HELLO
4633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4634 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4638 chvc->hello_known = GNUNET_YES;
4639 n = find_neighbour (peer);
4642 #if DEBUG_TRANSPORT_HELLO
4643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4644 "Calling hello_iterate_addresses for %s!\n",
4647 GNUNET_HELLO_iterate_addresses (h,
4649 &add_to_foreign_address_list,
4651 try_transmission_to_peer (n);
4655 #if DEBUG_TRANSPORT_HELLO
4656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4657 "No existing neighbor record for %s!\n",
4660 GNUNET_STATISTICS_update (stats,
4661 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4665 GNUNET_STATISTICS_update (stats,
4666 gettext_noop ("# HELLO validations (update case)"),
4669 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4671 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4678 * Process HELLO-message.
4680 * @param plugin transport involved, may be NULL
4681 * @param message the actual message
4682 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4685 process_hello (struct TransportPlugin *plugin,
4686 const struct GNUNET_MessageHeader *message)
4689 struct GNUNET_PeerIdentity target;
4690 const struct GNUNET_HELLO_Message *hello;
4691 struct CheckHelloValidatedContext *chvc;
4692 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4693 struct NeighbourList *n;
4694 #if DEBUG_TRANSPORT_HELLO > 2
4698 hsize = ntohs (message->size);
4699 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4700 (hsize < sizeof (struct GNUNET_MessageHeader)))
4703 return GNUNET_SYSERR;
4705 GNUNET_STATISTICS_update (stats,
4706 gettext_noop ("# HELLOs received for validation"),
4710 hello = (const struct GNUNET_HELLO_Message *) message;
4711 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4713 #if DEBUG_TRANSPORT_HELLO
4714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4715 "Unable to get public key from `%s' for `%4s'!\n",
4717 GNUNET_i2s (&target));
4719 GNUNET_break_op (0);
4720 return GNUNET_SYSERR;
4722 GNUNET_CRYPTO_hash (&publicKey,
4723 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4724 &target.hashPubKey);
4726 #if DEBUG_TRANSPORT_HELLO
4727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4728 "Received `%s' message for `%4s'\n",
4730 GNUNET_i2s (&target));
4732 if (0 == memcmp (&my_identity,
4734 sizeof (struct GNUNET_PeerIdentity)))
4736 GNUNET_STATISTICS_update (stats,
4737 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4742 n = find_neighbour (&target);
4744 (! n->public_key_valid) )
4746 GNUNET_HELLO_get_key (hello, &n->publicKey);
4747 n->public_key_valid = GNUNET_YES;
4750 /* check if load is too high before doing expensive stuff */
4751 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4753 GNUNET_STATISTICS_update (stats,
4754 gettext_noop ("# HELLOs ignored due to high load"),
4757 #if DEBUG_TRANSPORT_HELLO
4758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4759 "Ignoring `%s' for `%4s', load too high.\n",
4761 GNUNET_i2s (&target));
4768 while (NULL != chvc)
4770 if (GNUNET_HELLO_equals (hello,
4772 GNUNET_TIME_absolute_get ()).abs_value > 0)
4774 #if DEBUG_TRANSPORT_HELLO > 2
4775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4776 "Received duplicate `%s' message for `%4s'; ignored\n",
4778 GNUNET_i2s (&target));
4780 return GNUNET_OK; /* validation already pending */
4782 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4783 GNUNET_break (0 != memcmp (hello, chvc->hello,
4784 GNUNET_HELLO_size(hello)));
4789 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4790 if ((NULL != temp_neighbor))
4792 fprintf(stderr, "Already know peer, ignoring hello\n");
4797 #if DEBUG_TRANSPORT_HELLO > 2
4801 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4803 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4806 GNUNET_i2s (&target),
4808 GNUNET_HELLO_size(hello));
4809 GNUNET_free (my_id);
4813 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4815 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4816 memcpy (&chvc[1], hello, hsize);
4817 GNUNET_CONTAINER_DLL_insert (chvc_head,
4820 /* finally, check if HELLO was previously validated
4821 (continuation will then schedule actual validation) */
4822 GNUNET_STATISTICS_update (stats,
4823 gettext_noop ("# peerinfo process hello iterate requests"),
4826 GNUNET_STATISTICS_update (stats,
4827 gettext_noop ("# outstanding peerinfo iterate requests"),
4830 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4832 HELLO_VERIFICATION_TIMEOUT,
4833 &check_hello_validated, chvc);
4839 * The peer specified by the given neighbour has timed-out or a plugin
4840 * has disconnected. We may either need to do nothing (other plugins
4841 * still up), or trigger a full disconnect and clean up. This
4842 * function updates our state and does the necessary notifications.
4843 * Also notifies our clients that the neighbour is now officially
4846 * @param n the neighbour list entry for the peer
4847 * @param check GNUNET_YES to check if ALL addresses for this peer
4848 * are gone, GNUNET_NO to force a disconnect of the peer
4849 * regardless of whether other addresses exist.
4852 disconnect_neighbour (struct NeighbourList *n, int check)
4854 struct ReadyList *rpos;
4855 struct NeighbourList *npos;
4856 struct NeighbourList *nprev;
4857 struct MessageQueue *mq;
4858 struct ForeignAddressList *peer_addresses;
4859 struct ForeignAddressList *peer_pos;
4861 if (GNUNET_YES == n->in_disconnect)
4863 if (GNUNET_YES == check)
4866 while (NULL != rpos)
4868 peer_addresses = rpos->addresses;
4869 while (peer_addresses != NULL)
4871 /* Do not disconnect if: an address is connected or an inbound address exists */
4872 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4876 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4877 GNUNET_i2s (&n->id),
4878 a2s (peer_addresses->ready_list->plugin->short_name,
4879 peer_addresses->addr,
4880 peer_addresses->addrlen));
4882 return; /* still connected */
4884 peer_addresses = peer_addresses->next;
4890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4891 "Disconnecting from `%4s'\n",
4892 GNUNET_i2s (&n->id));
4894 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4896 /* notify all clients about disconnect */
4897 if (GNUNET_YES == n->received_pong)
4899 n->received_pong = GNUNET_NO;
4900 notify_clients_disconnect (&n->id);
4903 ats_modify_problem_state(ats, ATS_MODIFIED);
4905 /* clean up all plugins, cancel connections and pending transmissions */
4906 while (NULL != (rpos = n->plugins))
4908 n->plugins = rpos->next;
4909 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4910 while (rpos->addresses != NULL)
4912 peer_pos = rpos->addresses;
4913 rpos->addresses = peer_pos->next;
4914 if (peer_pos->connected == GNUNET_YES)
4916 GNUNET_STATISTICS_update (stats,
4917 gettext_noop ("# connected addresses"),
4920 peer_pos->connected = GNUNET_NO;
4922 if (GNUNET_YES == peer_pos->validated)
4923 GNUNET_STATISTICS_update (stats,
4924 gettext_noop ("# peer addresses considered valid"),
4927 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4929 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4930 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4932 GNUNET_free (peer_pos->ressources);
4933 peer_pos->ressources = NULL;
4934 GNUNET_free (peer_pos->quality);
4935 peer_pos->ressources = NULL;
4936 GNUNET_free (peer_pos);
4941 /* free all messages on the queue */
4942 while (NULL != (mq = n->messages_head))
4944 GNUNET_STATISTICS_update (stats,
4945 gettext_noop ("# bytes in message queue for other peers"),
4946 - (int64_t) mq->message_buf_size,
4948 GNUNET_STATISTICS_update (stats,
4949 gettext_noop ("# bytes discarded due to disconnect"),
4950 mq->message_buf_size,
4952 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4955 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4957 sizeof(struct GNUNET_PeerIdentity)));
4961 while (NULL != (mq = n->cont_head))
4964 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4967 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4969 sizeof(struct GNUNET_PeerIdentity)));
4973 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4975 GNUNET_SCHEDULER_cancel (n->timeout_task);
4976 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4978 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4980 GNUNET_SCHEDULER_cancel (n->retry_task);
4981 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4983 if (n->piter != NULL)
4985 GNUNET_PEERINFO_iterate_cancel (n->piter);
4986 GNUNET_STATISTICS_update (stats,
4987 gettext_noop ("# outstanding peerinfo iterate requests"),
4993 /* remove n from neighbours list */
4996 while ((npos != NULL) && (npos != n))
5001 GNUNET_assert (npos != NULL);
5003 neighbours = n->next;
5005 nprev->next = n->next;
5007 /* finally, free n itself */
5008 GNUNET_STATISTICS_update (stats,
5009 gettext_noop ("# active neighbours"),
5012 GNUNET_free_non_null (n->pre_connect_message_buffer);
5018 * We have received a PING message from someone. Need to send a PONG message
5019 * in response to the peer by any means necessary.
5022 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5023 const struct GNUNET_PeerIdentity *peer,
5024 struct Session *session,
5025 const char *sender_address,
5026 uint16_t sender_address_len)
5028 struct TransportPlugin *plugin = cls;
5029 struct SessionHeader *session_header = (struct SessionHeader*) session;
5030 struct TransportPingMessage *ping;
5031 struct TransportPongMessage *pong;
5032 struct NeighbourList *n;
5033 struct ReadyList *rl;
5034 struct ForeignAddressList *fal;
5035 struct OwnAddressList *oal;
5041 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5043 GNUNET_break_op (0);
5044 return GNUNET_SYSERR;
5047 ping = (struct TransportPingMessage *) message;
5048 if (0 != memcmp (&ping->target,
5049 plugin->env.my_identity,
5050 sizeof (struct GNUNET_PeerIdentity)))
5053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5054 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5056 (sender_address != NULL)
5057 ? a2s (plugin->short_name,
5058 (const struct sockaddr *)sender_address,
5061 GNUNET_i2s (&ping->target));
5063 return GNUNET_SYSERR;
5066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5067 "Processing `%s' from `%s'\n",
5069 (sender_address != NULL)
5070 ? a2s (plugin->short_name,
5071 (const struct sockaddr *)sender_address,
5075 GNUNET_STATISTICS_update (stats,
5076 gettext_noop ("# PING messages received"),
5079 addr = (const char*) &ping[1];
5080 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5081 slen = strlen (plugin->short_name) + 1;
5084 /* peer wants to confirm that we have an outbound connection to him */
5085 if (session == NULL)
5087 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5088 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5090 return GNUNET_SYSERR;
5092 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5093 1) it is NULL when we need to have a real value
5094 2) it is documented to be the address of the sender (source-IP), where
5095 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5099 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5100 a2s (plugin->short_name,
5102 sender_address_len),
5105 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5106 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5107 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5108 pong->purpose.size =
5109 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5111 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5112 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5113 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5114 pong->challenge = ping->challenge;
5115 pong->addrlen = htonl(sender_address_len + slen);
5118 sizeof(struct GNUNET_PeerIdentity));
5122 if ((sender_address!=NULL) && (sender_address_len > 0))
5123 memcpy (&((char*)&pong[1])[slen],
5125 sender_address_len);
5126 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5128 /* create / update cached sig */
5130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5131 "Creating PONG signature to indicate active connection.\n");
5133 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5134 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5135 GNUNET_assert (GNUNET_OK ==
5136 GNUNET_CRYPTO_rsa_sign (my_private_key,
5138 &session_header->pong_signature));
5142 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5144 memcpy (&pong->signature,
5145 &session_header->pong_signature,
5146 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5152 /* peer wants to confirm that this is one of our addresses */
5156 plugin->api->check_address (plugin->api->cls,
5160 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5161 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5162 a2s (plugin->short_name,
5167 oal = plugin->addresses;
5170 if ( (oal->addrlen == alen) &&
5177 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5178 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5179 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5180 pong->purpose.size =
5181 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5183 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5184 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5185 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5186 pong->challenge = ping->challenge;
5187 pong->addrlen = htonl(alen + slen);
5190 sizeof(struct GNUNET_PeerIdentity));
5191 memcpy (&pong[1], plugin->short_name, slen);
5192 memcpy (&((char*)&pong[1])[slen], addr, alen);
5193 if ( (oal != NULL) &&
5194 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5196 /* create / update cached sig */
5198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5199 "Creating PONG signature to indicate ownership.\n");
5201 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5202 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5203 GNUNET_assert (GNUNET_OK ==
5204 GNUNET_CRYPTO_rsa_sign (my_private_key,
5206 &oal->pong_signature));
5207 memcpy (&pong->signature,
5208 &oal->pong_signature,
5209 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5211 else if (oal == NULL)
5213 /* not using cache (typically DV-only) */
5214 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5215 GNUNET_assert (GNUNET_OK ==
5216 GNUNET_CRYPTO_rsa_sign (my_private_key,
5222 /* can used cached version */
5223 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5224 memcpy (&pong->signature,
5225 &oal->pong_signature,
5226 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5229 n = find_neighbour(peer);
5230 GNUNET_assert (n != NULL);
5231 did_pong = GNUNET_NO;
5232 /* first try reliable response transmission */
5236 fal = rl->addresses;
5239 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5242 ntohs (pong->header.size),
5243 TRANSPORT_PONG_PRIORITY,
5244 HELLO_VERIFICATION_TIMEOUT,
5251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5252 "Transmitted PONG to `%s' via reliable mechanism\n",
5255 GNUNET_STATISTICS_update (stats,
5256 gettext_noop ("# PONGs unicast via reliable transport"),
5262 did_pong = GNUNET_YES;
5267 /* no reliable method found, do multicast */
5268 GNUNET_STATISTICS_update (stats,
5269 gettext_noop ("# PONGs multicast to all available addresses"),
5275 fal = rl->addresses;
5278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5279 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5281 a2s (rl->plugin->short_name,
5284 rl->plugin->short_name);
5285 transmit_to_peer(NULL, fal,
5286 TRANSPORT_PONG_PRIORITY,
5287 HELLO_VERIFICATION_TIMEOUT,
5289 ntohs(pong->header.size),
5292 did_pong = GNUNET_YES;
5298 if (GNUNET_YES != did_pong)
5299 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5300 _("Could not send PONG to `%s': no address available\n"),
5307 * Function called by the plugin for each received message. Update
5308 * data volumes, possibly notify plugins about reducing the rate at
5309 * which they read from the socket and generally forward to our
5312 * @param cls the "struct TransportPlugin *" we gave to the plugin
5313 * @param peer (claimed) identity of the other peer
5314 * @param message the message, NULL if we only care about
5315 * learning about the delay until we should receive again
5316 * @param ats_data information for automatic transport selection
5317 * @param ats_count number of elements in ats not including 0-terminator
5318 * @param session identifier used for this session (can be NULL)
5319 * @param sender_address binary address of the sender (if observed)
5320 * @param sender_address_len number of bytes in sender_address
5321 * @return how long in ms the plugin should wait until receiving more data
5322 * (plugins that do not support this, can ignore the return value)
5324 static struct GNUNET_TIME_Relative
5325 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5326 const struct GNUNET_MessageHeader *message,
5327 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5329 struct Session *session,
5330 const char *sender_address,
5331 uint16_t sender_address_len)
5333 struct TransportPlugin *plugin = cls;
5334 struct ReadyList *service_context;
5335 struct ForeignAddressList *peer_address;
5337 struct NeighbourList *n;
5338 struct GNUNET_TIME_Relative ret;
5342 if (0 == memcmp (peer,
5344 sizeof (struct GNUNET_PeerIdentity)))
5346 /* refuse to receive from myself */
5348 return GNUNET_TIME_UNIT_FOREVER_REL;
5350 if (is_blacklisted (peer, plugin))
5351 return GNUNET_TIME_UNIT_FOREVER_REL;
5352 n = find_neighbour (peer);
5354 n = setup_new_neighbour (peer, GNUNET_YES);
5355 service_context = n->plugins;
5356 while ((service_context != NULL) && (plugin != service_context->plugin))
5357 service_context = service_context->next;
5358 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5359 peer_address = NULL;
5362 for (c=0; c<ats_count; c++)
5363 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5364 distance = ntohl(ats_data[c].value);
5367 if (message != NULL)
5369 if ( (session != NULL) ||
5370 (sender_address != NULL) )
5371 peer_address = add_peer_address (n,
5375 sender_address_len);
5376 if (peer_address != NULL)
5378 update_addr_ats(peer_address, ats_data, ats_count);
5379 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5381 peer_address->distance = distance;
5382 if (GNUNET_YES == peer_address->validated)
5384 mark_address_connected (peer_address);
5385 schedule_next_ping (peer_address);
5390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5391 "New address is unvalidated, trying to validate it now\n");
5393 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5395 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5396 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5398 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5401 peer_address->timeout
5402 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5404 /* update traffic received amount ... */
5405 msize = ntohs (message->size);
5407 GNUNET_STATISTICS_update (stats,
5408 gettext_noop ("# bytes received from other peers"),
5411 n->distance = distance;
5413 GNUNET_TIME_relative_to_absolute
5414 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5415 GNUNET_SCHEDULER_cancel (n->timeout_task);
5417 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5418 &neighbour_timeout_task, n);
5419 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5421 /* dropping message due to frequent inbound volume violations! */
5422 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5423 GNUNET_ERROR_TYPE_BULK,
5425 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5426 n->in_tracker.available_bytes_per_s__,
5427 n->quota_violation_count);
5428 GNUNET_STATISTICS_update (stats,
5429 gettext_noop ("# bandwidth quota violations by other peers"),
5432 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5434 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5435 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5438 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5439 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5440 /* Force ressource and quality update */
5441 if ((value == 4) && (ats != NULL))
5442 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5443 /* Force cost update */
5444 if ((value == 3) && (ats != NULL))
5445 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5446 /* Force quality update */
5447 if ((value == 2) && (ats != NULL))
5448 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5449 /* Force full rebuild */
5450 if ((value == 1) && (ats != NULL))
5451 ats_modify_problem_state(ats, ATS_MODIFIED);
5456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5457 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5458 ntohs (message->type),
5459 ntohs (message->size),
5462 switch (ntohs (message->type))
5464 case GNUNET_MESSAGE_TYPE_HELLO:
5465 GNUNET_STATISTICS_update (stats,
5466 gettext_noop ("# HELLO messages received from other peers"),
5469 process_hello (plugin, message);
5471 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5472 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5473 if (GNUNET_YES != n->received_pong)
5474 transmit_plain_ping (n);
5476 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5477 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5479 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5482 handle_payload_message (message, n);
5486 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5487 if (ret.rel_value > 0)
5490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5491 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5492 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5493 (unsigned int) n->in_tracker.available_bytes_per_s__,
5494 (unsigned long long) ret.rel_value);
5496 GNUNET_STATISTICS_update (stats,
5497 gettext_noop ("# ms throttling suggested"),
5498 (int64_t) ret.rel_value,
5505 * Handle START-message. This is the first message sent to us
5506 * by any client which causes us to add it to our list.
5508 * @param cls closure (always NULL)
5509 * @param client identification of the client
5510 * @param message the actual message
5513 handle_start (void *cls,
5514 struct GNUNET_SERVER_Client *client,
5515 const struct GNUNET_MessageHeader *message)
5517 const struct StartMessage *start;
5518 struct TransportClient *c;
5519 struct ConnectInfoMessage * cim;
5520 struct NeighbourList *n;
5524 start = (const struct StartMessage*) message;
5526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5527 "Received `%s' request from client\n", "START");
5532 if (c->client == client)
5534 /* client already on our list! */
5536 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5541 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5542 (0 != memcmp (&start->self,
5544 sizeof (struct GNUNET_PeerIdentity))) )
5546 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5547 _("Rejecting control connection from peer `%s', which is not me!\n"),
5548 GNUNET_i2s (&start->self));
5549 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5552 c = GNUNET_malloc (sizeof (struct TransportClient));
5556 if (our_hello != NULL)
5559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5560 "Sending our own `%s' to new client\n", "HELLO");
5562 transmit_to_client (c,
5563 (const struct GNUNET_MessageHeader *) our_hello,
5565 /* tell new client about all existing connections */
5567 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5568 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5572 cim = GNUNET_malloc (size);
5573 cim->header.size = htons (size);
5574 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5575 cim->ats_count = htonl(ats_count);
5576 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5577 (&(cim->ats))[2].value = htonl (0);
5581 if (GNUNET_YES == n->received_pong)
5583 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5584 (&cim->ats)[0].value = htonl (n->distance);
5585 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5586 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5588 transmit_to_client (c, &cim->header, GNUNET_NO);
5596 #if DEBUG_TRANSPORT_HELLO
5597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5598 "No HELLO created yet, will transmit HELLO to client later!\n");
5602 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5607 * Handle HELLO-message.
5609 * @param cls closure (always NULL)
5610 * @param client identification of the client
5611 * @param message the actual message
5614 handle_hello (void *cls,
5615 struct GNUNET_SERVER_Client *client,
5616 const struct GNUNET_MessageHeader *message)
5620 GNUNET_STATISTICS_update (stats,
5621 gettext_noop ("# HELLOs received from clients"),
5624 ret = process_hello (NULL, message);
5625 GNUNET_SERVER_receive_done (client, ret);
5630 * Closure for 'transmit_client_message'; followed by
5631 * 'msize' bytes of the actual message.
5633 struct TransmitClientMessageContext
5636 * Client on whom's behalf we are sending.
5638 struct GNUNET_SERVER_Client *client;
5641 * Timeout for the transmission.
5643 struct GNUNET_TIME_Absolute timeout;
5651 * Size of the message in bytes.
5658 * Schedule transmission of a message we got from a client to a peer.
5660 * @param cls the 'struct TransmitClientMessageContext*'
5661 * @param n destination, or NULL on error (in that case, drop the message)
5664 transmit_client_message (void *cls,
5665 struct NeighbourList *n)
5667 struct TransmitClientMessageContext *tcmc = cls;
5668 struct TransportClient *tc;
5671 while ((tc != NULL) && (tc->client != tcmc->client))
5676 transmit_to_peer (tc, NULL, tcmc->priority,
5677 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5679 tcmc->msize, GNUNET_NO, n);
5681 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5682 GNUNET_SERVER_client_drop (tcmc->client);
5688 * Handle SEND-message.
5690 * @param cls closure (always NULL)
5691 * @param client identification of the client
5692 * @param message the actual message
5695 handle_send (void *cls,
5696 struct GNUNET_SERVER_Client *client,
5697 const struct GNUNET_MessageHeader *message)
5699 const struct OutboundMessage *obm;
5700 const struct GNUNET_MessageHeader *obmm;
5701 struct TransmitClientMessageContext *tcmc;
5705 size = ntohs (message->size);
5707 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5710 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5713 GNUNET_STATISTICS_update (stats,
5714 gettext_noop ("# payload received for other peers"),
5717 obm = (const struct OutboundMessage *) message;
5718 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5719 msize = size - sizeof (struct OutboundMessage);
5721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5722 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5723 "SEND", GNUNET_i2s (&obm->peer),
5727 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5728 tcmc->client = client;
5729 tcmc->priority = ntohl (obm->priority);
5730 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5731 tcmc->msize = msize;
5732 /* FIXME: this memcpy can be up to 7% of our total runtime */
5733 memcpy (&tcmc[1], obmm, msize);
5734 GNUNET_SERVER_client_keep (client);
5735 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5736 &transmit_client_message,
5742 * Handle request connect message
5744 * @param cls closure (always NULL)
5745 * @param client identification of the client
5746 * @param message the actual message
5749 handle_request_connect (void *cls,
5750 struct GNUNET_SERVER_Client *client,
5751 const struct GNUNET_MessageHeader *message)
5753 const struct TransportRequestConnectMessage *trcm =
5754 (const struct TransportRequestConnectMessage *) message;
5756 GNUNET_STATISTICS_update (stats,
5757 gettext_noop ("# REQUEST CONNECT messages received"),
5761 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5762 "Received a request connect message for peer `%s'\n",
5763 GNUNET_i2s(&trcm->peer));
5765 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5767 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5772 * Handle SET_QUOTA-message.
5774 * @param cls closure (always NULL)
5775 * @param client identification of the client
5776 * @param message the actual message
5779 handle_set_quota (void *cls,
5780 struct GNUNET_SERVER_Client *client,
5781 const struct GNUNET_MessageHeader *message)
5783 const struct QuotaSetMessage *qsm =
5784 (const struct QuotaSetMessage *) message;
5785 struct NeighbourList *n;
5787 GNUNET_STATISTICS_update (stats,
5788 gettext_noop ("# SET QUOTA messages received"),
5791 n = find_neighbour (&qsm->peer);
5794 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5795 GNUNET_STATISTICS_update (stats,
5796 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5803 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5805 (unsigned int) ntohl (qsm->quota.value__),
5806 (unsigned int) n->in_tracker.available_bytes_per_s__,
5807 GNUNET_i2s (&qsm->peer));
5809 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5811 if (0 == ntohl (qsm->quota.value__))
5814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5815 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5818 GNUNET_STATISTICS_update (stats,
5819 gettext_noop ("# disconnects due to quota of 0"),
5822 disconnect_neighbour (n, GNUNET_NO);
5824 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5829 * Take the given address and append it to the set of results sent back to
5832 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5833 * @param address the resolved name, NULL to indicate the last response
5836 transmit_address_to_client (void *cls, const char *address)
5838 struct GNUNET_SERVER_TransmitContext *tc = cls;
5841 if (NULL != address)
5843 slen = strlen (address) + 1;
5844 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5845 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5849 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5855 * Handle AddressLookup-message.
5857 * @param cls closure (always NULL)
5858 * @param client identification of the client
5859 * @param message the actual message
5862 handle_address_lookup (void *cls,
5863 struct GNUNET_SERVER_Client *client,
5864 const struct GNUNET_MessageHeader *message)
5866 const struct AddressLookupMessage *alum;
5867 struct TransportPlugin *lsPlugin;
5868 const char *nameTransport;
5869 const char *address;
5871 struct GNUNET_SERVER_TransmitContext *tc;
5872 struct GNUNET_TIME_Absolute timeout;
5873 struct GNUNET_TIME_Relative rtimeout;
5876 size = ntohs (message->size);
5877 if (size < sizeof (struct AddressLookupMessage))
5879 GNUNET_break_op (0);
5880 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5883 alum = (const struct AddressLookupMessage *) message;
5884 uint32_t addressLen = ntohl (alum->addrlen);
5885 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5887 GNUNET_break_op (0);
5888 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5891 address = (const char *) &alum[1];
5892 nameTransport = (const char *) &address[addressLen];
5894 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5896 GNUNET_break_op (0);
5897 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5900 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5901 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5902 numeric = ntohl (alum->numeric_only);
5903 lsPlugin = find_transport (nameTransport);
5904 if (NULL == lsPlugin)
5906 tc = GNUNET_SERVER_transmit_context_create (client);
5907 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5908 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5909 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5912 GNUNET_SERVER_disable_receive_done_warning (client);
5913 tc = GNUNET_SERVER_transmit_context_create (client);
5914 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5916 address, addressLen,
5919 &transmit_address_to_client, tc);
5923 * Handle PeerAddressLookupMessage.
5925 * @param cls closure (always NULL)
5926 * @param client identification of the client
5927 * @param message the actual message
5930 handle_peer_address_lookup (void *cls,
5931 struct GNUNET_SERVER_Client *client,
5932 const struct GNUNET_MessageHeader *message)
5934 const struct PeerAddressLookupMessage *peer_address_lookup;
5935 struct NeighbourList *neighbor_iterator;
5936 struct ReadyList *ready_iterator;
5937 struct ForeignAddressList *foreign_address_iterator;
5938 struct TransportPlugin *transport_plugin;
5941 struct GNUNET_SERVER_TransmitContext *tc;
5942 struct GNUNET_TIME_Absolute timeout;
5943 struct GNUNET_TIME_Relative rtimeout;
5946 size = ntohs (message->size);
5947 if (size < sizeof (struct PeerAddressLookupMessage))
5949 GNUNET_break_op (0);
5950 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5953 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5955 timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5956 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5958 neighbor_iterator = neighbours;
5959 while (neighbor_iterator != NULL)
5961 if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5963 neighbor_iterator = neighbor_iterator->next;
5966 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5967 if (neighbor_iterator == NULL)
5970 tc = GNUNET_SERVER_transmit_context_create (client);
5971 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5972 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5973 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5977 ready_iterator = neighbor_iterator->plugins;
5978 GNUNET_SERVER_disable_receive_done_warning (client);
5979 tc = GNUNET_SERVER_transmit_context_create (client);
5980 while(ready_iterator != NULL)
5982 foreign_address_iterator = ready_iterator->addresses;
5983 while (foreign_address_iterator != NULL)
5985 transport_plugin = foreign_address_iterator->ready_list->plugin;
5986 if (foreign_address_iterator->addr != NULL)
5988 GNUNET_asprintf (&addr_buf, "%s --- %s",
5989 a2s (transport_plugin->short_name,
5990 foreign_address_iterator->addr,
5991 foreign_address_iterator->addrlen),
5992 (foreign_address_iterator->connected
5993 == GNUNET_YES) ? "CONNECTED"
5995 (foreign_address_iterator->validated
5996 == GNUNET_YES) ? "VALIDATED"
5998 transmit_address_to_client(tc, addr_buf);
5999 GNUNET_free (addr_buf);
6001 else if (foreign_address_iterator->addrlen == 0)
6003 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
6004 (foreign_address_iterator->connected
6005 == GNUNET_YES) ? "CONNECTED"
6007 (foreign_address_iterator->validated
6008 == GNUNET_YES) ? "VALIDATED"
6010 transmit_address_to_client (tc, addr_buf);
6011 GNUNET_free (addr_buf);
6014 foreign_address_iterator = foreign_address_iterator->next;
6016 ready_iterator = ready_iterator->next;
6018 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6019 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6020 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6024 * Handle AddressIterateMessage
6026 * @param cls closure (always NULL)
6027 * @param client identification of the client
6028 * @param message the actual message
6031 handle_address_iterate (void *cls,
6032 struct GNUNET_SERVER_Client *client,
6033 const struct GNUNET_MessageHeader *message)
6035 struct NeighbourList *neighbor_iterator;
6036 struct ReadyList *ready_iterator;
6037 struct ForeignAddressList *foreign_address_iterator;
6038 struct TransportPlugin *transport_plugin;
6041 struct GNUNET_SERVER_TransmitContext *tc;
6044 size = ntohs (message->size);
6045 if (size < sizeof (struct AddressIterateMessage))
6047 GNUNET_break_op (0);
6048 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6051 GNUNET_SERVER_disable_receive_done_warning (client);
6052 tc = GNUNET_SERVER_transmit_context_create (client);
6054 neighbor_iterator = neighbours;
6055 while (neighbor_iterator != NULL)
6057 ready_iterator = neighbor_iterator->plugins;
6058 while (ready_iterator != NULL)
6060 foreign_address_iterator = ready_iterator->addresses;
6061 while (foreign_address_iterator != NULL)
6063 transport_plugin = foreign_address_iterator->ready_list->plugin;
6064 if (foreign_address_iterator->addr != NULL)
6066 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6067 GNUNET_i2s(&neighbor_iterator->id),
6068 a2s (transport_plugin->short_name,
6069 foreign_address_iterator->addr,
6070 foreign_address_iterator->addrlen),
6071 (foreign_address_iterator->connected
6072 == GNUNET_YES) ? "CONNECTED"
6074 (foreign_address_iterator->validated
6075 == GNUNET_YES) ? "VALIDATED"
6077 transmit_address_to_client (tc, addr_buf);
6078 GNUNET_free (addr_buf);
6080 else if (foreign_address_iterator->addrlen == 0)
6082 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6083 GNUNET_i2s (&neighbor_iterator->id),
6085 (foreign_address_iterator->connected
6086 == GNUNET_YES) ? "CONNECTED"
6088 (foreign_address_iterator->validated
6089 == GNUNET_YES) ? "VALIDATED"
6091 transmit_address_to_client (tc, addr_buf);
6092 GNUNET_free (addr_buf);
6095 foreign_address_iterator = foreign_address_iterator->next;
6097 ready_iterator = ready_iterator->next;
6099 neighbor_iterator = neighbor_iterator->next;
6102 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6103 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6104 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6109 * Setup the environment for this plugin.
6112 create_environment (struct TransportPlugin *plug)
6114 plug->env.cfg = cfg;
6115 plug->env.my_identity = &my_identity;
6116 plug->env.our_hello = &our_hello;
6117 plug->env.cls = plug;
6118 plug->env.receive = &plugin_env_receive;
6119 plug->env.notify_address = &plugin_env_notify_address;
6120 plug->env.session_end = &plugin_env_session_end;
6121 plug->env.max_connections = max_connect_per_transport;
6122 plug->env.stats = stats;
6127 * Start the specified transport (load the plugin).
6130 start_transport (struct GNUNET_SERVER_Handle *server,
6133 struct TransportPlugin *plug;
6136 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6137 _("Loading `%s' transport plugin\n"), name);
6138 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6139 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6140 create_environment (plug);
6141 plug->short_name = GNUNET_strdup (name);
6142 plug->lib_name = libname;
6143 plug->next = plugins;
6145 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6146 if (plug->api == NULL)
6148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6149 _("Failed to load transport plugin for `%s'\n"), name);
6150 GNUNET_free (plug->short_name);
6151 plugins = plug->next;
6152 GNUNET_free (libname);
6159 * Called whenever a client is disconnected. Frees our
6160 * resources associated with that client.
6162 * @param cls closure
6163 * @param client identification of the client
6166 client_disconnect_notification (void *cls,
6167 struct GNUNET_SERVER_Client *client)
6169 struct TransportClient *pos;
6170 struct TransportClient *prev;
6171 struct ClientMessageQueueEntry *mqe;
6172 struct Blacklisters *bl;
6173 struct BlacklistCheck *bc;
6174 struct NeighbourList *n;
6175 struct MessageQueue *mq;
6180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6181 "Client disconnected, cleaning up.\n");
6183 /* clean up blacklister */
6187 if (bl->client == client)
6192 if (bc->bl_pos == bl)
6194 bc->bl_pos = bl->next;
6197 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6200 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6201 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6207 GNUNET_CONTAINER_DLL_remove (bl_head,
6210 GNUNET_SERVER_client_drop (bl->client);
6216 /* clean up 'normal' clients */
6219 while ((pos != NULL) && (pos->client != client))
6226 while (NULL != (mqe = pos->message_queue_head))
6228 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6229 pos->message_queue_tail,
6231 pos->message_count--;
6234 for (n = neighbours; n != NULL; n = n->next)
6236 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6238 if (mq->client == pos)
6239 mq->client = NULL; /* do not use anymore! */
6243 clients = pos->next;
6245 prev->next = pos->next;
6246 if (GNUNET_YES == pos->tcs_pending)
6251 if (pos->th != NULL)
6253 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6256 GNUNET_break (0 == pos->message_count);
6262 * Function called when the service shuts down. Unloads our plugins
6263 * and cancels pending validations.
6265 * @param cls closure, unused
6266 * @param tc task context (unused)
6269 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6271 struct TransportPlugin *plug;
6272 struct OwnAddressList *al;
6273 struct CheckHelloValidatedContext *chvc;
6275 shutdown_in_progress = GNUNET_YES;
6276 while (neighbours != NULL)
6279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6280 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6283 disconnect_neighbour (neighbours, GNUNET_NO);
6286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6287 "Transport service is unloading plugins...\n");
6289 while (NULL != (plug = plugins))
6291 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6293 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6294 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6296 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6297 GNUNET_free (plug->lib_name);
6298 GNUNET_free (plug->short_name);
6299 while (NULL != (al = plug->addresses))
6301 plug->addresses = al->next;
6304 plugins = plug->next;
6307 if (my_private_key != NULL)
6308 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6309 GNUNET_free_non_null (our_hello);
6311 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6314 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6315 validation_map = NULL;
6318 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6320 GNUNET_SCHEDULER_cancel(ats_task);
6321 ats_task = GNUNET_SCHEDULER_NO_TASK;
6328 /* free 'chvc' data structure */
6329 while (NULL != (chvc = chvc_head))
6331 chvc_head = chvc->next;
6332 if (chvc->piter != NULL)
6334 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6335 GNUNET_STATISTICS_update (stats,
6336 gettext_noop ("# outstanding peerinfo iterate requests"),
6343 GNUNET_assert (chvc->ve_count == 0);
6350 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6353 if (peerinfo != NULL)
6355 GNUNET_PEERINFO_disconnect (peerinfo);
6358 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6360 GNUNET_SCHEDULER_cancel (hello_task);
6361 hello_task = GNUNET_SCHEDULER_NO_TASK;
6363 /* Can we assume those are gone by now, or do we need to clean up
6365 GNUNET_break (bl_head == NULL);
6366 GNUNET_break (bc_head == NULL);
6370 void ats_result_cb ()
6372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6373 "ATS Result callback\n");
6378 create_ats_information ( struct ATS_peer **p,
6380 struct ATS_mechanism ** m,
6384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6385 "ATS requires clean address information\n");
6387 struct ATS_mechanism * mechanisms;
6388 struct ATS_peer *peers;
6391 struct NeighbourList *next = neighbours;
6395 int found_addresses = GNUNET_NO;
6396 struct ReadyList *r_next = next->plugins;
6397 while (r_next != NULL)
6399 struct ForeignAddressList * a_next = r_next->addresses;
6400 while (a_next != NULL)
6403 found_addresses = GNUNET_YES;
6404 a_next = a_next->next;
6406 r_next = r_next->next;
6408 if (found_addresses) c_peers++;
6413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6414 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6417 if ((c_peers == 0) && (c_mechs == 0))
6426 mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6427 peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6435 int found_addresses = GNUNET_NO;
6436 struct ReadyList *r_next = next->plugins;
6437 while (r_next != NULL)
6439 struct ForeignAddressList * a_next = r_next->addresses;
6440 while (a_next != NULL)
6442 if (found_addresses == GNUNET_NO)
6444 peers[c_peers].peer = next->id;
6445 peers[c_peers].m_head = NULL;
6446 peers[c_peers].m_tail = NULL;
6447 peers[c_peers].f = 1.0 / c_mechs;
6449 mechanisms[c_mechs].addr = a_next;
6450 mechanisms[c_mechs].col_index = c_mechs;
6451 mechanisms[c_mechs].peer = &peers[c_peers];
6452 mechanisms[c_mechs].next = NULL;
6453 mechanisms[c_mechs].plugin = r_next->plugin;
6454 mechanisms[c_mechs].ressources = a_next->ressources;
6455 mechanisms[c_mechs].quality = a_next->quality;
6456 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6457 peers[c_peers].m_tail,
6458 &mechanisms[c_mechs]);
6459 found_addresses = GNUNET_YES;
6461 a_next = a_next->next;
6463 r_next = r_next->next;
6465 if (found_addresses == GNUNET_YES)
6479 schedule_ats (void *cls,
6480 const struct GNUNET_SCHEDULER_TaskContext *tc)
6482 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6486 ats_task = GNUNET_SCHEDULER_NO_TASK;
6487 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6490 if (shutdown_in_progress == GNUNET_YES)
6493 struct GNUNET_TIME_Relative delta =
6494 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6495 if (delta.rel_value < ats_minimum_interval.rel_value)
6498 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6499 "Minimum time between cycles not reached\n");
6505 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6508 ats_calculate_bandwidth_distribution (ats);
6510 last_ats_execution = GNUNET_TIME_absolute_get();
6512 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6513 &schedule_ats, ats);
6516 struct ForeignAddressList * get_preferred_ats_address (
6517 struct NeighbourList *n)
6519 // TODO get ATS prefered address
6520 return find_ready_address(n);
6524 * Initiate transport service.
6526 * @param cls closure
6527 * @param server the initialized server
6528 * @param c configuration to use
6532 struct GNUNET_SERVER_Handle *server,
6533 const struct GNUNET_CONFIGURATION_Handle *c)
6535 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6536 {&handle_start, NULL,
6537 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6538 {&handle_hello, NULL,
6539 GNUNET_MESSAGE_TYPE_HELLO, 0},
6540 {&handle_send, NULL,
6541 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6542 {&handle_request_connect, NULL,
6543 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6544 {&handle_set_quota, NULL,
6545 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6546 {&handle_address_lookup, NULL,
6547 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6549 {&handle_peer_address_lookup, NULL,
6550 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6552 {&handle_address_iterate, NULL,
6553 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6555 {&handle_blacklist_init, NULL,
6556 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6557 {&handle_blacklist_reply, NULL,
6558 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6564 unsigned long long tneigh;
6567 shutdown_in_progress = GNUNET_NO;
6569 stats = GNUNET_STATISTICS_create ("transport", cfg);
6570 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6571 /* parse configuration */
6573 GNUNET_CONFIGURATION_get_value_number (c,
6578 GNUNET_CONFIGURATION_get_value_filename (c,
6580 "HOSTKEY", &keyfile)))
6582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6584 ("Transport service is lacking key configuration settings. Exiting.\n"));
6585 GNUNET_SCHEDULER_shutdown ();
6588 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6591 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6592 validation_map = NULL;
6596 max_connect_per_transport = (uint32_t) tneigh;
6597 peerinfo = GNUNET_PEERINFO_connect (cfg);
6598 if (peerinfo == NULL)
6600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6601 _("Could not access PEERINFO service. Exiting.\n"));
6602 GNUNET_SCHEDULER_shutdown ();
6605 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6608 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6609 validation_map = NULL;
6610 GNUNET_free (keyfile);
6613 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6614 GNUNET_free (keyfile);
6615 if (my_private_key == NULL)
6617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6619 ("Transport service could not access hostkey. Exiting.\n"));
6620 GNUNET_SCHEDULER_shutdown ();
6623 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6626 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6627 validation_map = NULL;
6630 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6631 GNUNET_CRYPTO_hash (&my_public_key,
6632 sizeof (my_public_key), &my_identity.hashPubKey);
6633 /* setup notification */
6634 GNUNET_SERVER_disconnect_notify (server,
6635 &client_disconnect_notification, NULL);
6636 /* load plugins... */
6639 GNUNET_CONFIGURATION_get_value_string (c,
6640 "TRANSPORT", "PLUGINS", &plugs))
6642 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6643 _("Starting transport plugins `%s'\n"), plugs);
6644 pos = strtok (plugs, " ");
6647 start_transport (server, pos);
6649 pos = strtok (NULL, " ");
6651 GNUNET_free (plugs);
6653 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6654 &shutdown_task, NULL);
6658 /* Initializing ATS */
6661 unsigned long long value;
6666 int v_b_min = 64000;
6670 ats_minimum_interval = ATS_MIN_INTERVAL;
6671 ats_regular_interval = ATS_EXEC_INTERVAL;
6673 /* loading cost ressources */
6674 for (co=0; co<available_ressources; co++)
6676 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6677 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6679 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6686 "Found ressource cost: [%s] = %llu\n",
6689 ressources[co].c_max = value;
6692 GNUNET_free (section);
6693 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6694 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6696 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6703 "Found ressource cost: [%s] = %llu\n",
6706 ressources[co].c_min = value;
6709 GNUNET_free (section);
6712 ats = ats_init (D, U, R, v_b_min, v_n_min,
6713 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6714 create_ats_information,
6718 int log_problem = GNUNET_NO;
6719 int log_solution = GNUNET_NO;
6720 int overwrite_dump = GNUNET_NO;
6721 int minimum_peers = 0;
6722 int minimum_addresses = 0;
6724 log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6727 log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6730 overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6734 GNUNET_CONFIGURATION_get_value_number(cfg,
6738 minimum_peers = (int) value;
6740 GNUNET_CONFIGURATION_get_value_number(cfg,
6744 minimum_addresses = (int) value;
6745 GNUNET_break (GNUNET_OK ==
6746 GNUNET_CONFIGURATION_get_value_time (cfg,
6748 "ATS_EXEC_INTERVAL",
6749 &ats_regular_interval));
6750 GNUNET_break (GNUNET_OK ==
6751 GNUNET_CONFIGURATION_get_value_time (cfg,
6754 &ats_minimum_interval));
6756 ats_set_logging_options (ats,
6765 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6771 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6772 _("Transport service ready.\n"));
6774 /* If we have a blacklist file, read from it */
6775 read_blacklist_file(cfg);
6776 /* process client requests */
6777 GNUNET_SERVER_add_handlers (server, handlers);
6782 * The main function for the transport service.
6784 * @param argc number of arguments from the command line
6785 * @param argv command line arguments
6786 * @return 0 ok, 1 on error
6789 main (int argc, char *const *argv)
6791 a2s (NULL, NULL, 0); /* make compiler happy */
6792 return (GNUNET_OK ==
6793 GNUNET_SERVICE_run (argc,
6796 GNUNET_SERVICE_OPTION_NONE,
6797 &run, NULL)) ? 0 : 1;
6800 /* end of gnunet-service-transport.c */