2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "gnunet-service-transport_ats.h"
41 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_INBOUND GNUNET_NO
54 * Should we do some additional checks (to validate behavior
57 #define EXTRA_CHECKS GNUNET_YES
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
71 #define MAX_PENDING (128 * 1024)
74 * Size of the per-transport blacklist hash maps.
76 #define TRANSPORT_BLACKLIST_HT_SIZE 16
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
83 #define MAX_CONNECT_RETRY 3
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
90 #define MAX_HELLO_LOAD 4
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
96 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
106 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
115 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
118 * Priority to use for PONG messages.
120 #define TRANSPORT_PONG_PRIORITY 4
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
126 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
133 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
141 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * List of addresses of other peers
146 struct ForeignAddressList
149 * This is a linked list.
151 struct ForeignAddressList *next;
154 * Which ready list does this entry belong to.
156 struct ReadyList *ready_list;
159 * How long until we auto-expire this address (unless it is
160 * re-confirmed by the transport)?
162 struct GNUNET_TIME_Absolute expires;
165 * Task used to re-validate addresses, updates latencies and
168 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176 * Session (or NULL if no valid session currently exists or if the
177 * plugin does not use sessions).
179 struct Session *session;
181 struct ATS_ressource_entry * ressources;
183 struct ATS_quality_entry * quality;
186 * What was the last latency observed for this address, plugin and peer?
188 struct GNUNET_TIME_Relative latency;
191 * If we did not successfully transmit a message to the given peer
192 * via this connection during the specified time, we should consider
193 * the connection to be dead. This is used in the case that a TCP
194 * transport simply stalls writing to the stream but does not
195 * formerly get a signal that the other peer died.
197 struct GNUNET_TIME_Absolute timeout;
200 * How often have we tried to connect using this plugin? Used to
201 * discriminate against addresses that do not work well.
202 * FIXME: not yet used, but should be!
204 unsigned int connect_attempts;
207 * DV distance to this peer (1 if no DV is used).
208 * FIXME: need to set this from transport plugins!
218 * Have we ever estimated the latency of this address? Used to
219 * ensure that the first time we add an address, we immediately
225 * Are we currently connected via this address? The first time we
226 * successfully transmit or receive data to a peer via a particular
227 * address, we set this to GNUNET_YES. If we later get an error
228 * (disconnect notification, transmission failure, timeout), we set
229 * it back to GNUNET_NO.
234 * Is this plugin currently busy transmitting to the specific target?
235 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
236 * messages do not count as 'in transmit'.
241 * Has this address been validated yet?
249 * Entry in linked list of network addresses for ourselves. Also
250 * includes a cached signature for 'struct TransportPongMessage's.
252 struct OwnAddressList
255 * This is a linked list.
257 struct OwnAddressList *next;
260 * How long until the current signature expires? (ZERO if the
261 * signature was never created).
263 struct GNUNET_TIME_Absolute pong_sig_expires;
266 * Signature for a 'struct TransportPongMessage' for this address.
268 struct GNUNET_CRYPTO_RsaSignature pong_signature;
279 * Entry in linked list of all of our plugins.
281 struct TransportPlugin
284 * This is a linked list.
286 struct TransportPlugin *next;
289 * API of the transport as returned by the plugin's
290 * initialization function.
292 struct GNUNET_TRANSPORT_PluginFunctions *api;
295 * Short name for the plugin (i.e. "tcp").
300 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
305 * List of our known addresses for this transport.
307 struct OwnAddressList *addresses;
310 * Environment this transport service is using
313 struct GNUNET_TRANSPORT_PluginEnvironment env;
316 * ID of task that is used to clean up expired addresses.
318 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
321 * Set to GNUNET_YES if we need to scrap the existing list of
322 * "addresses" and start fresh when we receive the next address
323 * update from a transport. Set to GNUNET_NO if we should just add
324 * the new address to the list and wait for the commit call.
328 struct ATS_plugin * rc;
331 * Hashmap of blacklisted peers for this particular transport.
333 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
336 struct NeighbourList;
339 * For each neighbour we keep a list of messages
340 * that we still want to transmit to the neighbour.
346 * This is a doubly linked list.
348 struct MessageQueue *next;
351 * This is a doubly linked list.
353 struct MessageQueue *prev;
356 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
357 * stuck together in memory. Allocated at the end of this struct.
359 const char *message_buf;
362 * Size of the message buf
364 size_t message_buf_size;
367 * Client responsible for queueing the message;
368 * used to check that a client has no two messages
369 * pending for the same target. Can be NULL.
371 struct TransportClient *client;
374 * Using which specific address should we send this message?
376 struct ForeignAddressList *specific_address;
379 * Peer ID of the Neighbour this entry belongs to.
381 struct GNUNET_PeerIdentity neighbour_id;
384 * Plugin that we used for the transmission.
385 * NULL until we scheduled a transmission.
387 struct TransportPlugin *plugin;
390 * At what time should we fail?
392 struct GNUNET_TIME_Absolute timeout;
395 * Internal message of the transport system that should not be
396 * included in the usual SEND-SEND_OK transmission confirmation
397 * traffic management scheme. Typically, "internal_msg" will
398 * be set whenever "client" is NULL (but it is not strictly
404 * How important is the message?
406 unsigned int priority;
412 * For a given Neighbour, which plugins are available
413 * to talk to this peer and what are their costs?
418 * This is a linked list.
420 struct ReadyList *next;
423 * Which of our transport plugins does this entry
426 struct TransportPlugin *plugin;
429 * Transport addresses, latency, and readiness for
430 * this particular plugin.
432 struct ForeignAddressList *addresses;
435 * To which neighbour does this ready list belong to?
437 struct NeighbourList *neighbour;
442 * Entry in linked list of all of our current neighbours.
448 * This is a linked list.
450 struct NeighbourList *next;
453 * Which of our transports is connected to this peer
454 * and what is their status?
456 struct ReadyList *plugins;
459 * Head of list of messages we would like to send to this peer;
460 * must contain at most one message per client.
462 struct MessageQueue *messages_head;
465 * Tail of list of messages we would like to send to this peer; must
466 * contain at most one message per client.
468 struct MessageQueue *messages_tail;
471 * Head of list of messages of messages we expected the continuation
472 * to be called to destroy the message
474 struct MessageQueue *cont_head;
477 * Tail of list of messages of messages we expected the continuation
478 * to be called to destroy the message
480 struct MessageQueue *cont_tail;
483 * Buffer for at most one payload message used when we receive
484 * payload data before our PING-PONG has succeeded. We then
485 * store such messages in this intermediary buffer until the
486 * connection is fully up.
488 struct GNUNET_MessageHeader *pre_connect_message_buffer;
491 * Context for peerinfo iteration.
492 * NULL after we are done processing peerinfo's information.
494 struct GNUNET_PEERINFO_IteratorContext *piter;
497 * Public key for this peer. Valid only if the respective flag is set below.
499 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
502 * Identity of this neighbour.
504 struct GNUNET_PeerIdentity id;
507 * ID of task scheduled to run when this peer is about to
508 * time out (will free resources associated with the peer).
510 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
513 * ID of task scheduled to run when we should retry transmitting
514 * the head of the message queue. Actually triggered when the
515 * transmission is timing out (we trigger instantly when we have
516 * a chance of success).
518 GNUNET_SCHEDULER_TaskIdentifier retry_task;
521 * How long until we should consider this peer dead
522 * (if we don't receive another message in the
525 struct GNUNET_TIME_Absolute peer_timeout;
528 * Tracker for inbound bandwidth.
530 struct GNUNET_BANDWIDTH_Tracker in_tracker;
533 * The latency we have seen for this particular address for
534 * this particular peer. This latency may have been calculated
535 * over multiple transports. This value reflects how long it took
536 * us to receive a response when SENDING via this particular
537 * transport/neighbour/address combination!
539 * FIXME: we need to periodically send PINGs to update this
540 * latency (at least more often than the current "huge" (11h?)
543 struct GNUNET_TIME_Relative latency;
546 * How often has the other peer (recently) violated the
547 * inbound traffic limit? Incremented by 10 per violation,
548 * decremented by 1 per non-violation (for each
551 unsigned int quota_violation_count;
554 * DV distance to this peer (1 if no DV is used).
559 * Have we seen an PONG from this neighbour in the past (and
560 * not had a disconnect since)?
565 * Do we have a valid public key for this neighbour?
567 int public_key_valid;
570 * Are we already in the process of disconnecting this neighbour?
575 * Performance data for the peer.
577 struct GNUNET_TRANSPORT_ATS_Information *ats;
581 * Message used to ask a peer to validate receipt (to check an address
582 * from a HELLO). Followed by the address we are trying to validate,
583 * or an empty address if we are just sending a PING to confirm that a
584 * connection which the receiver (of the PING) initiated is still valid.
586 struct TransportPingMessage
590 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
592 struct GNUNET_MessageHeader header;
595 * Challenge code (to ensure fresh reply).
597 uint32_t challenge GNUNET_PACKED;
600 * Who is the intended recipient?
602 struct GNUNET_PeerIdentity target;
608 * Message used to validate a HELLO. The challenge is included in the
609 * confirmation to make matching of replies to requests possible. The
610 * signature signs our public key, an expiration time and our address.<p>
612 * This message is followed by our transport address that the PING tried
613 * to confirm (if we liked it). The address can be empty (zero bytes)
614 * if the PING had not address either (and we received the request via
615 * a connection that we initiated).
617 struct TransportPongMessage
621 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
623 struct GNUNET_MessageHeader header;
626 * Challenge code from PING (showing freshness). Not part of what
627 * is signed so that we can re-use signatures.
629 uint32_t challenge GNUNET_PACKED;
634 struct GNUNET_CRYPTO_RsaSignature signature;
637 * What are we signing and why? Two possible reason codes can be here:
638 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
639 * plausible address for this peer (pid is set to identity of signer); or
640 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
641 * an address we used to connect to the peer with the given pid.
643 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
646 * When does this signature expire?
648 struct GNUNET_TIME_AbsoluteNBO expiration;
651 * Either the identity of the peer Who signed this message, or the
652 * identity of the peer that we're connected to using the given
653 * address (depending on purpose.type).
655 struct GNUNET_PeerIdentity pid;
658 * Size of address appended to this message (part of what is
659 * being signed, hence not redundant).
667 * Linked list of messages to be transmitted to the client. Each
668 * entry is followed by the actual message.
670 struct ClientMessageQueueEntry
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *next;
678 * This is a doubly-linked list.
680 struct ClientMessageQueueEntry *prev;
685 * Client connected to the transport service.
687 struct TransportClient
691 * This is a linked list.
693 struct TransportClient *next;
696 * Handle to the client.
698 struct GNUNET_SERVER_Client *client;
701 * Linked list of messages yet to be transmitted to
704 struct ClientMessageQueueEntry *message_queue_head;
707 * Tail of linked list of messages yet to be transmitted to the
710 struct ClientMessageQueueEntry *message_queue_tail;
713 * Current transmit request handle.
715 struct GNUNET_CONNECTION_TransmitHandle *th;
718 * Is a call to "transmit_send_continuation" pending? If so, we
719 * must not free this struct (even if the corresponding client
720 * disconnects) and instead only remove it from the linked list and
721 * set the "client" field to NULL.
726 * Length of the list of messages pending for this client.
728 unsigned int message_count;
734 * Context of currently active requests to peerinfo
735 * for validation of HELLOs.
737 struct CheckHelloValidatedContext;
741 * Entry in map of all HELLOs awaiting validation.
743 struct ValidationEntry
747 * NULL if this entry is not part of a larger HELLO validation.
749 struct CheckHelloValidatedContext *chvc;
752 * The address, actually a pointer to the end
753 * of this struct. Do not free!
758 * Name of the transport.
760 char *transport_name;
763 * The public key of the peer.
765 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
768 * ID of task that will clean up this entry if we don't succeed
769 * with the validation first.
771 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
774 * At what time did we send this validation?
776 struct GNUNET_TIME_Absolute send_time;
779 * Session being validated (or NULL for none).
781 struct Session *session;
784 * Challenge number we used.
797 * Context of currently active requests to peerinfo
798 * for validation of HELLOs.
800 struct CheckHelloValidatedContext
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *next;
809 * This is a doubly-linked list.
811 struct CheckHelloValidatedContext *prev;
814 * Hello that we are validating.
816 const struct GNUNET_HELLO_Message *hello;
819 * Context for peerinfo iteration.
820 * NULL after we are done processing peerinfo's information.
822 struct GNUNET_PEERINFO_IteratorContext *piter;
825 * Was a HELLO known for this peer to peerinfo?
830 * Number of validation entries currently referring to this
833 unsigned int ve_count;
838 * All zero hash for comparison.
840 static GNUNET_HashCode null_hash;
845 static struct GNUNET_HELLO_Message *our_hello;
850 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
855 static struct GNUNET_PeerIdentity my_identity;
860 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
865 const struct GNUNET_CONFIGURATION_Handle *cfg;
868 * Linked list of all clients to this service.
870 static struct TransportClient *clients;
873 * All loaded plugins.
875 static struct TransportPlugin *plugins;
878 * Handle to peerinfo service.
880 static struct GNUNET_PEERINFO_Handle *peerinfo;
883 * All known neighbours and their HELLOs.
885 static struct NeighbourList *neighbours;
888 * Number of neighbours we'd like to have.
890 static uint32_t max_connect_per_transport;
893 * Head of linked list.
895 static struct CheckHelloValidatedContext *chvc_head;
898 * Tail of linked list.
900 static struct CheckHelloValidatedContext *chvc_tail;
903 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
904 * of the given peer that we are currently validating).
906 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
909 * Handle for reporting statistics.
911 static struct GNUNET_STATISTICS_Handle *stats;
914 * Identifier of 'refresh_hello' task.
916 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
919 * Identifier of ats scheduler task.
921 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
924 * Is transport service shutting down ?
926 static int shutdown_in_progress;
929 * Handle for ats information
931 static struct ATS_Handle *ats;
934 * Time of last ats execution
936 struct GNUNET_TIME_Absolute last_ats_execution;
938 * Minimum interval between two ATS executions
940 struct GNUNET_TIME_Relative ats_minimum_interval;
942 * Regular interval when ATS execution is triggered
944 struct GNUNET_TIME_Relative ats_regular_interval;
947 * The peer specified by the given neighbour has timed-out or a plugin
948 * has disconnected. We may either need to do nothing (other plugins
949 * still up), or trigger a full disconnect and clean up. This
950 * function updates our state and do the necessary notifications.
951 * Also notifies our clients that the neighbour is now officially
954 * @param n the neighbour list entry for the peer
955 * @param check should we just check if all plugins
956 * disconnected or must we ask all plugins to
959 static void disconnect_neighbour (struct NeighbourList *n, int check);
962 * Check the ready list for the given neighbour and if a plugin is
963 * ready for transmission (and if we have a message), do so!
965 * @param nexi target peer for which to transmit
967 static void try_transmission_to_peer (struct NeighbourList *n);
969 struct ForeignAddressList * get_preferred_ats_address (
970 struct NeighbourList *n);
973 * Find an entry in the neighbour list for a particular peer.
975 * @return NULL if not found.
977 static struct NeighbourList *
978 find_neighbour (const struct GNUNET_PeerIdentity *key)
980 struct NeighbourList *head = neighbours;
982 while ((head != NULL) &&
983 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
988 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
992 for (c=0; c<available_quality_metrics; c++)
994 if (ats_index == qm[c].atis_index)
996 fal->quality[c].values[0] = fal->quality[c].values[1];
997 fal->quality[c].values[1] = fal->quality[c].values[2];
998 fal->quality[c].values[2] = value;
1001 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1005 if (set == GNUNET_NO)
1007 for (c=0; c<available_ressources; c++)
1009 if (ats_index == ressources[c].atis_index)
1011 fal->ressources[c].c = value;
1014 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1023 update_addr_ats (struct ForeignAddressList *fal,
1024 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1029 for (c1=0; c1<ats_count; c1++)
1031 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1037 * Find an entry in the transport list for a particular transport.
1039 * @return NULL if not found.
1041 static struct TransportPlugin *
1042 find_transport (const char *short_name)
1044 struct TransportPlugin *head = plugins;
1045 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1051 * Is a particular peer blacklisted for a particular transport?
1053 * @param peer the peer to check for
1054 * @param plugin the plugin used to connect to the peer
1056 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1059 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1062 if (plugin->blacklist != NULL)
1064 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Peer `%s:%s' is blacklisted!\n",
1069 plugin->short_name, GNUNET_i2s (peer));
1072 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1082 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1083 char *transport_name)
1085 struct TransportPlugin *plugin;
1087 plugin = find_transport(transport_name);
1088 if (plugin == NULL) /* Nothing to do */
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 "Adding peer `%s' with plugin `%s' to blacklist\n",
1096 if (plugin->blacklist == NULL)
1097 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1098 GNUNET_assert(plugin->blacklist != NULL);
1099 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1106 * Read the blacklist file, containing transport:peer entries.
1107 * Provided the transport is loaded, set up hashmap with these
1108 * entries to blacklist peers by transport.
1112 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1119 struct GNUNET_PeerIdentity pid;
1121 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1122 unsigned int entries_found;
1123 char *transport_name;
1126 GNUNET_CONFIGURATION_get_value_filename (cfg,
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Option `%s' in section `%s' not specified!\n",
1139 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1140 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1141 | GNUNET_DISK_PERM_USER_WRITE);
1142 if (0 != STAT (fn, &frstat))
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 _("Could not read blacklist file `%s'\n"), fn);
1149 if (frstat.st_size == 0)
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 _("Blacklist file `%s' is empty.\n"),
1159 /* FIXME: use mmap */
1160 data = GNUNET_malloc_large (frstat.st_size);
1161 GNUNET_assert(data != NULL);
1162 if (frstat.st_size !=
1163 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _("Failed to read blacklist from `%s'\n"), fn);
1173 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1175 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1176 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1179 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1182 if (colon_pos >= frstat.st_size)
1184 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1185 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1186 (unsigned long long) colon_pos);
1192 if (isspace( (unsigned char) data[colon_pos]))
1194 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1195 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1196 (unsigned long long) colon_pos);
1198 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1202 tsize = colon_pos - pos;
1203 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1206 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1207 (unsigned long long) colon_pos);
1216 transport_name = GNUNET_malloc(tsize + 1);
1217 memcpy(transport_name, &data[pos], tsize);
1218 pos = colon_pos + 1;
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Read transport name %s in blacklist file.\n",
1224 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1225 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1227 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1228 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1229 (unsigned long long) pos);
1231 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1233 GNUNET_free_non_null(transport_name);
1236 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1237 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1239 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1240 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1241 (unsigned long long) pos,
1246 if (0 != memcmp (&pid,
1248 sizeof (struct GNUNET_PeerIdentity)))
1251 add_peer_to_blacklist (&pid,
1256 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1257 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1261 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1262 GNUNET_free_non_null(transport_name);
1263 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1266 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1273 * Function called to notify a client about the socket being ready to
1274 * queue more data. "buf" will be NULL and "size" zero if the socket
1275 * was closed for writing in the meantime.
1277 * @param cls closure
1278 * @param size number of bytes available in buf
1279 * @param buf where the callee should write the message
1280 * @return number of bytes written to buf
1283 transmit_to_client_callback (void *cls, size_t size, void *buf)
1285 struct TransportClient *client = cls;
1286 struct ClientMessageQueueEntry *q;
1289 const struct GNUNET_MessageHeader *msg;
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Transmission to client failed, closing connection.\n");
1299 /* fatal error with client, free message queue! */
1300 while (NULL != (q = client->message_queue_head))
1302 GNUNET_STATISTICS_update (stats,
1303 gettext_noop ("# bytes discarded (could not transmit to client)"),
1304 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1306 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1307 client->message_queue_tail,
1311 client->message_count = 0;
1316 while (NULL != (q = client->message_queue_head))
1318 msg = (const struct GNUNET_MessageHeader *) &q[1];
1319 msize = ntohs (msg->size);
1320 if (msize + tsize > size)
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "Transmitting message of type %u to client.\n",
1327 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1328 client->message_queue_tail,
1330 memcpy (&cbuf[tsize], msg, msize);
1333 client->message_count--;
1337 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1338 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1340 GNUNET_TIME_UNIT_FOREVER_REL,
1341 &transmit_to_client_callback,
1343 GNUNET_assert (client->th != NULL);
1350 * Convert an address to a string.
1352 * @param plugin name of the plugin responsible for the address
1353 * @param addr binary address
1354 * @param addr_len number of bytes in addr
1355 * @return NULL on error, otherwise address string
1358 a2s (const char *plugin,
1362 struct TransportPlugin *p;
1366 p = find_transport (plugin);
1367 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1370 return p->api->address_to_string (NULL,
1380 * Iterator to free entries in the validation_map.
1382 * @param cls closure (unused)
1383 * @param key current key code
1384 * @param value value in the hash map (validation to abort)
1385 * @return GNUNET_YES (always)
1388 abort_validation (void *cls,
1389 const GNUNET_HashCode * key,
1392 struct ValidationEntry *va = value;
1394 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1395 GNUNET_SCHEDULER_cancel (va->timeout_task);
1396 GNUNET_free (va->transport_name);
1397 if (va->chvc != NULL)
1399 va->chvc->ve_count--;
1400 if (va->chvc->ve_count == 0)
1402 GNUNET_CONTAINER_DLL_remove (chvc_head,
1405 GNUNET_free (va->chvc);
1415 * HELLO validation cleanup task (validation failed).
1417 * @param cls the 'struct ValidationEntry' that failed
1418 * @param tc scheduler context (unused)
1421 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1423 struct ValidationEntry *va = cls;
1424 struct GNUNET_PeerIdentity pid;
1426 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1427 GNUNET_STATISTICS_update (stats,
1428 gettext_noop ("# address validation timeouts"),
1431 GNUNET_CRYPTO_hash (&va->publicKey,
1433 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1435 GNUNET_break (GNUNET_OK ==
1436 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1439 abort_validation (NULL, NULL, va);
1445 * Send the specified message to the specified client. Since multiple
1446 * messages may be pending for the same client at a time, this code
1447 * makes sure that no message is lost.
1449 * @param client client to transmit the message to
1450 * @param msg the message to send
1451 * @param may_drop can this message be dropped if the
1452 * message queue for this client is getting far too large?
1455 transmit_to_client (struct TransportClient *client,
1456 const struct GNUNET_MessageHeader *msg, int may_drop)
1458 struct ClientMessageQueueEntry *q;
1461 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1463 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1465 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1468 client->message_count,
1470 GNUNET_STATISTICS_update (stats,
1471 gettext_noop ("# messages dropped due to slow client"),
1476 msize = ntohs (msg->size);
1477 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1478 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1479 memcpy (&q[1], msg, msize);
1480 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1481 client->message_queue_tail,
1483 client->message_count++;
1484 if (client->th == NULL)
1486 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1488 GNUNET_TIME_UNIT_FOREVER_REL,
1489 &transmit_to_client_callback,
1491 GNUNET_assert (client->th != NULL);
1497 * Transmit a 'SEND_OK' notification to the given client for the
1500 * @param client who to notify
1501 * @param n neighbour to notify about, can be NULL (on failure)
1502 * @param target target of the transmission
1503 * @param result status code for the transmission request
1506 transmit_send_ok (struct TransportClient *client,
1507 struct NeighbourList *n,
1508 const struct GNUNET_PeerIdentity *target,
1511 struct SendOkMessage send_ok_msg;
1513 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1514 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1515 send_ok_msg.success = htonl (result);
1517 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1519 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1520 send_ok_msg.peer = *target;
1521 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1526 * Mark the given FAL entry as 'connected' (and hence preferred for
1527 * sending); also mark all others for the same peer as 'not connected'
1528 * (since only one can be preferred).
1530 * @param fal address to set to 'connected'
1533 mark_address_connected (struct ForeignAddressList *fal);
1538 * We should re-try transmitting to the given peer,
1539 * hopefully we've learned something in the meantime.
1542 retry_transmission_task (void *cls,
1543 const struct GNUNET_SCHEDULER_TaskContext *tc)
1545 struct NeighbourList *n = cls;
1547 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1548 try_transmission_to_peer (n);
1553 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1554 * upon "completion" of a send request. This tells the API
1555 * that it is now legal to send another message to the given
1558 * @param cls closure, identifies the entry on the
1559 * message queue that was transmitted and the
1560 * client responsible for queuing the message
1561 * @param target the peer receiving the message
1562 * @param result GNUNET_OK on success, if the transmission
1563 * failed, we should not tell the client to transmit
1567 transmit_send_continuation (void *cls,
1568 const struct GNUNET_PeerIdentity *target,
1571 struct MessageQueue *mq = cls;
1572 struct NeighbourList *n;
1574 GNUNET_STATISTICS_update (stats,
1575 gettext_noop ("# bytes pending with plugins"),
1576 - (int64_t) mq->message_buf_size,
1578 if (result == GNUNET_OK)
1580 GNUNET_STATISTICS_update (stats,
1581 gettext_noop ("# bytes successfully transmitted by plugins"),
1582 mq->message_buf_size,
1587 GNUNET_STATISTICS_update (stats,
1588 gettext_noop ("# bytes with transmission failure by plugins"),
1589 mq->message_buf_size,
1592 if (mq->specific_address != NULL)
1594 if (result == GNUNET_OK)
1596 mq->specific_address->timeout =
1597 GNUNET_TIME_relative_to_absolute
1598 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1599 if (mq->specific_address->validated == GNUNET_YES)
1600 mark_address_connected (mq->specific_address);
1604 if (mq->specific_address->connected != GNUNET_NO)
1607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1609 a2s (mq->specific_address->ready_list->plugin->short_name,
1610 mq->specific_address->addr,
1611 mq->specific_address->addrlen));
1613 GNUNET_STATISTICS_update (stats,
1614 gettext_noop ("# connected addresses"),
1617 mq->specific_address->connected = GNUNET_NO;
1620 if (! mq->internal_msg)
1621 mq->specific_address->in_transmit = GNUNET_NO;
1623 n = find_neighbour (&mq->neighbour_id);
1624 if (mq->client != NULL)
1625 transmit_send_ok (mq->client, n, target, result);
1626 GNUNET_assert (n != NULL);
1627 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1631 if (result == GNUNET_OK)
1632 try_transmission_to_peer (n);
1633 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1634 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1640 * Check the ready list for the given neighbour and if a plugin is
1641 * ready for transmission (and if we have a message), do so!
1643 * @param neighbour target peer for which to transmit
1646 try_transmission_to_peer (struct NeighbourList *n)
1648 struct ReadyList *rl;
1649 struct MessageQueue *mq;
1650 struct GNUNET_TIME_Relative timeout;
1654 if (n->messages_head == NULL)
1657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1658 "Transmission queue for `%4s' is empty\n",
1659 GNUNET_i2s (&n->id));
1661 return; /* nothing to do */
1664 mq = n->messages_head;
1665 force_address = GNUNET_YES;
1666 if (mq->specific_address == NULL)
1669 mq->specific_address = get_preferred_ats_address(n);
1670 GNUNET_STATISTICS_update (stats,
1671 gettext_noop ("# transport selected peer address freely"),
1674 force_address = GNUNET_NO;
1676 if (mq->specific_address == NULL)
1678 GNUNET_STATISTICS_update (stats,
1679 gettext_noop ("# transport failed to selected peer address"),
1682 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1683 if (timeout.rel_value == 0)
1686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1687 "No destination address available to transmit message of size %u to peer `%4s'\n",
1688 mq->message_buf_size,
1689 GNUNET_i2s (&mq->neighbour_id));
1691 GNUNET_STATISTICS_update (stats,
1692 gettext_noop ("# bytes in message queue for other peers"),
1693 - (int64_t) mq->message_buf_size,
1695 GNUNET_STATISTICS_update (stats,
1696 gettext_noop ("# bytes discarded (no destination address available)"),
1697 mq->message_buf_size,
1699 if (mq->client != NULL)
1700 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1701 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1705 return; /* nobody ready */
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# message delivery deferred (no address)"),
1711 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1712 GNUNET_SCHEDULER_cancel (n->retry_task);
1713 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1714 &retry_transmission_task,
1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1719 mq->message_buf_size,
1720 GNUNET_i2s (&mq->neighbour_id),
1723 /* FIXME: might want to trigger peerinfo lookup here
1724 (unless that's already pending...) */
1727 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1730 if (mq->specific_address->connected == GNUNET_NO)
1731 mq->specific_address->connect_attempts++;
1732 rl = mq->specific_address->ready_list;
1733 mq->plugin = rl->plugin;
1734 if (!mq->internal_msg)
1735 mq->specific_address->in_transmit = GNUNET_YES;
1737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1738 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1739 mq->message_buf_size,
1740 GNUNET_i2s (&n->id),
1741 (mq->specific_address->addr != NULL)
1742 ? a2s (mq->plugin->short_name,
1743 mq->specific_address->addr,
1744 mq->specific_address->addrlen)
1746 rl->plugin->short_name);
1748 GNUNET_STATISTICS_update (stats,
1749 gettext_noop ("# bytes in message queue for other peers"),
1750 - (int64_t) mq->message_buf_size,
1752 GNUNET_STATISTICS_update (stats,
1753 gettext_noop ("# bytes pending with plugins"),
1754 mq->message_buf_size,
1757 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1761 ret = rl->plugin->api->send (rl->plugin->api->cls,
1764 mq->message_buf_size,
1766 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1767 mq->specific_address->session,
1768 mq->specific_address->addr,
1769 mq->specific_address->addrlen,
1771 &transmit_send_continuation, mq);
1774 /* failure, but 'send' would not call continuation in this case,
1775 so we need to do it here! */
1776 transmit_send_continuation (mq,
1784 * Send the specified message to the specified peer.
1786 * @param client source of the transmission request (can be NULL)
1787 * @param peer_address ForeignAddressList where we should send this message
1788 * @param priority how important is the message
1789 * @param timeout how long do we have to transmit?
1790 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1791 * @param message_buf_size total size of all messages in message_buf
1792 * @param is_internal is this an internal message; these are pre-pended and
1793 * also do not count for plugins being "ready" to transmit
1794 * @param neighbour handle to the neighbour for transmission
1797 transmit_to_peer (struct TransportClient *client,
1798 struct ForeignAddressList *peer_address,
1799 unsigned int priority,
1800 struct GNUNET_TIME_Relative timeout,
1801 const char *message_buf,
1802 size_t message_buf_size,
1803 int is_internal, struct NeighbourList *neighbour)
1805 struct MessageQueue *mq;
1810 /* check for duplicate submission */
1811 mq = neighbour->messages_head;
1814 if (mq->client == client)
1816 /* client transmitted to same peer twice
1817 before getting SEND_OK! */
1825 GNUNET_STATISTICS_update (stats,
1826 gettext_noop ("# bytes in message queue for other peers"),
1829 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1830 mq->specific_address = peer_address;
1831 mq->client = client;
1832 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1833 memcpy (&mq[1], message_buf, message_buf_size);
1834 mq->message_buf = (const char*) &mq[1];
1835 mq->message_buf_size = message_buf_size;
1836 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1837 mq->internal_msg = is_internal;
1838 mq->priority = priority;
1839 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1841 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1842 neighbour->messages_tail,
1845 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1846 neighbour->messages_tail,
1847 neighbour->messages_tail,
1849 try_transmission_to_peer (neighbour);
1854 * Send a plain PING (without address or our HELLO) to the given
1855 * foreign address to try to establish a connection (and validate
1856 * that the other peer is really who he claimed he is).
1858 * @param n neighbour to PING
1861 transmit_plain_ping (struct NeighbourList *n)
1863 struct ValidationEntry *ve;
1864 struct TransportPingMessage ping;
1865 struct ReadyList *rl;
1866 struct TransportPlugin *plugin;
1867 struct ForeignAddressList *fal;
1869 if (! n->public_key_valid)
1871 /* This should not happen since the other peer
1872 should send us a HELLO prior to sending his
1874 GNUNET_break_op (0);
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Could not transmit plain PING to `%s': public key not known\n",
1877 GNUNET_i2s (&n->id));
1880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881 "Looking for addresses to transmit plain PING to `%s'\n",
1882 GNUNET_i2s (&n->id));
1883 for (rl = n->plugins; rl != NULL; rl = rl->next)
1885 plugin = rl->plugin;
1886 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1888 if (! fal->connected)
1890 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1891 ve->transport_name = GNUNET_strdup (plugin->short_name);
1892 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1894 ve->send_time = GNUNET_TIME_absolute_get();
1895 ve->session = fal->session;
1896 memcpy(&ve->publicKey,
1898 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1899 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1900 &timeout_hello_validation,
1902 GNUNET_CONTAINER_multihashmap_put (validation_map,
1905 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1906 ping.header.size = htons(sizeof(struct TransportPingMessage));
1907 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1908 ping.challenge = htonl(ve->challenge);
1909 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1910 GNUNET_STATISTICS_update (stats,
1911 gettext_noop ("# PING without HELLO messages sent"),
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "Transmitting plain PING to `%s'\n",
1916 GNUNET_i2s (&n->id));
1917 transmit_to_peer (NULL,
1919 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1920 HELLO_VERIFICATION_TIMEOUT,
1921 (const char*) &ping, sizeof (ping),
1929 * Mark the given FAL entry as 'connected' (and hence preferred for
1930 * sending); also mark all others for the same peer as 'not connected'
1931 * (since only one can be preferred).
1933 * @param fal address to set to 'connected'
1936 mark_address_connected(struct ForeignAddressList *fal)
1938 struct ForeignAddressList *pos;
1939 struct ForeignAddressList *inbound;
1940 struct ForeignAddressList *outbound;
1943 GNUNET_assert (GNUNET_YES == fal->validated);
1944 if (fal->connected == GNUNET_YES)
1945 return; /* nothing to do */
1950 pos = fal->ready_list->addresses;
1953 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1954 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) && (0
1957 else if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1962 pos = fal->ready_list->addresses;
1965 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1966 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) && (0
1969 else if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1975 if (inbound != NULL)
1976 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1977 if (outbound != NULL)
1978 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1981 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1982 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1983 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1984 &my_identity.hashPubKey, &null_hash)))
1987 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1991 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1992 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1993 &my_identity.hashPubKey, &null_hash))))
1996 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
2001 pos = fal->ready_list->addresses;
2004 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2008 GNUNET_ERROR_TYPE_DEBUG,
2009 "Marking address `%s' as no longer connected (due to connect on other address)\n",
2010 a2s (pos->ready_list->plugin->short_name, pos->addr,
2013 GNUNET_break (cnt == GNUNET_YES);
2016 fprintf(stderr, "Peer: %s, setting %s connection to disconnected.\n", GNUNET_i2s(&my_identity), (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2018 pos->connected = GNUNET_NO;
2019 GNUNET_STATISTICS_update (stats,
2020 gettext_noop ("# connected addresses"), -1,
2026 fal->connected = GNUNET_YES;
2027 if (GNUNET_YES == cnt)
2029 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2036 * Find an address in any of the available transports for
2037 * the given neighbour that would be good for message
2038 * transmission. This is essentially the transport selection
2041 * @param neighbour for whom to select an address
2042 * @return selected address, NULL if we have none
2044 struct ForeignAddressList *
2045 find_ready_address(struct NeighbourList *neighbour)
2047 struct ReadyList *head = neighbour->plugins;
2048 struct ForeignAddressList *addresses;
2049 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2050 struct ForeignAddressList *best_address;
2052 /* Hack to prefer unix domain sockets */
2053 struct ForeignAddressList *unix_address = NULL;
2055 best_address = NULL;
2056 while (head != NULL)
2058 addresses = head->addresses;
2059 while (addresses != NULL)
2061 if ( (addresses->timeout.abs_value < now.abs_value) &&
2062 (addresses->connected == GNUNET_YES) )
2065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2066 "Marking long-time inactive connection to `%4s' as down.\n",
2067 GNUNET_i2s (&neighbour->id));
2069 GNUNET_STATISTICS_update (stats,
2070 gettext_noop ("# connected addresses"),
2073 addresses->connected = GNUNET_NO;
2075 addresses = addresses->next;
2078 addresses = head->addresses;
2079 while (addresses != NULL)
2082 if (addresses->addr != NULL)
2083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2085 a2s (head->plugin->short_name,
2087 addresses->addrlen),
2088 GNUNET_i2s (&neighbour->id),
2089 addresses->connected,
2090 addresses->in_transmit,
2091 addresses->validated,
2092 addresses->connect_attempts,
2093 (unsigned long long) addresses->timeout.abs_value,
2094 (unsigned int) addresses->distance);
2096 if (0==strcmp(head->plugin->short_name,"unix"))
2098 if ( (unix_address == NULL) ||
2099 ( (unix_address != NULL) &&
2100 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2101 unix_address = addresses;
2103 if ( ( (best_address == NULL) ||
2104 (addresses->connected == GNUNET_YES) ||
2105 (best_address->connected == GNUNET_NO) ) &&
2106 (addresses->in_transmit == GNUNET_NO) &&
2107 ( (best_address == NULL) ||
2108 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2109 best_address = addresses;
2110 /* FIXME: also give lower-latency addresses that are not
2111 connected a chance some times... */
2112 addresses = addresses->next;
2114 if (unix_address != NULL)
2118 if (unix_address != NULL)
2120 best_address = unix_address;
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2123 "Found UNIX address, forced this address\n");
2126 if (best_address != NULL)
2129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2130 "Best address found (`%s') has latency of %llu ms.\n",
2131 (best_address->addrlen > 0)
2132 ? a2s (best_address->ready_list->plugin->short_name,
2134 best_address->addrlen)
2136 best_address->latency.rel_value);
2141 GNUNET_STATISTICS_update (stats,
2142 gettext_noop ("# transmission attempts failed (no address)"),
2147 return best_address;
2154 struct GeneratorContext
2156 struct TransportPlugin *plug_pos;
2157 struct OwnAddressList *addr_pos;
2158 struct GNUNET_TIME_Absolute expiration;
2166 address_generator (void *cls, size_t max, void *buf)
2168 struct GeneratorContext *gc = cls;
2171 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2173 gc->plug_pos = gc->plug_pos->next;
2174 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2176 if (NULL == gc->plug_pos)
2181 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2184 gc->addr_pos->addrlen, buf, max);
2185 gc->addr_pos = gc->addr_pos->next;
2191 * Construct our HELLO message from all of the addresses of
2192 * all of the transports.
2195 * @param tc scheduler context
2198 refresh_hello_task (void *cls,
2199 const struct GNUNET_SCHEDULER_TaskContext *tc)
2201 struct GNUNET_HELLO_Message *hello;
2202 struct TransportClient *cpos;
2203 struct NeighbourList *npos;
2204 struct GeneratorContext gc;
2206 hello_task = GNUNET_SCHEDULER_NO_TASK;
2207 gc.plug_pos = plugins;
2208 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2209 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2210 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2213 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2215 GNUNET_STATISTICS_update (stats,
2216 gettext_noop ("# refreshed my HELLO"),
2220 while (cpos != NULL)
2222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2223 "Transmitting my HELLO to client!\n");
2224 transmit_to_client (cpos,
2225 (const struct GNUNET_MessageHeader *) hello,
2230 GNUNET_free_non_null (our_hello);
2232 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2233 for (npos = neighbours; npos != NULL; npos = npos->next)
2235 if (GNUNET_YES != npos->received_pong)
2238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2239 "Transmitting updated `%s' to neighbour `%4s'\n",
2240 "HELLO", GNUNET_i2s (&npos->id));
2242 GNUNET_STATISTICS_update (stats,
2243 gettext_noop ("# transmitted my HELLO to other peers"),
2246 transmit_to_peer (NULL, NULL, 0,
2247 HELLO_ADDRESS_EXPIRATION,
2248 (const char *) our_hello,
2249 GNUNET_HELLO_size(our_hello),
2256 * Schedule task to refresh hello (unless such a
2257 * task exists already).
2262 #if DEBUG_TRANSPORT_HELLO
2263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2264 "refresh_hello() called!\n");
2266 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2269 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2275 * Iterator over hash map entries that NULLs the session of validation
2276 * entries that match the given session.
2278 * @param cls closure (the 'struct Session*' to match against)
2279 * @param key current key code (peer ID, not used)
2280 * @param value value in the hash map ('struct ValidationEntry*')
2281 * @return GNUNET_YES (we should continue to iterate)
2284 remove_session_validations (void *cls,
2285 const GNUNET_HashCode * key,
2288 struct Session *session = cls;
2289 struct ValidationEntry *ve = value;
2291 if (session == ve->session)
2298 * We've been disconnected from the other peer (for some
2299 * connection-oriented transport). Either quickly
2300 * re-establish the connection or signal the disconnect
2303 * Only signal CORE level disconnect if ALL addresses
2304 * for the peer are exhausted.
2306 * @param p overall plugin context
2307 * @param nl neighbour that was disconnected
2310 try_fast_reconnect (struct TransportPlugin *p,
2311 struct NeighbourList *nl)
2313 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2314 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2315 "try_fast_reconnect not implemented!\n");
2316 /* Note: the idea here is to hide problems with transports (or
2317 switching between plugins) from the core to eliminate the need to
2318 re-negotiate session keys and the like; OTOH, we should tell core
2319 quickly (much faster than timeout) `if a connection was lost and
2320 could not be re-established (i.e. other peer went down or is
2321 unable / refuses to communicate);
2323 So we should consider:
2324 1) ideally: our own willingness / need to connect
2325 2) prior failures to connect to this peer (by plugin)
2326 3) ideally: reasons why other peer terminated (as far as knowable)
2328 Most importantly, it must be POSSIBLE for another peer to terminate
2329 a connection for a while (without us instantly re-establishing it).
2330 Similarly, if another peer is gone we should quickly notify CORE.
2331 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2332 on the other end), we should reconnect in such a way that BOTH CORE
2333 services never even notice.
2334 Furthermore, the same mechanism (or small variation) could be used
2335 to switch to a better-performing plugin (ATS).
2337 Finally, this needs to be tested throughly... */
2340 * GNUNET_NO in the call below makes transport disconnect the peer,
2341 * even if only a single address (out of say, six) went away. This
2342 * function must be careful to ONLY disconnect if the peer is gone,
2343 * not just a specific address.
2345 * More specifically, half the places it was used had it WRONG.
2348 /* No reconnect, signal disconnect instead! */
2351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2352 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2353 "try_fast_reconnect");
2355 GNUNET_STATISTICS_update (stats,
2356 gettext_noop ("# disconnects due to try_fast_reconnect"),
2360 disconnect_neighbour (nl, GNUNET_YES);
2366 * Function that will be called whenever the plugin internally
2367 * cleans up a session pointer and hence the service needs to
2368 * discard all of those sessions as well. Plugins that do not
2369 * use sessions can simply omit calling this function and always
2370 * use NULL wherever a session pointer is needed.
2372 * @param cls closure
2373 * @param peer which peer was the session for
2374 * @param session which session is being destoyed
2377 plugin_env_session_end (void *cls,
2378 const struct GNUNET_PeerIdentity *peer,
2379 struct Session *session)
2381 struct TransportPlugin *p = cls;
2382 struct NeighbourList *nl;
2383 struct ReadyList *rl;
2384 struct ForeignAddressList *pos;
2385 struct ForeignAddressList *prev;
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2389 "Session ended with peer `%4s', %s\n",
2391 "plugin_env_session_end");
2393 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2394 &remove_session_validations,
2396 nl = find_neighbour (peer);
2400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401 "No neighbour record found for peer `%4s'\n",
2404 return; /* was never marked as connected */
2409 if (rl->plugin == p)
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417 "Plugin was associated with peer `%4s'\n",
2420 GNUNET_STATISTICS_update (stats,
2421 gettext_noop ("# disconnects due to session end"),
2424 disconnect_neighbour (nl, GNUNET_YES);
2428 pos = rl->addresses;
2429 while ( (pos != NULL) &&
2430 (pos->session != session) )
2438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2439 "Session was never marked as ready for peer `%4s'\n",
2443 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2445 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2446 if (validations_pending ==GNUNET_YES)
2449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2450 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2455 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2456 GNUNET_STATISTICS_update (stats,
2457 gettext_noop ("# disconnects due to unready session"),
2461 disconnect_neighbour (nl, GNUNET_YES);
2462 return; /* was never marked as connected */
2464 pos->session = NULL;
2465 pos->connected = GNUNET_NO;
2466 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2468 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2469 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2472 if (pos->addrlen != 0)
2474 if (nl->received_pong != GNUNET_NO)
2476 GNUNET_STATISTICS_update (stats,
2477 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2480 if (GNUNET_YES == pos->connected)
2481 try_fast_reconnect (p, nl);
2485 GNUNET_STATISTICS_update (stats,
2486 gettext_noop ("# disconnects due to missing pong"),
2489 /* FIXME this is never true?! See: line 2416*/
2490 if (GNUNET_YES == pos->connected)
2491 disconnect_neighbour (nl, GNUNET_YES);
2496 GNUNET_STATISTICS_update (stats,
2497 gettext_noop ("# connected addresses"),
2501 /* was inbound connection, free 'pos' */
2503 rl->addresses = pos->next;
2505 prev->next = pos->next;
2506 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2508 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2509 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2511 GNUNET_free_non_null(pos->ressources);
2512 GNUNET_free_non_null(pos->quality);
2514 ats_modify_problem_state (ats, ATS_MODIFIED);
2516 if (GNUNET_YES != pos->connected)
2518 /* nothing else to do, connection was never up... */
2524 if (nl->received_pong == GNUNET_NO)
2526 GNUNET_STATISTICS_update (stats,
2527 gettext_noop ("# disconnects due to NO pong"),
2530 disconnect_neighbour (nl, GNUNET_YES);
2531 return; /* nothing to do, never connected... */
2533 /* check if we have any validated addresses left */
2534 pos = rl->addresses;
2537 if (GNUNET_YES == pos->validated)
2539 GNUNET_STATISTICS_update (stats,
2540 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2543 try_fast_reconnect (p, nl);
2548 /* no valid addresses left, signal disconnect! */
2551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2552 "Disconnecting peer `%4s', %s\n",
2554 "plugin_env_session_end");
2556 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2557 * it means there aren't any left for this PLUGIN/PEER combination! So
2558 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2559 * when it isn't necessary. Using GNUNET_YES at least checks to see
2560 * if there are any addresses that work first, so as not to overdo it.
2563 GNUNET_STATISTICS_update (stats,
2564 gettext_noop ("# disconnects due to plugin_env_session_end"),
2567 disconnect_neighbour (nl, GNUNET_YES);
2572 * Function that must be called by each plugin to notify the
2573 * transport service about the addresses under which the transport
2574 * provided by the plugin can be reached.
2576 * @param cls closure
2577 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2578 * @param addr one of the addresses of the host, NULL for the last address
2579 * the specific address format depends on the transport
2580 * @param addrlen length of the address
2583 plugin_env_notify_address (void *cls,
2588 struct TransportPlugin *p = cls;
2589 struct OwnAddressList *al;
2590 struct OwnAddressList *prev;
2592 GNUNET_assert (p->api != NULL);
2594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2595 (add_remove == GNUNET_YES)
2596 ? "Adding `%s':%s to the set of our addresses\n"
2597 : "Removing `%s':%s from the set of our addresses\n",
2602 GNUNET_assert (addr != NULL);
2603 if (GNUNET_NO == add_remove)
2609 if ( (addrlen == al->addrlen) &&
2610 (0 == memcmp (addr, &al[1], addrlen)) )
2613 p->addresses = al->next;
2615 prev->next = al->next;
2626 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2627 al->next = p->addresses;
2629 al->addrlen = addrlen;
2630 memcpy (&al[1], addr, addrlen);
2636 * Notify all of our clients about a peer connecting.
2639 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2640 struct GNUNET_TIME_Relative latency,
2643 struct ConnectInfoMessage * cim;
2644 struct TransportClient *cpos;
2648 if (0 == memcmp (peer,
2650 sizeof (struct GNUNET_PeerIdentity)))
2656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657 "Notifying clients about connection with `%s'\n",
2660 GNUNET_STATISTICS_update (stats,
2661 gettext_noop ("# peers connected"),
2666 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2667 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2668 cim = GNUNET_malloc (size);
2669 cim->header.size = htons (size);
2670 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2671 cim->ats_count = htonl(2);
2672 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2673 (&cim->ats)[0].value = htonl (distance);
2674 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2675 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2676 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2677 (&cim->ats)[2].value = htonl (0);
2678 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2680 /* notify ats about connecting peer */
2681 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2684 ats_modify_problem_state(ats, ATS_MODIFIED);
2685 ats_calculate_bandwidth_distribution (ats, stats);
2689 while (cpos != NULL)
2691 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2699 * Notify all of our clients about a peer disconnecting.
2702 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2704 struct DisconnectInfoMessage dim;
2705 struct TransportClient *cpos;
2707 if (0 == memcmp (peer,
2709 sizeof (struct GNUNET_PeerIdentity)))
2715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2716 "Notifying clients about lost connection to `%s'\n",
2719 GNUNET_STATISTICS_update (stats,
2720 gettext_noop ("# peers connected"),
2723 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2724 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2725 dim.reserved = htonl (0);
2726 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2728 /* notify ats about connecting peer */
2729 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2732 ats_modify_problem_state(ats, ATS_MODIFIED);
2733 ats_calculate_bandwidth_distribution (ats, stats);
2738 while (cpos != NULL)
2740 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2747 * Find a ForeignAddressList entry for the given neighbour
2748 * that matches the given address and transport.
2750 * @param neighbour which peer we care about
2751 * @param tname name of the transport plugin
2752 * @param session session to look for, NULL for 'any'; otherwise
2753 * can be used for the service to "learn" this session ID
2755 * @param addr binary address
2756 * @param addrlen length of addr
2757 * @return NULL if no such entry exists
2759 static struct ForeignAddressList *
2760 find_peer_address(struct NeighbourList *neighbour,
2762 struct Session *session,
2766 struct ReadyList *head;
2767 struct ForeignAddressList *pos;
2769 head = neighbour->plugins;
2770 while (head != NULL)
2772 if (0 == strcmp (tname, head->plugin->short_name))
2778 pos = head->addresses;
2779 while ( (pos != NULL) &&
2780 ( (pos->addrlen != addrlen) ||
2781 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2783 if ( (session != NULL) &&
2784 (pos->session == session) )
2788 if ( (session != NULL) && (pos != NULL) )
2789 pos->session = session; /* learn it! */
2795 * Get the peer address struct for the given neighbour and
2796 * address. If it doesn't yet exist, create it.
2798 * @param neighbour which peer we care about
2799 * @param tname name of the transport plugin
2800 * @param session session of the plugin, or NULL for none
2801 * @param addr binary address
2802 * @param addrlen length of addr
2803 * @return NULL if we do not have a transport plugin for 'tname'
2805 static struct ForeignAddressList *
2806 add_peer_address (struct NeighbourList *neighbour,
2808 struct Session *session,
2812 struct ReadyList *head;
2813 struct ForeignAddressList *ret;
2816 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2819 head = neighbour->plugins;
2821 while (head != NULL)
2823 if (0 == strcmp (tname, head->plugin->short_name))
2829 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2830 ret->session = session;
2831 if ((addrlen > 0) && (addr != NULL))
2833 ret->addr = (const char*) &ret[1];
2834 memcpy (&ret[1], addr, addrlen);
2841 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2842 for (c=0; c<available_ressources; c++)
2844 struct ATS_ressource_entry *r = ret->ressources;
2846 r[c].atis_index = ressources[c].atis_index;
2847 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2849 r[c].c = ressources[c].c_unix;
2851 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2853 r[c].c = ressources[c].c_udp;
2855 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2857 r[c].c = ressources[c].c_tcp;
2859 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2861 r[c].c = ressources[c].c_http;
2863 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2865 r[c].c = ressources[c].c_https;
2867 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2869 r[c].c = ressources[c].c_wlan;
2873 r[c].c = ressources[c].c_default;
2874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2875 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2876 GNUNET_i2s(&neighbour->id),
2877 neighbour->plugins->plugin->short_name);
2881 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2882 ret->addrlen = addrlen;
2883 ret->expires = GNUNET_TIME_relative_to_absolute
2884 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2885 ret->latency = GNUNET_TIME_relative_get_forever();
2887 ret->timeout = GNUNET_TIME_relative_to_absolute
2888 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2889 ret->ready_list = head;
2890 ret->next = head->addresses;
2891 head->addresses = ret;
2897 * Closure for 'add_validated_address'.
2899 struct AddValidatedAddressContext
2902 * Entry that has been validated.
2904 const struct ValidationEntry *ve;
2907 * Flag set after we have added the address so
2908 * that we terminate the iteration next time.
2915 * Callback function used to fill a buffer of max bytes with a list of
2916 * addresses in the format used by HELLOs. Should use
2917 * "GNUNET_HELLO_add_address" as a helper function.
2919 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2920 * @param max maximum number of bytes that can be written to buf
2921 * @param buf where to write the address information
2922 * @return number of bytes written, 0 to signal the
2923 * end of the iteration.
2926 add_validated_address (void *cls,
2927 size_t max, void *buf)
2929 struct AddValidatedAddressContext *avac = cls;
2930 const struct ValidationEntry *ve = avac->ve;
2932 if (GNUNET_YES == avac->done)
2934 avac->done = GNUNET_YES;
2935 return GNUNET_HELLO_add_address (ve->transport_name,
2936 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2946 * Closure for 'check_address_exists'.
2948 struct CheckAddressExistsClosure
2951 * Address to check for.
2956 * Name of the transport.
2963 struct Session *session;
2966 * Set to GNUNET_YES if the address exists.
2979 * Iterator over hash map entries. Checks if the given
2980 * validation entry is for the same address as what is given
2983 * @param cls the 'struct CheckAddressExistsClosure*'
2984 * @param key current key code (ignored)
2985 * @param value value in the hash map ('struct ValidationEntry')
2986 * @return GNUNET_YES if we should continue to
2987 * iterate (mismatch), GNUNET_NO if not (entry matched)
2990 check_address_exists (void *cls,
2991 const GNUNET_HashCode * key,
2994 struct CheckAddressExistsClosure *caec = cls;
2995 struct ValidationEntry *ve = value;
2997 if ( (0 == strcmp (caec->tname,
2998 ve->transport_name)) &&
2999 (caec->addrlen == ve->addrlen) &&
3000 (0 == memcmp (caec->addr,
3004 caec->exists = GNUNET_YES;
3007 if ( (ve->session != NULL) &&
3008 (caec->session == ve->session) )
3010 caec->exists = GNUNET_YES;
3018 neighbour_timeout_task (void *cls,
3019 const struct GNUNET_SCHEDULER_TaskContext *tc)
3021 struct NeighbourList *n = cls;
3024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3025 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3027 GNUNET_STATISTICS_update (stats,
3028 gettext_noop ("# disconnects due to timeout"),
3031 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3032 disconnect_neighbour (n, GNUNET_NO);
3037 * Schedule the job that will cause us to send a PING to the
3038 * foreign address to evaluate its validity and latency.
3040 * @param fal address to PING
3043 schedule_next_ping (struct ForeignAddressList *fal);
3047 * Add the given address to the list of foreign addresses
3048 * available for the given peer (check for duplicates).
3050 * @param cls the respective 'struct NeighbourList' to update
3051 * @param tname name of the transport
3052 * @param expiration expiration time
3053 * @param addr the address
3054 * @param addrlen length of the address
3055 * @return GNUNET_OK (always)
3058 add_to_foreign_address_list (void *cls,
3060 struct GNUNET_TIME_Absolute expiration,
3064 struct NeighbourList *n = cls;
3065 struct ForeignAddressList *fal;
3068 GNUNET_STATISTICS_update (stats,
3069 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3073 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3076 #if DEBUG_TRANSPORT_HELLO
3077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3078 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3079 a2s (tname, addr, addrlen),
3081 GNUNET_i2s (&n->id),
3082 expiration.abs_value);
3084 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3087 GNUNET_STATISTICS_update (stats,
3088 gettext_noop ("# previously validated addresses lacking transport"),
3094 fal->expires = GNUNET_TIME_absolute_max (expiration,
3096 schedule_next_ping (fal);
3102 fal->expires = GNUNET_TIME_absolute_max (expiration,
3108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3109 "Failed to add new address for `%4s'\n",
3110 GNUNET_i2s (&n->id));
3114 if (fal->validated == GNUNET_NO)
3116 fal->validated = GNUNET_YES;
3117 GNUNET_STATISTICS_update (stats,
3118 gettext_noop ("# peer addresses considered valid"),
3122 if (try == GNUNET_YES)
3125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3126 "Have new addresses, will try to trigger transmissions.\n");
3128 try_transmission_to_peer (n);
3135 * Add addresses in validated HELLO "h" to the set of addresses
3136 * we have for this peer.
3138 * @param cls closure ('struct NeighbourList*')
3139 * @param peer id of the peer, NULL for last call
3140 * @param h hello message for the peer (can be NULL)
3141 * @param err_msg NULL if successful, otherwise contains error message
3144 add_hello_for_peer (void *cls,
3145 const struct GNUNET_PeerIdentity *peer,
3146 const struct GNUNET_HELLO_Message *h,
3147 const char *err_msg)
3149 struct NeighbourList *n = cls;
3151 if (err_msg != NULL)
3154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3155 _("Error in communication with PEERINFO service: %s\n"),
3162 GNUNET_STATISTICS_update (stats,
3163 gettext_noop ("# outstanding peerinfo iterate requests"),
3170 return; /* no HELLO available */
3172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3177 if (GNUNET_YES != n->public_key_valid)
3179 GNUNET_HELLO_get_key (h, &n->publicKey);
3180 n->public_key_valid = GNUNET_YES;
3182 GNUNET_HELLO_iterate_addresses (h,
3184 &add_to_foreign_address_list,
3190 * Create a fresh entry in our neighbour list for the given peer.
3191 * Will try to transmit our current HELLO to the new neighbour.
3192 * Do not call this function directly, use 'setup_peer_check_blacklist.
3194 * @param peer the peer for which we create the entry
3195 * @param do_hello should we schedule transmitting a HELLO
3196 * @return the new neighbour list entry
3198 static struct NeighbourList *
3199 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3202 struct NeighbourList *n;
3203 struct TransportPlugin *tp;
3204 struct ReadyList *rl;
3206 GNUNET_assert (0 != memcmp (peer,
3208 sizeof (struct GNUNET_PeerIdentity)));
3210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211 "Setting up state for neighbour `%4s'\n",
3214 GNUNET_STATISTICS_update (stats,
3215 gettext_noop ("# active neighbours"),
3218 n = GNUNET_malloc (sizeof (struct NeighbourList));
3219 n->next = neighbours;
3223 GNUNET_TIME_relative_to_absolute
3224 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3225 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3226 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3227 MAX_BANDWIDTH_CARRY_S);
3231 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3233 rl = GNUNET_malloc (sizeof (struct ReadyList));
3235 rl->next = n->plugins;
3238 rl->addresses = NULL;
3242 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3244 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3245 &neighbour_timeout_task, n);
3248 GNUNET_STATISTICS_update (stats,
3249 gettext_noop ("# peerinfo new neighbor iterate requests"),
3252 GNUNET_STATISTICS_update (stats,
3253 gettext_noop ("# outstanding peerinfo iterate requests"),
3256 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3257 GNUNET_TIME_UNIT_FOREVER_REL,
3258 &add_hello_for_peer, n);
3260 GNUNET_STATISTICS_update (stats,
3261 gettext_noop ("# HELLO's sent to new neighbors"),
3264 if (NULL != our_hello)
3265 transmit_to_peer (NULL, NULL, 0,
3266 HELLO_ADDRESS_EXPIRATION,
3267 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3275 * Function called after we have checked if communicating
3276 * with a given peer is acceptable.
3278 * @param cls closure
3279 * @param n NULL if communication is not acceptable
3281 typedef void (*SetupContinuation)(void *cls,
3282 struct NeighbourList *n);
3286 * Information kept for each client registered to perform
3292 * This is a linked list.
3294 struct Blacklisters *next;
3297 * This is a linked list.
3299 struct Blacklisters *prev;
3302 * Client responsible for this entry.
3304 struct GNUNET_SERVER_Client *client;
3307 * Blacklist check that we're currently performing.
3309 struct BlacklistCheck *bc;
3315 * Head of DLL of blacklisting clients.
3317 static struct Blacklisters *bl_head;
3320 * Tail of DLL of blacklisting clients.
3322 static struct Blacklisters *bl_tail;
3326 * Context we use when performing a blacklist check.
3328 struct BlacklistCheck
3332 * This is a linked list.
3334 struct BlacklistCheck *next;
3337 * This is a linked list.
3339 struct BlacklistCheck *prev;
3342 * Peer being checked.
3344 struct GNUNET_PeerIdentity peer;
3347 * Option for setup neighbour afterwards.
3352 * Continuation to call with the result.
3354 SetupContinuation cont;
3362 * Current transmission request handle for this client, or NULL if no
3363 * request is pending.
3365 struct GNUNET_CONNECTION_TransmitHandle *th;
3368 * Our current position in the blacklisters list.
3370 struct Blacklisters *bl_pos;
3373 * Current task performing the check.
3375 GNUNET_SCHEDULER_TaskIdentifier task;
3380 * Head of DLL of active blacklisting queries.
3382 static struct BlacklistCheck *bc_head;
3385 * Tail of DLL of active blacklisting queries.
3387 static struct BlacklistCheck *bc_tail;
3391 * Perform next action in the blacklist check.
3393 * @param cls the 'struct BlacklistCheck*'
3397 do_blacklist_check (void *cls,
3398 const struct GNUNET_SCHEDULER_TaskContext *tc);
3401 * Transmit blacklist query to the client.
3403 * @param cls the 'struct BlacklistCheck'
3404 * @param size number of bytes allowed
3405 * @param buf where to copy the message
3406 * @return number of bytes copied to buf
3409 transmit_blacklist_message (void *cls,
3413 struct BlacklistCheck *bc = cls;
3414 struct Blacklisters *bl;
3415 struct BlacklistMessage bm;
3420 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3421 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3423 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3424 "Failed to send blacklist test for peer `%s' to client\n",
3425 GNUNET_i2s (&bc->peer));
3429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3430 "Sending blacklist test for peer `%s' to client\n",
3431 GNUNET_i2s (&bc->peer));
3434 bm.header.size = htons (sizeof (struct BlacklistMessage));
3435 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3436 bm.is_allowed = htonl (0);
3438 memcpy (buf, &bm, sizeof (bm));
3439 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3445 * Perform next action in the blacklist check.
3447 * @param cls the 'struct BlacklistCheck*'
3451 do_blacklist_check (void *cls,
3452 const struct GNUNET_SCHEDULER_TaskContext *tc)
3454 struct BlacklistCheck *bc = cls;
3455 struct Blacklisters *bl;
3457 bc->task = GNUNET_SCHEDULER_NO_TASK;
3462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3464 GNUNET_i2s (&bc->peer));
3466 bc->cont (bc->cont_cls,
3467 setup_new_neighbour (&bc->peer, bc->do_hello));
3474 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3475 sizeof (struct BlacklistMessage),
3476 GNUNET_TIME_UNIT_FOREVER_REL,
3477 &transmit_blacklist_message,
3484 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3485 * does not yet exist, check the blacklist. If the blacklist says creating
3486 * one is acceptable, create one and call the continuation; otherwise
3487 * call the continuation with NULL.
3489 * @param peer peer to setup or look up a struct NeighbourList for
3490 * @param do_hello should we also schedule sending our HELLO to the peer
3491 * if this is a new record
3492 * @param cont function to call with the 'struct NeigbhbourList*'
3493 * @param cont_cls closure for cont
3496 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3498 SetupContinuation cont,
3501 struct NeighbourList *n;
3502 struct BlacklistCheck *bc;
3504 n = find_neighbour(peer);
3508 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3509 "Neighbour record exists for peer `%s'\n",
3516 if (bl_head == NULL)
3519 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3521 setup_new_neighbour(peer, do_hello);
3524 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3525 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3527 bc->do_hello = do_hello;
3529 bc->cont_cls = cont_cls;
3530 bc->bl_pos = bl_head;
3531 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3537 * Function called with the result of querying a new blacklister about
3538 * it being allowed (or not) to continue to talk to an existing neighbour.
3540 * @param cls the original 'struct NeighbourList'
3541 * @param n NULL if we need to disconnect
3544 confirm_or_drop_neighbour (void *cls,
3545 struct NeighbourList *n)
3547 struct NeighbourList * orig = cls;
3552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3553 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3554 "confirm_or_drop_neighboUr");
3556 GNUNET_STATISTICS_update (stats,
3557 gettext_noop ("# disconnects due to blacklist"),
3560 disconnect_neighbour (orig, GNUNET_NO);
3566 * Handle a request to start a blacklist.
3568 * @param cls closure (always NULL)
3569 * @param client identification of the client
3570 * @param message the actual message
3573 handle_blacklist_init (void *cls,
3574 struct GNUNET_SERVER_Client *client,
3575 const struct GNUNET_MessageHeader *message)
3577 struct Blacklisters *bl;
3578 struct BlacklistCheck *bc;
3579 struct NeighbourList *n;
3584 if (bl->client == client)
3587 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3592 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3593 bl->client = client;
3594 GNUNET_SERVER_client_keep (client);
3595 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3596 /* confirm that all existing connections are OK! */
3600 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3601 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3603 bc->do_hello = GNUNET_NO;
3604 bc->cont = &confirm_or_drop_neighbour;
3607 if (n == neighbours) /* all would wait for the same client, no need to
3608 create more than just the first task right now */
3609 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3617 * Handle a request to blacklist a peer.
3619 * @param cls closure (always NULL)
3620 * @param client identification of the client
3621 * @param message the actual message
3624 handle_blacklist_reply (void *cls,
3625 struct GNUNET_SERVER_Client *client,
3626 const struct GNUNET_MessageHeader *message)
3628 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3629 struct Blacklisters *bl;
3630 struct BlacklistCheck *bc;
3633 while ( (bl != NULL) &&
3634 (bl->client != client) )
3639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3640 "Blacklist client disconnected\n");
3642 /* FIXME: other error handling here!? */
3643 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3648 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3652 "Blacklist check failed, peer not allowed\n");
3654 bc->cont (bc->cont_cls, NULL);
3655 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3662 "Blacklist check succeeded, continuing with checks\n");
3664 bc->bl_pos = bc->bl_pos->next;
3665 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3668 /* check if any other bc's are waiting for this blacklister */
3672 if ( (bc->bl_pos == bl) &&
3673 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3674 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3682 * Send periodic PING messages to a given foreign address.
3684 * @param cls our 'struct PeriodicValidationContext*'
3685 * @param tc task context
3688 send_periodic_ping (void *cls,
3689 const struct GNUNET_SCHEDULER_TaskContext *tc)
3691 struct ForeignAddressList *peer_address = cls;
3692 struct TransportPlugin *tp;
3693 struct ValidationEntry *va;
3694 struct NeighbourList *neighbour;
3695 struct TransportPingMessage ping;
3696 struct CheckAddressExistsClosure caec;
3698 uint16_t hello_size;
3702 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3705 GNUNET_assert (peer_address != NULL);
3706 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3708 tp = peer_address->ready_list->plugin;
3709 neighbour = peer_address->ready_list->neighbour;
3710 if (GNUNET_YES != neighbour->public_key_valid)
3712 /* no public key yet, try again later */
3713 schedule_next_ping (peer_address);
3716 caec.addr = peer_address->addr;
3717 caec.addrlen = peer_address->addrlen;
3718 caec.tname = tp->short_name;
3719 caec.session = peer_address->session;
3720 caec.exists = GNUNET_NO;
3722 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3723 &check_address_exists,
3725 if (caec.exists == GNUNET_YES)
3727 /* During validation attempts we will likely trigger the other
3728 peer trying to validate our address which in turn will cause
3729 it to send us its HELLO, so we expect to hit this case rather
3730 frequently. Only print something if we are very verbose. */
3731 #if DEBUG_TRANSPORT > 1
3732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3733 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3734 (peer_address->addr != NULL)
3735 ? a2s (tp->short_name,
3737 peer_address->addrlen)
3740 GNUNET_i2s (&neighbour->id));
3742 schedule_next_ping (peer_address);
3745 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3746 va->transport_name = GNUNET_strdup (tp->short_name);
3747 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3749 va->send_time = GNUNET_TIME_absolute_get();
3750 va->session = peer_address->session;
3751 if (peer_address->addr != NULL)
3753 va->addr = (const void*) &va[1];
3754 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3755 va->addrlen = peer_address->addrlen;
3757 memcpy(&va->publicKey,
3758 &neighbour->publicKey,
3759 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3761 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3762 &timeout_hello_validation,
3764 GNUNET_CONTAINER_multihashmap_put (validation_map,
3765 &neighbour->id.hashPubKey,
3767 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3769 if (peer_address->validated != GNUNET_YES)
3770 hello_size = GNUNET_HELLO_size(our_hello);
3774 tsize = sizeof(struct TransportPingMessage) + hello_size;
3776 if (peer_address->addr != NULL)
3778 slen = strlen (tp->short_name) + 1;
3779 tsize += slen + peer_address->addrlen;
3783 slen = 0; /* make gcc happy */
3785 message_buf = GNUNET_malloc(tsize);
3786 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3787 ping.challenge = htonl(va->challenge);
3788 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3789 if (peer_address->validated != GNUNET_YES)
3791 memcpy(message_buf, our_hello, hello_size);
3794 if (peer_address->addr != NULL)
3796 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3797 peer_address->addrlen +
3799 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3802 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3804 peer_address->addrlen);
3808 ping.header.size = htons(sizeof(struct TransportPingMessage));
3811 memcpy(&message_buf[hello_size],
3813 sizeof(struct TransportPingMessage));
3815 #if DEBUG_TRANSPORT_REVALIDATION
3816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3817 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3818 (peer_address->addr != NULL)
3819 ? a2s (peer_address->plugin->short_name,
3821 peer_address->addrlen)
3824 GNUNET_i2s (&neighbour->id),
3825 "HELLO", hello_size,
3828 if (peer_address->validated != GNUNET_YES)
3829 GNUNET_STATISTICS_update (stats,
3830 gettext_noop ("# PING with HELLO messages sent"),
3834 GNUNET_STATISTICS_update (stats,
3835 gettext_noop ("# PING without HELLO messages sent"),
3838 GNUNET_STATISTICS_update (stats,
3839 gettext_noop ("# PING messages sent for re-validation"),
3842 transmit_to_peer (NULL, peer_address,
3843 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3844 HELLO_VERIFICATION_TIMEOUT,
3846 GNUNET_YES, neighbour);
3847 GNUNET_free(message_buf);
3848 schedule_next_ping (peer_address);
3853 * Schedule the job that will cause us to send a PING to the
3854 * foreign address to evaluate its validity and latency.
3856 * @param fal address to PING
3859 schedule_next_ping (struct ForeignAddressList *fal)
3861 struct GNUNET_TIME_Relative delay;
3863 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3865 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3866 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3868 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3869 delay.rel_value /= 2; /* do before expiration */
3870 delay = GNUNET_TIME_relative_min (delay,
3871 LATENCY_EVALUATION_MAX_DELAY);
3872 if (GNUNET_YES != fal->estimated)
3874 delay = GNUNET_TIME_UNIT_ZERO;
3875 fal->estimated = GNUNET_YES;
3878 if (GNUNET_YES == fal->connected)
3880 delay = GNUNET_TIME_relative_min (delay,
3881 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3883 /* FIXME: also adjust delay based on how close the last
3884 observed latency is to the latency of the best alternative */
3885 /* bound how fast we can go */
3886 delay = GNUNET_TIME_relative_max (delay,
3887 GNUNET_TIME_UNIT_SECONDS);
3888 /* randomize a bit (to avoid doing all at the same time) */
3889 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3891 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3892 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3893 &send_periodic_ping,
3901 * Function that will be called if we receive some payload
3902 * from another peer.
3904 * @param message the payload
3905 * @param n peer who claimed to be the sender
3908 handle_payload_message (const struct GNUNET_MessageHeader *message,
3909 struct NeighbourList *n)
3911 struct InboundMessage *im;
3912 struct TransportClient *cpos;
3915 msize = ntohs (message->size);
3916 if (n->received_pong == GNUNET_NO)
3919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3920 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3921 ntohs (message->type),
3922 ntohs (message->size),
3923 GNUNET_i2s (&n->id));
3925 GNUNET_free_non_null (n->pre_connect_message_buffer);
3926 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3927 memcpy (n->pre_connect_message_buffer, message, msize);
3932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3933 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3934 ntohs (message->type),
3935 ntohs (message->size),
3936 GNUNET_i2s (&n->id));
3938 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3941 n->quota_violation_count++;
3943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3944 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3945 n->in_tracker.available_bytes_per_s__,
3946 n->quota_violation_count);
3948 /* Discount 32k per violation */
3949 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3954 if (n->quota_violation_count > 0)
3956 /* try to add 32k back */
3957 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3959 n->quota_violation_count--;
3962 GNUNET_STATISTICS_update (stats,
3963 gettext_noop ("# payload received from other peers"),
3966 /* transmit message to all clients */
3967 uint32_t ats_count = 2;
3968 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3969 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3972 im = GNUNET_malloc (size);
3973 im->header.size = htons (size);
3974 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3976 im->ats_count = htonl(ats_count);
3977 /* Setting ATS data */
3978 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3979 (&(im->ats))[0].value = htonl (n->distance);
3980 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3981 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3982 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3983 (&(im->ats))[ats_count].value = htonl (0);
3985 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3987 while (cpos != NULL)
3989 transmit_to_client (cpos, &im->header, GNUNET_YES);
3997 * Iterator over hash map entries. Checks if the given validation
3998 * entry is for the same challenge as what is given in the PONG.
4000 * @param cls the 'struct TransportPongMessage*'
4001 * @param key peer identity
4002 * @param value value in the hash map ('struct ValidationEntry')
4003 * @return GNUNET_YES if we should continue to
4004 * iterate (mismatch), GNUNET_NO if not (entry matched)
4007 check_pending_validation (void *cls,
4008 const GNUNET_HashCode * key,
4011 const struct TransportPongMessage *pong = cls;
4012 struct ValidationEntry *ve = value;
4013 struct AddValidatedAddressContext avac;
4014 unsigned int challenge = ntohl(pong->challenge);
4015 struct GNUNET_HELLO_Message *hello;
4016 struct GNUNET_PeerIdentity target;
4017 struct NeighbourList *n;
4018 struct ForeignAddressList *fal;
4019 struct OwnAddressList *oal;
4020 struct TransportPlugin *tp;
4021 struct GNUNET_MessageHeader *prem;
4027 ps = ntohs (pong->header.size);
4028 if (ps < sizeof (struct TransportPongMessage))
4030 GNUNET_break_op (0);
4033 addr = (const char*) &pong[1];
4034 slen = strlen (ve->transport_name) + 1;
4035 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4036 (ve->challenge != challenge) ||
4037 (addr[slen-1] != '\0') ||
4038 (0 != strcmp (addr, ve->transport_name)) ||
4039 (ntohl (pong->purpose.size)
4040 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4042 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4043 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4048 alen = ps - sizeof (struct TransportPongMessage) - slen;
4049 switch (ntohl (pong->purpose.purpose))
4051 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4052 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4053 (0 != memcmp (&addr[slen],
4057 return GNUNET_YES; /* different entry, keep trying! */
4059 if (0 != memcmp (&pong->pid,
4061 sizeof (struct GNUNET_PeerIdentity)))
4063 GNUNET_break_op (0);
4067 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4072 GNUNET_break_op (0);
4077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4078 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4080 a2s (ve->transport_name,
4081 (const struct sockaddr *) ve->addr,
4083 ve->transport_name);
4086 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4087 if (0 != memcmp (&pong->pid,
4089 sizeof (struct GNUNET_PeerIdentity)))
4093 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4096 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4097 GNUNET_i2s (&my_identity),
4103 if (ve->addrlen != 0)
4105 /* must have been for a different validation entry */
4108 tp = find_transport (ve->transport_name);
4114 oal = tp->addresses;
4117 if ( (oal->addrlen == alen) &&
4118 (0 == memcmp (&oal[1],
4126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4127 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4128 GNUNET_i2s (&pong->pid),
4129 a2s (ve->transport_name,
4132 /* FIXME: since the sender of the PONG currently uses the
4133 wrong address (see FIMXE there!), we cannot run a
4134 proper check here... */
4140 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4145 GNUNET_break_op (0);
4150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4151 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4153 a2s (ve->transport_name,
4156 ve->transport_name);
4160 GNUNET_break_op (0);
4163 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4165 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4166 _("Received expired signature. Check system time.\n"));
4169 GNUNET_STATISTICS_update (stats,
4170 gettext_noop ("# address validation successes"),
4173 /* create the updated HELLO */
4174 GNUNET_CRYPTO_hash (&ve->publicKey,
4175 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4176 &target.hashPubKey);
4177 if (ve->addr != NULL)
4179 avac.done = GNUNET_NO;
4181 hello = GNUNET_HELLO_create (&ve->publicKey,
4182 &add_validated_address,
4184 GNUNET_PEERINFO_add_peer (peerinfo,
4186 GNUNET_free (hello);
4188 n = find_neighbour (&target);
4191 n->publicKey = ve->publicKey;
4192 n->public_key_valid = GNUNET_YES;
4193 fal = add_peer_address (n,
4198 GNUNET_assert (fal != NULL);
4199 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4200 fal->validated = GNUNET_YES;
4201 mark_address_connected (fal);
4202 GNUNET_STATISTICS_update (stats,
4203 gettext_noop ("# peer addresses considered valid"),
4206 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4207 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4209 schedule_next_ping (fal);
4210 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4211 n->latency = fal->latency;
4213 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4215 n->distance = fal->distance;
4216 if (GNUNET_NO == n->received_pong)
4218 n->received_pong = GNUNET_YES;
4219 notify_clients_connect (&target, n->latency, n->distance);
4220 if (NULL != (prem = n->pre_connect_message_buffer))
4222 n->pre_connect_message_buffer = NULL;
4223 handle_payload_message (prem, n);
4227 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4229 GNUNET_SCHEDULER_cancel (n->retry_task);
4230 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4231 try_transmission_to_peer (n);
4235 /* clean up validation entry */
4236 GNUNET_assert (GNUNET_YES ==
4237 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4240 abort_validation (NULL, NULL, ve);
4246 * Function that will be called if we receive a validation
4247 * of an address challenge that we transmitted to another
4248 * peer. Note that the validation should only be considered
4249 * acceptable if the challenge matches AND if the sender
4250 * address is at least a plausible address for this peer
4251 * (otherwise we may be seeing a MiM attack).
4253 * @param cls closure
4254 * @param message the pong message
4255 * @param peer who responded to our challenge
4256 * @param sender_address string describing our sender address (as observed
4257 * by the other peer in binary format)
4258 * @param sender_address_len number of bytes in 'sender_address'
4261 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4262 const struct GNUNET_PeerIdentity *peer,
4263 const char *sender_address,
4264 size_t sender_address_len)
4266 if (0 == memcmp (peer,
4268 sizeof (struct GNUNET_PeerIdentity)))
4270 /* PONG send to self, ignore */
4271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4272 "Receiving `%s' message from myself\n",
4276 #if DEBUG_TRANSPORT > 1
4277 /* we get tons of these that just get discarded, only log
4278 if we are quite verbose */
4279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4280 "Receiving `%s' message from `%4s'.\n", "PONG",
4283 GNUNET_STATISTICS_update (stats,
4284 gettext_noop ("# PONG messages received"),
4287 if (GNUNET_SYSERR !=
4288 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4290 &check_pending_validation,
4293 /* This is *expected* to happen a lot since we send
4294 PONGs to *all* known addresses of the sender of
4295 the PING, so most likely we get multiple PONGs
4296 per PING, and all but the first PONG will end up
4297 here. So really we should not print anything here
4298 unless we want to be very, very verbose... */
4299 #if DEBUG_TRANSPORT > 2
4300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4301 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4313 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4315 * @param cls the 'struct ValidationEntry*'
4316 * @param neighbour neighbour to validate, NULL if validation failed
4319 transmit_hello_and_ping (void *cls,
4320 struct NeighbourList *neighbour)
4322 struct ValidationEntry *va = cls;
4323 struct ForeignAddressList *peer_address;
4324 struct TransportPingMessage ping;
4325 uint16_t hello_size;
4328 struct GNUNET_PeerIdentity id;
4331 GNUNET_CRYPTO_hash (&va->publicKey,
4332 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4334 if (neighbour == NULL)
4336 /* FIXME: stats... */
4337 GNUNET_break (GNUNET_OK ==
4338 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4341 abort_validation (NULL, NULL, va);
4344 neighbour->publicKey = va->publicKey;
4345 neighbour->public_key_valid = GNUNET_YES;
4346 peer_address = add_peer_address (neighbour,
4347 va->transport_name, NULL,
4348 (const void*) &va[1],
4350 if (peer_address == NULL)
4352 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4353 "Failed to add peer `%4s' for plugin `%s'\n",
4354 GNUNET_i2s (&neighbour->id),
4355 va->transport_name);
4356 GNUNET_break (GNUNET_OK ==
4357 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4360 abort_validation (NULL, NULL, va);
4363 if (NULL == our_hello)
4364 refresh_hello_task (NULL, NULL);
4365 hello_size = GNUNET_HELLO_size(our_hello);
4366 slen = strlen(va->transport_name) + 1;
4367 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4368 message_buf = GNUNET_malloc(tsize);
4369 ping.challenge = htonl(va->challenge);
4370 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4371 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4372 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4373 memcpy(message_buf, our_hello, hello_size);
4374 memcpy(&message_buf[hello_size],
4376 sizeof(struct TransportPingMessage));
4377 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4380 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4385 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4388 : a2s (va->transport_name,
4389 (const void*) &va[1], va->addrlen),
4391 GNUNET_i2s (&neighbour->id),
4392 "HELLO", hello_size,
4393 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4396 GNUNET_STATISTICS_update (stats,
4397 gettext_noop ("# PING messages sent for initial validation"),
4400 transmit_to_peer (NULL, peer_address,
4401 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4402 HELLO_VERIFICATION_TIMEOUT,
4404 GNUNET_YES, neighbour);
4405 GNUNET_free(message_buf);
4410 * Check if the given address is already being validated; if not,
4411 * append the given address to the list of entries that are being be
4412 * validated and initiate validation.
4414 * @param cls closure ('struct CheckHelloValidatedContext *')
4415 * @param tname name of the transport
4416 * @param expiration expiration time
4417 * @param addr the address
4418 * @param addrlen length of the address
4419 * @return GNUNET_OK (always)
4422 run_validation (void *cls,
4424 struct GNUNET_TIME_Absolute expiration,
4428 struct CheckHelloValidatedContext *chvc = cls;
4429 struct GNUNET_PeerIdentity id;
4430 struct TransportPlugin *tp;
4431 struct ValidationEntry *va;
4432 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4433 struct CheckAddressExistsClosure caec;
4434 struct OwnAddressList *oal;
4436 GNUNET_assert (addr != NULL);
4438 GNUNET_STATISTICS_update (stats,
4439 gettext_noop ("# peer addresses scheduled for validation"),
4442 tp = find_transport (tname);
4445 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4446 GNUNET_ERROR_TYPE_BULK,
4448 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4450 GNUNET_STATISTICS_update (stats,
4451 gettext_noop ("# peer addresses not validated (plugin not available)"),
4456 /* check if this is one of our own addresses */
4457 oal = tp->addresses;
4460 if ( (oal->addrlen == addrlen) &&
4461 (0 == memcmp (&oal[1],
4465 /* not plausible, this address is equivalent to our own address! */
4466 GNUNET_STATISTICS_update (stats,
4467 gettext_noop ("# peer addresses not validated (loopback)"),
4474 GNUNET_HELLO_get_key (chvc->hello, &pk);
4475 GNUNET_CRYPTO_hash (&pk,
4477 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4480 if (is_blacklisted(&id, tp))
4483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4484 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4492 caec.addrlen = addrlen;
4493 caec.session = NULL;
4495 caec.exists = GNUNET_NO;
4496 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4497 &check_address_exists,
4499 if (caec.exists == GNUNET_YES)
4501 /* During validation attempts we will likely trigger the other
4502 peer trying to validate our address which in turn will cause
4503 it to send us its HELLO, so we expect to hit this case rather
4504 frequently. Only print something if we are very verbose. */
4505 #if DEBUG_TRANSPORT > 1
4506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4507 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4508 a2s (tname, addr, addrlen),
4512 GNUNET_STATISTICS_update (stats,
4513 gettext_noop ("# peer addresses not validated (in progress)"),
4518 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4521 va->transport_name = GNUNET_strdup (tname);
4522 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4524 va->send_time = GNUNET_TIME_absolute_get();
4525 va->addr = (const void*) &va[1];
4526 memcpy (&va[1], addr, addrlen);
4527 va->addrlen = addrlen;
4528 GNUNET_HELLO_get_key (chvc->hello,
4530 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4531 &timeout_hello_validation,
4533 GNUNET_CONTAINER_multihashmap_put (validation_map,
4536 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4537 setup_peer_check_blacklist (&id, GNUNET_NO,
4538 &transmit_hello_and_ping,
4545 * Check if addresses in validated hello "h" overlap with
4546 * those in "chvc->hello" and validate the rest.
4548 * @param cls closure
4549 * @param peer id of the peer, NULL for last call
4550 * @param h hello message for the peer (can be NULL)
4551 * @param err_msg NULL if successful, otherwise contains error message
4554 check_hello_validated (void *cls,
4555 const struct GNUNET_PeerIdentity *peer,
4556 const struct GNUNET_HELLO_Message *h,
4557 const char *err_msg)
4559 struct CheckHelloValidatedContext *chvc = cls;
4560 struct GNUNET_HELLO_Message *plain_hello;
4561 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4562 struct GNUNET_PeerIdentity target;
4563 struct NeighbourList *n;
4565 if (err_msg != NULL)
4568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4569 _("Error in communication with PEERINFO service: %s\n"),
4577 GNUNET_STATISTICS_update (stats,
4578 gettext_noop ("# outstanding peerinfo iterate requests"),
4582 if (GNUNET_NO == chvc->hello_known)
4584 /* notify PEERINFO about the peer now, so that we at least
4585 have the public key if some other component needs it */
4586 GNUNET_HELLO_get_key (chvc->hello, &pk);
4587 GNUNET_CRYPTO_hash (&pk,
4588 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4589 &target.hashPubKey);
4590 plain_hello = GNUNET_HELLO_create (&pk,
4593 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4594 GNUNET_free (plain_hello);
4595 #if DEBUG_TRANSPORT_HELLO
4596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4597 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4599 GNUNET_i2s (&target));
4601 GNUNET_STATISTICS_update (stats,
4602 gettext_noop ("# new HELLOs requiring full validation"),
4605 GNUNET_HELLO_iterate_addresses (chvc->hello,
4612 GNUNET_STATISTICS_update (stats,
4613 gettext_noop ("# duplicate HELLO (peer known)"),
4618 if (chvc->ve_count == 0)
4620 GNUNET_CONTAINER_DLL_remove (chvc_head,
4629 #if DEBUG_TRANSPORT_HELLO
4630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4631 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4635 chvc->hello_known = GNUNET_YES;
4636 n = find_neighbour (peer);
4639 #if DEBUG_TRANSPORT_HELLO
4640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4641 "Calling hello_iterate_addresses for %s!\n",
4644 GNUNET_HELLO_iterate_addresses (h,
4646 &add_to_foreign_address_list,
4648 try_transmission_to_peer (n);
4652 #if DEBUG_TRANSPORT_HELLO
4653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4654 "No existing neighbor record for %s!\n",
4657 GNUNET_STATISTICS_update (stats,
4658 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4662 GNUNET_STATISTICS_update (stats,
4663 gettext_noop ("# HELLO validations (update case)"),
4666 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4668 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4675 * Process HELLO-message.
4677 * @param plugin transport involved, may be NULL
4678 * @param message the actual message
4679 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4682 process_hello (struct TransportPlugin *plugin,
4683 const struct GNUNET_MessageHeader *message)
4686 struct GNUNET_PeerIdentity target;
4687 const struct GNUNET_HELLO_Message *hello;
4688 struct CheckHelloValidatedContext *chvc;
4689 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4690 struct NeighbourList *n;
4691 #if DEBUG_TRANSPORT_HELLO > 2
4695 hsize = ntohs (message->size);
4696 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4697 (hsize < sizeof (struct GNUNET_MessageHeader)))
4700 return GNUNET_SYSERR;
4702 GNUNET_STATISTICS_update (stats,
4703 gettext_noop ("# HELLOs received for validation"),
4707 hello = (const struct GNUNET_HELLO_Message *) message;
4708 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4710 #if DEBUG_TRANSPORT_HELLO
4711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4712 "Unable to get public key from `%s' for `%4s'!\n",
4714 GNUNET_i2s (&target));
4716 GNUNET_break_op (0);
4717 return GNUNET_SYSERR;
4719 GNUNET_CRYPTO_hash (&publicKey,
4720 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4721 &target.hashPubKey);
4723 #if DEBUG_TRANSPORT_HELLO
4724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4725 "Received `%s' message for `%4s'\n",
4727 GNUNET_i2s (&target));
4729 if (0 == memcmp (&my_identity,
4731 sizeof (struct GNUNET_PeerIdentity)))
4733 GNUNET_STATISTICS_update (stats,
4734 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4739 n = find_neighbour (&target);
4741 (! n->public_key_valid) )
4743 GNUNET_HELLO_get_key (hello, &n->publicKey);
4744 n->public_key_valid = GNUNET_YES;
4747 /* check if load is too high before doing expensive stuff */
4748 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4750 GNUNET_STATISTICS_update (stats,
4751 gettext_noop ("# HELLOs ignored due to high load"),
4754 #if DEBUG_TRANSPORT_HELLO
4755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4756 "Ignoring `%s' for `%4s', load too high.\n",
4758 GNUNET_i2s (&target));
4765 while (NULL != chvc)
4767 if (GNUNET_HELLO_equals (hello,
4769 GNUNET_TIME_absolute_get ()).abs_value > 0)
4771 #if DEBUG_TRANSPORT_HELLO > 2
4772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4773 "Received duplicate `%s' message for `%4s'; ignored\n",
4775 GNUNET_i2s (&target));
4777 return GNUNET_OK; /* validation already pending */
4779 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4780 GNUNET_break (0 != memcmp (hello, chvc->hello,
4781 GNUNET_HELLO_size(hello)));
4786 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4787 if ((NULL != temp_neighbor))
4789 fprintf(stderr, "Already know peer, ignoring hello\n");
4794 #if DEBUG_TRANSPORT_HELLO > 2
4797 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4800 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4803 GNUNET_i2s (&target),
4805 GNUNET_HELLO_size(hello));
4810 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4812 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4813 memcpy (&chvc[1], hello, hsize);
4814 GNUNET_CONTAINER_DLL_insert (chvc_head,
4817 /* finally, check if HELLO was previously validated
4818 (continuation will then schedule actual validation) */
4819 GNUNET_STATISTICS_update (stats,
4820 gettext_noop ("# peerinfo process hello iterate requests"),
4823 GNUNET_STATISTICS_update (stats,
4824 gettext_noop ("# outstanding peerinfo iterate requests"),
4827 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4829 HELLO_VERIFICATION_TIMEOUT,
4830 &check_hello_validated, chvc);
4836 * The peer specified by the given neighbour has timed-out or a plugin
4837 * has disconnected. We may either need to do nothing (other plugins
4838 * still up), or trigger a full disconnect and clean up. This
4839 * function updates our state and does the necessary notifications.
4840 * Also notifies our clients that the neighbour is now officially
4843 * @param n the neighbour list entry for the peer
4844 * @param check GNUNET_YES to check if ALL addresses for this peer
4845 * are gone, GNUNET_NO to force a disconnect of the peer
4846 * regardless of whether other addresses exist.
4849 disconnect_neighbour (struct NeighbourList *n, int check)
4851 struct ReadyList *rpos;
4852 struct NeighbourList *npos;
4853 struct NeighbourList *nprev;
4854 struct MessageQueue *mq;
4855 struct ForeignAddressList *peer_addresses;
4856 struct ForeignAddressList *peer_pos;
4858 if (GNUNET_YES == n->in_disconnect)
4860 if (GNUNET_YES == check)
4863 while (NULL != rpos)
4865 peer_addresses = rpos->addresses;
4866 while (peer_addresses != NULL)
4868 /* Do not disconnect if: an address is connected or an inbound address exists */
4869 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4873 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4874 GNUNET_i2s (&n->id),
4875 a2s (peer_addresses->ready_list->plugin->short_name,
4876 peer_addresses->addr,
4877 peer_addresses->addrlen));
4879 return; /* still connected */
4881 peer_addresses = peer_addresses->next;
4887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4888 "Disconnecting from `%4s'\n",
4889 GNUNET_i2s (&n->id));
4891 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4893 /* notify all clients about disconnect */
4894 if (GNUNET_YES == n->received_pong)
4896 n->received_pong = GNUNET_NO;
4897 notify_clients_disconnect (&n->id);
4900 ats_modify_problem_state(ats, ATS_MODIFIED);
4902 /* clean up all plugins, cancel connections and pending transmissions */
4903 while (NULL != (rpos = n->plugins))
4905 n->plugins = rpos->next;
4906 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4907 while (rpos->addresses != NULL)
4909 peer_pos = rpos->addresses;
4910 rpos->addresses = peer_pos->next;
4911 if (peer_pos->connected == GNUNET_YES)
4912 GNUNET_STATISTICS_update (stats,
4913 gettext_noop ("# connected addresses"),
4916 if (GNUNET_YES == peer_pos->validated)
4917 GNUNET_STATISTICS_update (stats,
4918 gettext_noop ("# peer addresses considered valid"),
4921 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4923 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4924 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4926 GNUNET_free(peer_pos->ressources);
4927 peer_pos->ressources = NULL;
4928 GNUNET_free(peer_pos->quality);
4929 peer_pos->ressources = NULL;
4930 GNUNET_free(peer_pos);
4935 /* free all messages on the queue */
4936 while (NULL != (mq = n->messages_head))
4938 GNUNET_STATISTICS_update (stats,
4939 gettext_noop ("# bytes in message queue for other peers"),
4940 - (int64_t) mq->message_buf_size,
4942 GNUNET_STATISTICS_update (stats,
4943 gettext_noop ("# bytes discarded due to disconnect"),
4944 mq->message_buf_size,
4946 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4949 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4951 sizeof(struct GNUNET_PeerIdentity)));
4955 while (NULL != (mq = n->cont_head))
4958 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4961 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4963 sizeof(struct GNUNET_PeerIdentity)));
4967 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4969 GNUNET_SCHEDULER_cancel (n->timeout_task);
4970 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4972 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4974 GNUNET_SCHEDULER_cancel (n->retry_task);
4975 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4977 if (n->piter != NULL)
4979 GNUNET_PEERINFO_iterate_cancel (n->piter);
4980 GNUNET_STATISTICS_update (stats,
4981 gettext_noop ("# outstanding peerinfo iterate requests"),
4987 /* remove n from neighbours list */
4990 while ((npos != NULL) && (npos != n))
4995 GNUNET_assert (npos != NULL);
4997 neighbours = n->next;
4999 nprev->next = n->next;
5001 /* finally, free n itself */
5002 GNUNET_STATISTICS_update (stats,
5003 gettext_noop ("# active neighbours"),
5006 GNUNET_free_non_null (n->pre_connect_message_buffer);
5012 * We have received a PING message from someone. Need to send a PONG message
5013 * in response to the peer by any means necessary.
5016 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5017 const struct GNUNET_PeerIdentity *peer,
5018 struct Session *session,
5019 const char *sender_address,
5020 uint16_t sender_address_len)
5022 struct TransportPlugin *plugin = cls;
5023 struct SessionHeader *session_header = (struct SessionHeader*) session;
5024 struct TransportPingMessage *ping;
5025 struct TransportPongMessage *pong;
5026 struct NeighbourList *n;
5027 struct ReadyList *rl;
5028 struct ForeignAddressList *fal;
5029 struct OwnAddressList *oal;
5035 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5037 GNUNET_break_op (0);
5038 return GNUNET_SYSERR;
5041 ping = (struct TransportPingMessage *) message;
5042 if (0 != memcmp (&ping->target,
5043 plugin->env.my_identity,
5044 sizeof (struct GNUNET_PeerIdentity)))
5047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5048 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5050 (sender_address != NULL)
5051 ? a2s (plugin->short_name,
5052 (const struct sockaddr *)sender_address,
5055 GNUNET_i2s (&ping->target));
5057 return GNUNET_SYSERR;
5060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5061 "Processing `%s' from `%s'\n",
5063 (sender_address != NULL)
5064 ? a2s (plugin->short_name,
5065 (const struct sockaddr *)sender_address,
5069 GNUNET_STATISTICS_update (stats,
5070 gettext_noop ("# PING messages received"),
5073 addr = (const char*) &ping[1];
5074 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5075 slen = strlen (plugin->short_name) + 1;
5078 /* peer wants to confirm that we have an outbound connection to him */
5079 if (session == NULL)
5081 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5082 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5084 return GNUNET_SYSERR;
5086 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5087 1) it is NULL when we need to have a real value
5088 2) it is documented to be the address of the sender (source-IP), where
5089 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5093 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5094 a2s (plugin->short_name,
5096 sender_address_len),
5099 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5100 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5101 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5102 pong->purpose.size =
5103 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5105 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5106 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5107 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5108 pong->challenge = ping->challenge;
5109 pong->addrlen = htonl(sender_address_len + slen);
5112 sizeof(struct GNUNET_PeerIdentity));
5116 if ((sender_address!=NULL) && (sender_address_len > 0))
5117 memcpy (&((char*)&pong[1])[slen],
5119 sender_address_len);
5120 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5122 /* create / update cached sig */
5124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5125 "Creating PONG signature to indicate active connection.\n");
5127 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5128 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5129 GNUNET_assert (GNUNET_OK ==
5130 GNUNET_CRYPTO_rsa_sign (my_private_key,
5132 &session_header->pong_signature));
5136 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5138 memcpy (&pong->signature,
5139 &session_header->pong_signature,
5140 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5146 /* peer wants to confirm that this is one of our addresses */
5150 plugin->api->check_address (plugin->api->cls,
5154 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5155 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5156 a2s (plugin->short_name,
5161 oal = plugin->addresses;
5164 if ( (oal->addrlen == alen) &&
5171 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5172 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5173 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5174 pong->purpose.size =
5175 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5177 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5178 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5179 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5180 pong->challenge = ping->challenge;
5181 pong->addrlen = htonl(alen + slen);
5184 sizeof(struct GNUNET_PeerIdentity));
5185 memcpy (&pong[1], plugin->short_name, slen);
5186 memcpy (&((char*)&pong[1])[slen], addr, alen);
5187 if ( (oal != NULL) &&
5188 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5190 /* create / update cached sig */
5192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5193 "Creating PONG signature to indicate ownership.\n");
5195 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5196 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5197 GNUNET_assert (GNUNET_OK ==
5198 GNUNET_CRYPTO_rsa_sign (my_private_key,
5200 &oal->pong_signature));
5201 memcpy (&pong->signature,
5202 &oal->pong_signature,
5203 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5205 else if (oal == NULL)
5207 /* not using cache (typically DV-only) */
5208 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5209 GNUNET_assert (GNUNET_OK ==
5210 GNUNET_CRYPTO_rsa_sign (my_private_key,
5216 /* can used cached version */
5217 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5218 memcpy (&pong->signature,
5219 &oal->pong_signature,
5220 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5223 n = find_neighbour(peer);
5224 GNUNET_assert (n != NULL);
5225 did_pong = GNUNET_NO;
5226 /* first try reliable response transmission */
5230 fal = rl->addresses;
5233 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5236 ntohs (pong->header.size),
5237 TRANSPORT_PONG_PRIORITY,
5238 HELLO_VERIFICATION_TIMEOUT,
5245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5246 "Transmitted PONG to `%s' via reliable mechanism\n",
5249 GNUNET_STATISTICS_update (stats,
5250 gettext_noop ("# PONGs unicast via reliable transport"),
5256 did_pong = GNUNET_YES;
5261 /* no reliable method found, do multicast */
5262 GNUNET_STATISTICS_update (stats,
5263 gettext_noop ("# PONGs multicast to all available addresses"),
5269 fal = rl->addresses;
5272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5273 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5275 a2s (rl->plugin->short_name,
5278 rl->plugin->short_name);
5279 transmit_to_peer(NULL, fal,
5280 TRANSPORT_PONG_PRIORITY,
5281 HELLO_VERIFICATION_TIMEOUT,
5283 ntohs(pong->header.size),
5286 did_pong = GNUNET_YES;
5292 if (GNUNET_YES != did_pong)
5293 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5294 _("Could not send PONG to `%s': no address available\n"),
5301 * Function called by the plugin for each received message. Update
5302 * data volumes, possibly notify plugins about reducing the rate at
5303 * which they read from the socket and generally forward to our
5306 * @param cls the "struct TransportPlugin *" we gave to the plugin
5307 * @param peer (claimed) identity of the other peer
5308 * @param message the message, NULL if we only care about
5309 * learning about the delay until we should receive again
5310 * @param ats_data information for automatic transport selection
5311 * @param ats_count number of elements in ats not including 0-terminator
5312 * @param session identifier used for this session (can be NULL)
5313 * @param sender_address binary address of the sender (if observed)
5314 * @param sender_address_len number of bytes in sender_address
5315 * @return how long in ms the plugin should wait until receiving more data
5316 * (plugins that do not support this, can ignore the return value)
5318 static struct GNUNET_TIME_Relative
5319 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5320 const struct GNUNET_MessageHeader *message,
5321 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5323 struct Session *session,
5324 const char *sender_address,
5325 uint16_t sender_address_len)
5327 struct TransportPlugin *plugin = cls;
5328 struct ReadyList *service_context;
5329 struct ForeignAddressList *peer_address;
5331 struct NeighbourList *n;
5332 struct GNUNET_TIME_Relative ret;
5336 if (0 == memcmp (peer,
5338 sizeof (struct GNUNET_PeerIdentity)))
5340 /* refuse to receive from myself */
5342 return GNUNET_TIME_UNIT_FOREVER_REL;
5344 if (is_blacklisted (peer, plugin))
5345 return GNUNET_TIME_UNIT_FOREVER_REL;
5346 n = find_neighbour (peer);
5348 n = setup_new_neighbour (peer, GNUNET_YES);
5349 service_context = n->plugins;
5350 while ((service_context != NULL) && (plugin != service_context->plugin))
5351 service_context = service_context->next;
5352 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5353 peer_address = NULL;
5356 for (c=0; c<ats_count; c++)
5357 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5358 distance = ntohl(ats_data[c].value);
5361 if (message != NULL)
5363 if ( (session != NULL) ||
5364 (sender_address != NULL) )
5365 peer_address = add_peer_address (n,
5369 sender_address_len);
5370 if (peer_address != NULL)
5372 update_addr_ats(peer_address, ats_data, ats_count);
5373 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5375 peer_address->distance = distance;
5376 if (GNUNET_YES == peer_address->validated)
5378 mark_address_connected (peer_address);
5379 schedule_next_ping (peer_address);
5384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5385 "New address is unvalidated, trying to validate it now\n");
5387 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5389 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5390 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5392 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5395 peer_address->timeout
5396 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5398 /* update traffic received amount ... */
5399 msize = ntohs (message->size);
5401 GNUNET_STATISTICS_update (stats,
5402 gettext_noop ("# bytes received from other peers"),
5405 n->distance = distance;
5407 GNUNET_TIME_relative_to_absolute
5408 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5409 GNUNET_SCHEDULER_cancel (n->timeout_task);
5411 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5412 &neighbour_timeout_task, n);
5413 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5415 /* dropping message due to frequent inbound volume violations! */
5416 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5417 GNUNET_ERROR_TYPE_BULK,
5419 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5420 n->in_tracker.available_bytes_per_s__,
5421 n->quota_violation_count);
5422 GNUNET_STATISTICS_update (stats,
5423 gettext_noop ("# bandwidth quota violations by other peers"),
5426 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5428 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5429 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5432 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5433 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5434 /* Force ressource and quality update */
5435 if ((value == 4) && (ats != NULL))
5436 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5437 /* Force cost update */
5438 if ((value == 3) && (ats != NULL))
5439 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5440 /* Force quality update */
5441 if ((value == 2) && (ats != NULL))
5442 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5443 /* Force full rebuild */
5444 if ((value == 1) && (ats != NULL))
5445 ats_modify_problem_state(ats, ATS_MODIFIED);
5450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5451 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5452 ntohs (message->type),
5453 ntohs (message->size),
5456 switch (ntohs (message->type))
5458 case GNUNET_MESSAGE_TYPE_HELLO:
5459 GNUNET_STATISTICS_update (stats,
5460 gettext_noop ("# HELLO messages received from other peers"),
5463 process_hello (plugin, message);
5465 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5466 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5467 if (GNUNET_YES != n->received_pong)
5468 transmit_plain_ping (n);
5470 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5471 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5473 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5476 handle_payload_message (message, n);
5480 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5481 if (ret.rel_value > 0)
5484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5485 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5486 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5487 (unsigned int) n->in_tracker.available_bytes_per_s__,
5488 (unsigned long long) ret.rel_value);
5490 GNUNET_STATISTICS_update (stats,
5491 gettext_noop ("# ms throttling suggested"),
5492 (int64_t) ret.rel_value,
5499 * Handle START-message. This is the first message sent to us
5500 * by any client which causes us to add it to our list.
5502 * @param cls closure (always NULL)
5503 * @param client identification of the client
5504 * @param message the actual message
5507 handle_start (void *cls,
5508 struct GNUNET_SERVER_Client *client,
5509 const struct GNUNET_MessageHeader *message)
5511 const struct StartMessage *start;
5512 struct TransportClient *c;
5513 struct ConnectInfoMessage * cim;
5514 struct NeighbourList *n;
5518 start = (const struct StartMessage*) message;
5520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5521 "Received `%s' request from client\n", "START");
5526 if (c->client == client)
5528 /* client already on our list! */
5530 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5535 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5536 (0 != memcmp (&start->self,
5538 sizeof (struct GNUNET_PeerIdentity))) )
5540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5541 _("Rejecting control connection from peer `%s', which is not me!\n"),
5542 GNUNET_i2s (&start->self));
5543 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5546 c = GNUNET_malloc (sizeof (struct TransportClient));
5550 if (our_hello != NULL)
5553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5554 "Sending our own `%s' to new client\n", "HELLO");
5556 transmit_to_client (c,
5557 (const struct GNUNET_MessageHeader *) our_hello,
5559 /* tell new client about all existing connections */
5561 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5562 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5566 cim = GNUNET_malloc (size);
5567 cim->header.size = htons (size);
5568 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5569 cim->ats_count = htonl(ats_count);
5570 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5571 (&(cim->ats))[2].value = htonl (0);
5575 if (GNUNET_YES == n->received_pong)
5577 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5578 (&cim->ats)[0].value = htonl (n->distance);
5579 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5580 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5582 transmit_to_client (c, &cim->header, GNUNET_NO);
5590 #if DEBUG_TRANSPORT_HELLO
5591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5592 "No HELLO created yet, will transmit HELLO to client later!\n");
5596 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5601 * Handle HELLO-message.
5603 * @param cls closure (always NULL)
5604 * @param client identification of the client
5605 * @param message the actual message
5608 handle_hello (void *cls,
5609 struct GNUNET_SERVER_Client *client,
5610 const struct GNUNET_MessageHeader *message)
5614 GNUNET_STATISTICS_update (stats,
5615 gettext_noop ("# HELLOs received from clients"),
5618 ret = process_hello (NULL, message);
5619 GNUNET_SERVER_receive_done (client, ret);
5624 * Closure for 'transmit_client_message'; followed by
5625 * 'msize' bytes of the actual message.
5627 struct TransmitClientMessageContext
5630 * Client on whom's behalf we are sending.
5632 struct GNUNET_SERVER_Client *client;
5635 * Timeout for the transmission.
5637 struct GNUNET_TIME_Absolute timeout;
5645 * Size of the message in bytes.
5652 * Schedule transmission of a message we got from a client to a peer.
5654 * @param cls the 'struct TransmitClientMessageContext*'
5655 * @param n destination, or NULL on error (in that case, drop the message)
5658 transmit_client_message (void *cls,
5659 struct NeighbourList *n)
5661 struct TransmitClientMessageContext *tcmc = cls;
5662 struct TransportClient *tc;
5665 while ((tc != NULL) && (tc->client != tcmc->client))
5670 transmit_to_peer (tc, NULL, tcmc->priority,
5671 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5673 tcmc->msize, GNUNET_NO, n);
5675 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5676 GNUNET_SERVER_client_drop (tcmc->client);
5682 * Handle SEND-message.
5684 * @param cls closure (always NULL)
5685 * @param client identification of the client
5686 * @param message the actual message
5689 handle_send (void *cls,
5690 struct GNUNET_SERVER_Client *client,
5691 const struct GNUNET_MessageHeader *message)
5693 const struct OutboundMessage *obm;
5694 const struct GNUNET_MessageHeader *obmm;
5695 struct TransmitClientMessageContext *tcmc;
5699 size = ntohs (message->size);
5701 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5704 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5707 GNUNET_STATISTICS_update (stats,
5708 gettext_noop ("# payload received for other peers"),
5711 obm = (const struct OutboundMessage *) message;
5712 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5713 msize = size - sizeof (struct OutboundMessage);
5715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5716 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5717 "SEND", GNUNET_i2s (&obm->peer),
5721 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5722 tcmc->client = client;
5723 tcmc->priority = ntohl (obm->priority);
5724 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5725 tcmc->msize = msize;
5726 /* FIXME: this memcpy can be up to 7% of our total runtime */
5727 memcpy (&tcmc[1], obmm, msize);
5728 GNUNET_SERVER_client_keep (client);
5729 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5730 &transmit_client_message,
5736 * Handle request connect message
5738 * @param cls closure (always NULL)
5739 * @param client identification of the client
5740 * @param message the actual message
5743 handle_request_connect (void *cls,
5744 struct GNUNET_SERVER_Client *client,
5745 const struct GNUNET_MessageHeader *message)
5747 const struct TransportRequestConnectMessage *trcm =
5748 (const struct TransportRequestConnectMessage *) message;
5750 GNUNET_STATISTICS_update (stats,
5751 gettext_noop ("# REQUEST CONNECT messages received"),
5755 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5756 "Received a request connect message for peer `%s'\n",
5757 GNUNET_i2s(&trcm->peer));
5759 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5761 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5766 * Handle SET_QUOTA-message.
5768 * @param cls closure (always NULL)
5769 * @param client identification of the client
5770 * @param message the actual message
5773 handle_set_quota (void *cls,
5774 struct GNUNET_SERVER_Client *client,
5775 const struct GNUNET_MessageHeader *message)
5777 const struct QuotaSetMessage *qsm =
5778 (const struct QuotaSetMessage *) message;
5779 struct NeighbourList *n;
5781 GNUNET_STATISTICS_update (stats,
5782 gettext_noop ("# SET QUOTA messages received"),
5785 n = find_neighbour (&qsm->peer);
5788 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5789 GNUNET_STATISTICS_update (stats,
5790 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5797 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5799 (unsigned int) ntohl (qsm->quota.value__),
5800 (unsigned int) n->in_tracker.available_bytes_per_s__,
5801 GNUNET_i2s (&qsm->peer));
5803 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5805 if (0 == ntohl (qsm->quota.value__))
5808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5809 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5812 GNUNET_STATISTICS_update (stats,
5813 gettext_noop ("# disconnects due to quota of 0"),
5816 disconnect_neighbour (n, GNUNET_NO);
5818 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5823 * Take the given address and append it to the set of results sent back to
5826 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5827 * @param address the resolved name, NULL to indicate the last response
5830 transmit_address_to_client (void *cls, const char *address)
5832 struct GNUNET_SERVER_TransmitContext *tc = cls;
5835 if (NULL != address)
5837 slen = strlen (address) + 1;
5838 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5839 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5843 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5849 * Handle AddressLookup-message.
5851 * @param cls closure (always NULL)
5852 * @param client identification of the client
5853 * @param message the actual message
5856 handle_address_lookup (void *cls,
5857 struct GNUNET_SERVER_Client *client,
5858 const struct GNUNET_MessageHeader *message)
5860 const struct AddressLookupMessage *alum;
5861 struct TransportPlugin *lsPlugin;
5862 const char *nameTransport;
5863 const char *address;
5865 struct GNUNET_SERVER_TransmitContext *tc;
5866 struct GNUNET_TIME_Absolute timeout;
5867 struct GNUNET_TIME_Relative rtimeout;
5870 size = ntohs (message->size);
5871 if (size < sizeof (struct AddressLookupMessage))
5873 GNUNET_break_op (0);
5874 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5877 alum = (const struct AddressLookupMessage *) message;
5878 uint32_t addressLen = ntohl (alum->addrlen);
5879 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5881 GNUNET_break_op (0);
5882 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5885 address = (const char *) &alum[1];
5886 nameTransport = (const char *) &address[addressLen];
5888 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5890 GNUNET_break_op (0);
5891 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5894 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5895 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5896 numeric = ntohl (alum->numeric_only);
5897 lsPlugin = find_transport (nameTransport);
5898 if (NULL == lsPlugin)
5900 tc = GNUNET_SERVER_transmit_context_create (client);
5901 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5902 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5903 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5906 GNUNET_SERVER_disable_receive_done_warning (client);
5907 tc = GNUNET_SERVER_transmit_context_create (client);
5908 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5910 address, addressLen,
5913 &transmit_address_to_client, tc);
5917 * Handle PeerAddressLookupMessage.
5919 * @param cls closure (always NULL)
5920 * @param client identification of the client
5921 * @param message the actual message
5924 handle_peer_address_lookup (void *cls,
5925 struct GNUNET_SERVER_Client *client,
5926 const struct GNUNET_MessageHeader *message)
5928 const struct PeerAddressLookupMessage *peer_address_lookup;
5929 struct NeighbourList *neighbor_iterator;
5930 struct ReadyList *ready_iterator;
5931 struct ForeignAddressList *foreign_address_iterator;
5932 struct TransportPlugin *transport_plugin;
5935 struct GNUNET_SERVER_TransmitContext *tc;
5936 struct GNUNET_TIME_Absolute timeout;
5937 struct GNUNET_TIME_Relative rtimeout;
5940 size = ntohs (message->size);
5941 if (size < sizeof (struct PeerAddressLookupMessage))
5943 GNUNET_break_op (0);
5944 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5947 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5949 timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5950 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5952 neighbor_iterator = neighbours;
5953 while (neighbor_iterator != NULL)
5955 if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5957 neighbor_iterator = neighbor_iterator->next;
5960 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5961 if (neighbor_iterator == NULL)
5964 tc = GNUNET_SERVER_transmit_context_create (client);
5965 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5966 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5967 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5971 ready_iterator = neighbor_iterator->plugins;
5972 GNUNET_SERVER_disable_receive_done_warning (client);
5973 tc = GNUNET_SERVER_transmit_context_create (client);
5974 while(ready_iterator != NULL)
5976 foreign_address_iterator = ready_iterator->addresses;
5977 while (foreign_address_iterator != NULL)
5979 transport_plugin = foreign_address_iterator->ready_list->plugin;
5980 if (foreign_address_iterator->addr != NULL)
5982 GNUNET_asprintf (&addr_buf, "%s --- %s",
5983 a2s (transport_plugin->short_name,
5984 foreign_address_iterator->addr,
5985 foreign_address_iterator->addrlen),
5986 (foreign_address_iterator->connected
5987 == GNUNET_YES) ? "CONNECTED"
5989 (foreign_address_iterator->validated
5990 == GNUNET_YES) ? "VALIDATED"
5992 transmit_address_to_client(tc, addr_buf);
5993 GNUNET_free(addr_buf);
5995 else if (foreign_address_iterator->addrlen == 0)
5997 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5998 (foreign_address_iterator->connected
5999 == GNUNET_YES) ? "CONNECTED"
6001 (foreign_address_iterator->validated
6002 == GNUNET_YES) ? "VALIDATED"
6004 transmit_address_to_client (tc, addr_buf);
6005 GNUNET_free(addr_buf);
6008 foreign_address_iterator = foreign_address_iterator->next;
6010 ready_iterator = ready_iterator->next;
6012 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6013 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6014 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6018 * Handle AddressIterateMessage
6020 * @param cls closure (always NULL)
6021 * @param client identification of the client
6022 * @param message the actual message
6025 handle_address_iterate (void *cls,
6026 struct GNUNET_SERVER_Client *client,
6027 const struct GNUNET_MessageHeader *message)
6029 const struct AddressIterateMessage *address_iterate;
6030 struct NeighbourList *neighbor_iterator;
6031 struct ReadyList *ready_iterator;
6032 struct ForeignAddressList *foreign_address_iterator;
6033 struct TransportPlugin *transport_plugin;
6036 struct GNUNET_SERVER_TransmitContext *tc;
6037 struct GNUNET_TIME_Absolute timeout;
6038 struct GNUNET_TIME_Relative rtimeout;
6041 size = ntohs (message->size);
6042 if (size < sizeof (struct AddressIterateMessage))
6044 GNUNET_break_op (0);
6045 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6048 address_iterate = (const struct AddressIterateMessage *) message;
6050 timeout = GNUNET_TIME_absolute_ntoh (address_iterate->timeout);
6051 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
6053 GNUNET_SERVER_disable_receive_done_warning (client);
6054 tc = GNUNET_SERVER_transmit_context_create (client);
6056 neighbor_iterator = neighbours;
6057 while (neighbor_iterator != NULL)
6059 ready_iterator = neighbor_iterator->plugins;
6060 while (ready_iterator != NULL)
6062 foreign_address_iterator = ready_iterator->addresses;
6063 while (foreign_address_iterator != NULL)
6065 transport_plugin = foreign_address_iterator->ready_list->plugin;
6066 if (foreign_address_iterator->addr != NULL)
6068 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6069 GNUNET_i2s(&neighbor_iterator->id),
6070 a2s (transport_plugin->short_name,
6071 foreign_address_iterator->addr,
6072 foreign_address_iterator->addrlen),
6073 (foreign_address_iterator->connected
6074 == GNUNET_YES) ? "CONNECTED"
6076 (foreign_address_iterator->validated
6077 == GNUNET_YES) ? "VALIDATED"
6079 transmit_address_to_client (tc, addr_buf);
6080 GNUNET_free(addr_buf);
6082 else if (foreign_address_iterator->addrlen == 0)
6084 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6085 GNUNET_i2s (&neighbor_iterator->id),
6087 (foreign_address_iterator->connected
6088 == GNUNET_YES) ? "CONNECTED"
6090 (foreign_address_iterator->validated
6091 == GNUNET_YES) ? "VALIDATED"
6093 transmit_address_to_client (tc, addr_buf);
6094 GNUNET_free(addr_buf);
6097 foreign_address_iterator = foreign_address_iterator->next;
6099 ready_iterator = ready_iterator->next;
6101 neighbor_iterator = neighbor_iterator->next;
6104 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6105 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6106 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6111 * Setup the environment for this plugin.
6114 create_environment (struct TransportPlugin *plug)
6116 plug->env.cfg = cfg;
6117 plug->env.my_identity = &my_identity;
6118 plug->env.our_hello = &our_hello;
6119 plug->env.cls = plug;
6120 plug->env.receive = &plugin_env_receive;
6121 plug->env.notify_address = &plugin_env_notify_address;
6122 plug->env.session_end = &plugin_env_session_end;
6123 plug->env.max_connections = max_connect_per_transport;
6124 plug->env.stats = stats;
6129 * Start the specified transport (load the plugin).
6132 start_transport (struct GNUNET_SERVER_Handle *server,
6135 struct TransportPlugin *plug;
6138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6139 _("Loading `%s' transport plugin\n"), name);
6140 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6141 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6142 create_environment (plug);
6143 plug->short_name = GNUNET_strdup (name);
6144 plug->lib_name = libname;
6145 plug->next = plugins;
6147 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6148 if (plug->api == NULL)
6150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6151 _("Failed to load transport plugin for `%s'\n"), name);
6152 GNUNET_free (plug->short_name);
6153 plugins = plug->next;
6154 GNUNET_free (libname);
6161 * Called whenever a client is disconnected. Frees our
6162 * resources associated with that client.
6164 * @param cls closure
6165 * @param client identification of the client
6168 client_disconnect_notification (void *cls,
6169 struct GNUNET_SERVER_Client *client)
6171 struct TransportClient *pos;
6172 struct TransportClient *prev;
6173 struct ClientMessageQueueEntry *mqe;
6174 struct Blacklisters *bl;
6175 struct BlacklistCheck *bc;
6176 struct NeighbourList *n;
6177 struct MessageQueue *mq;
6182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6183 "Client disconnected, cleaning up.\n");
6185 /* clean up blacklister */
6189 if (bl->client == client)
6194 if (bc->bl_pos == bl)
6196 bc->bl_pos = bl->next;
6199 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6202 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6203 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6209 GNUNET_CONTAINER_DLL_remove (bl_head,
6212 GNUNET_SERVER_client_drop (bl->client);
6218 /* clean up 'normal' clients */
6221 while ((pos != NULL) && (pos->client != client))
6228 while (NULL != (mqe = pos->message_queue_head))
6230 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6231 pos->message_queue_tail,
6233 pos->message_count--;
6236 for (n = neighbours; n != NULL; n = n->next)
6238 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6240 if (mq->client == pos)
6241 mq->client = NULL; /* do not use anymore! */
6245 clients = pos->next;
6247 prev->next = pos->next;
6248 if (GNUNET_YES == pos->tcs_pending)
6253 if (pos->th != NULL)
6255 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6258 GNUNET_break (0 == pos->message_count);
6264 * Function called when the service shuts down. Unloads our plugins
6265 * and cancels pending validations.
6267 * @param cls closure, unused
6268 * @param tc task context (unused)
6271 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6273 struct TransportPlugin *plug;
6274 struct OwnAddressList *al;
6275 struct CheckHelloValidatedContext *chvc;
6277 shutdown_in_progress = GNUNET_YES;
6278 while (neighbours != NULL)
6281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6282 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6285 disconnect_neighbour (neighbours, GNUNET_NO);
6288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6289 "Transport service is unloading plugins...\n");
6291 while (NULL != (plug = plugins))
6293 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6295 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6296 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6298 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6299 GNUNET_free (plug->lib_name);
6300 GNUNET_free (plug->short_name);
6301 while (NULL != (al = plug->addresses))
6303 plug->addresses = al->next;
6306 plugins = plug->next;
6309 if (my_private_key != NULL)
6310 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6311 GNUNET_free_non_null (our_hello);
6313 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6316 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6317 validation_map = NULL;
6320 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6322 GNUNET_SCHEDULER_cancel(ats_task);
6323 ats_task = GNUNET_SCHEDULER_NO_TASK;
6330 /* free 'chvc' data structure */
6331 while (NULL != (chvc = chvc_head))
6333 chvc_head = chvc->next;
6334 if (chvc->piter != NULL)
6336 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6337 GNUNET_STATISTICS_update (stats,
6338 gettext_noop ("# outstanding peerinfo iterate requests"),
6345 GNUNET_assert (chvc->ve_count == 0);
6352 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6355 if (peerinfo != NULL)
6357 GNUNET_PEERINFO_disconnect (peerinfo);
6360 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6362 GNUNET_SCHEDULER_cancel (hello_task);
6363 hello_task = GNUNET_SCHEDULER_NO_TASK;
6365 /* Can we assume those are gone by now, or do we need to clean up
6367 GNUNET_break (bl_head == NULL);
6368 GNUNET_break (bc_head == NULL);
6372 void ats_result_cb ()
6374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6375 "ATS Result callback\n");
6379 void create_ats_information ( struct ATS_peer **p,
6381 struct ATS_mechanism ** m,
6385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6386 "ATS requires clean address information\n");
6388 struct ATS_mechanism * mechanisms;
6389 struct ATS_peer *peers;
6391 int connected_addresses = 0;
6394 struct NeighbourList *next = neighbours;
6398 int found_addresses = GNUNET_NO;
6399 struct ReadyList *r_next = next->plugins;
6400 while (r_next != NULL)
6402 struct ForeignAddressList * a_next = r_next->addresses;
6403 while (a_next != NULL)
6406 found_addresses = GNUNET_YES;
6407 a_next = a_next->next;
6409 r_next = r_next->next;
6411 if (found_addresses) c_peers++;
6416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6417 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6420 if ((c_peers == 0) && (c_mechs == 0))
6429 mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6430 peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6438 int found_addresses = GNUNET_NO;
6439 struct ReadyList *r_next = next->plugins;
6440 while (r_next != NULL)
6442 struct ForeignAddressList * a_next = r_next->addresses;
6443 while (a_next != NULL)
6445 if (a_next->connected == GNUNET_YES)
6446 connected_addresses ++;
6447 if (found_addresses == GNUNET_NO)
6449 peers[c_peers].peer = next->id;
6450 peers[c_peers].m_head = NULL;
6451 peers[c_peers].m_tail = NULL;
6452 peers[c_peers].f = 1.0 / c_mechs;
6455 mechanisms[c_mechs].addr = a_next;
6456 mechanisms[c_mechs].col_index = c_mechs;
6457 mechanisms[c_mechs].peer = &peers[c_peers];
6458 mechanisms[c_mechs].next = NULL;
6459 mechanisms[c_mechs].plugin = r_next->plugin;
6460 mechanisms[c_mechs].ressources = a_next->ressources;
6461 mechanisms[c_mechs].quality = a_next->quality;
6463 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6464 peers[c_peers].m_tail,
6465 &mechanisms[c_mechs]);
6466 found_addresses = GNUNET_YES;
6469 a_next = a_next->next;
6471 r_next = r_next->next;
6473 if (found_addresses == GNUNET_YES)
6484 GNUNET_STATISTICS_set(stats,
6485 gettext_noop ("# connected addresses"),
6486 connected_addresses,
6491 schedule_ats (void *cls,
6492 const struct GNUNET_SCHEDULER_TaskContext *tc)
6494 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6498 ats_task = GNUNET_SCHEDULER_NO_TASK;
6499 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6502 if (shutdown_in_progress == GNUNET_YES)
6505 struct GNUNET_TIME_Relative delta =
6506 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6507 if (delta.rel_value < ats_minimum_interval.rel_value)
6510 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6511 "Minimum time between cycles not reached\n");
6517 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6520 ats_calculate_bandwidth_distribution (ats, stats);
6522 last_ats_execution = GNUNET_TIME_absolute_get();
6524 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6525 &schedule_ats, ats);
6528 struct ForeignAddressList * get_preferred_ats_address (
6529 struct NeighbourList *n)
6531 // TODO get ATS prefered address
6532 return find_ready_address(n);
6536 * Initiate transport service.
6538 * @param cls closure
6539 * @param server the initialized server
6540 * @param c configuration to use
6544 struct GNUNET_SERVER_Handle *server,
6545 const struct GNUNET_CONFIGURATION_Handle *c)
6547 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6548 {&handle_start, NULL,
6549 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6550 {&handle_hello, NULL,
6551 GNUNET_MESSAGE_TYPE_HELLO, 0},
6552 {&handle_send, NULL,
6553 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6554 {&handle_request_connect, NULL,
6555 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6556 {&handle_set_quota, NULL,
6557 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6558 {&handle_address_lookup, NULL,
6559 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6561 {&handle_peer_address_lookup, NULL,
6562 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6564 {&handle_address_iterate, NULL,
6565 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6567 {&handle_blacklist_init, NULL,
6568 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6569 {&handle_blacklist_reply, NULL,
6570 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6576 unsigned long long tneigh;
6579 shutdown_in_progress = GNUNET_NO;
6581 stats = GNUNET_STATISTICS_create ("transport", cfg);
6582 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6583 /* parse configuration */
6585 GNUNET_CONFIGURATION_get_value_number (c,
6590 GNUNET_CONFIGURATION_get_value_filename (c,
6592 "HOSTKEY", &keyfile)))
6594 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6596 ("Transport service is lacking key configuration settings. Exiting.\n"));
6597 GNUNET_SCHEDULER_shutdown ();
6600 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6603 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6604 validation_map = NULL;
6608 max_connect_per_transport = (uint32_t) tneigh;
6609 peerinfo = GNUNET_PEERINFO_connect (cfg);
6610 if (peerinfo == NULL)
6612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6613 _("Could not access PEERINFO service. Exiting.\n"));
6614 GNUNET_SCHEDULER_shutdown ();
6617 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6620 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6621 validation_map = NULL;
6622 GNUNET_free (keyfile);
6625 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6626 GNUNET_free (keyfile);
6627 if (my_private_key == NULL)
6629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6631 ("Transport service could not access hostkey. Exiting.\n"));
6632 GNUNET_SCHEDULER_shutdown ();
6635 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6638 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6639 validation_map = NULL;
6642 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6643 GNUNET_CRYPTO_hash (&my_public_key,
6644 sizeof (my_public_key), &my_identity.hashPubKey);
6645 /* setup notification */
6646 GNUNET_SERVER_disconnect_notify (server,
6647 &client_disconnect_notification, NULL);
6648 /* load plugins... */
6651 GNUNET_CONFIGURATION_get_value_string (c,
6652 "TRANSPORT", "PLUGINS", &plugs))
6654 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6655 _("Starting transport plugins `%s'\n"), plugs);
6656 pos = strtok (plugs, " ");
6659 start_transport (server, pos);
6661 pos = strtok (NULL, " ");
6663 GNUNET_free (plugs);
6665 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6666 &shutdown_task, NULL);
6670 /* Initializing ATS */
6673 unsigned long long value;
6678 int v_b_min = 64000;
6682 ats_minimum_interval = ATS_MIN_INTERVAL;
6683 ats_regular_interval = ATS_EXEC_INTERVAL;
6685 /* loading cost ressources */
6686 for (co=0; co<available_ressources; co++)
6688 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6689 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6691 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6697 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6698 "Found ressource cost: [%s] = %llu\n",
6701 ressources[co].c_max = value;
6704 GNUNET_free (section);
6705 GNUNET_asprintf(§ion,"%s_DOWN",ressources[co].cfg_param);
6706 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6708 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6715 "Found ressource cost: [%s] = %llu\n",
6718 ressources[co].c_min = value;
6721 GNUNET_free (section);
6724 ats = ats_init (D, U, R, v_b_min, v_n_min,
6725 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6726 create_ats_information,
6730 int log_problem = GNUNET_NO;
6731 int log_solution = GNUNET_NO;
6732 int overwrite_dump = GNUNET_NO;
6733 int minimum_peers = 0;
6734 int minimum_addresses = 0;
6736 log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6739 log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6742 overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6746 GNUNET_CONFIGURATION_get_value_number(cfg,
6750 minimum_peers = (int) value;
6752 GNUNET_CONFIGURATION_get_value_number(cfg,
6756 minimum_addresses = (int) value;
6758 GNUNET_CONFIGURATION_get_value_number(cfg,
6762 overwrite_dump = (int) value;
6763 GNUNET_break (GNUNET_OK ==
6764 GNUNET_CONFIGURATION_get_value_time (cfg,
6766 "ATS_EXEC_INTERVAL",
6767 &ats_regular_interval));
6768 GNUNET_break (GNUNET_OK ==
6769 GNUNET_CONFIGURATION_get_value_time (cfg,
6772 &ats_minimum_interval));
6774 ats_set_logging_options (ats,
6782 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6788 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6789 _("Transport service ready.\n"));
6791 /* If we have a blacklist file, read from it */
6792 read_blacklist_file(cfg);
6793 /* process client requests */
6794 GNUNET_SERVER_add_handlers (server, handlers);
6799 * The main function for the transport service.
6801 * @param argc number of arguments from the command line
6802 * @param argv command line arguments
6803 * @return 0 ok, 1 on error
6806 main (int argc, char *const *argv)
6808 a2s (NULL, NULL, 0); /* make compiler happy */
6809 return (GNUNET_OK ==
6810 GNUNET_SERVICE_run (argc,
6813 GNUNET_SERVICE_OPTION_NONE,
6814 &run, NULL)) ? 0 : 1;
6817 /* end of gnunet-service-transport.c */