2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "gnunet-service-transport_ats.h"
41 #include "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
51 #define DEBUG_INBOUND GNUNET_NO
54 * Should we do some additional checks (to validate behavior
57 #define EXTRA_CHECKS GNUNET_YES
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
71 #define MAX_PENDING (128 * 1024)
74 * Size of the per-transport blacklist hash maps.
76 #define TRANSPORT_BLACKLIST_HT_SIZE 16
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
83 #define MAX_CONNECT_RETRY 3
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
90 #define MAX_HELLO_LOAD 4
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
96 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
106 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
115 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
118 * Priority to use for PONG messages.
120 #define TRANSPORT_PONG_PRIORITY 4
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
126 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
133 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
141 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * List of addresses of other peers
146 struct ForeignAddressList
149 * This is a linked list.
151 struct ForeignAddressList *next;
154 * Which ready list does this entry belong to.
156 struct ReadyList *ready_list;
159 * How long until we auto-expire this address (unless it is
160 * re-confirmed by the transport)?
162 struct GNUNET_TIME_Absolute expires;
165 * Task used to re-validate addresses, updates latencies and
168 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176 * Session (or NULL if no valid session currently exists or if the
177 * plugin does not use sessions).
179 struct Session *session;
181 struct ATS_ressource_entry * ressources;
183 struct ATS_quality_entry * quality;
186 * What was the last latency observed for this address, plugin and peer?
188 struct GNUNET_TIME_Relative latency;
191 * If we did not successfully transmit a message to the given peer
192 * via this connection during the specified time, we should consider
193 * the connection to be dead. This is used in the case that a TCP
194 * transport simply stalls writing to the stream but does not
195 * formerly get a signal that the other peer died.
197 struct GNUNET_TIME_Absolute timeout;
200 * How often have we tried to connect using this plugin? Used to
201 * discriminate against addresses that do not work well.
202 * FIXME: not yet used, but should be!
204 unsigned int connect_attempts;
207 * DV distance to this peer (1 if no DV is used).
208 * FIXME: need to set this from transport plugins!
218 * Have we ever estimated the latency of this address? Used to
219 * ensure that the first time we add an address, we immediately
225 * Are we currently connected via this address? The first time we
226 * successfully transmit or receive data to a peer via a particular
227 * address, we set this to GNUNET_YES. If we later get an error
228 * (disconnect notification, transmission failure, timeout), we set
229 * it back to GNUNET_NO.
234 * Is this plugin currently busy transmitting to the specific target?
235 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
236 * messages do not count as 'in transmit'.
241 * Has this address been validated yet?
249 * Entry in linked list of network addresses for ourselves. Also
250 * includes a cached signature for 'struct TransportPongMessage's.
252 struct OwnAddressList
255 * This is a linked list.
257 struct OwnAddressList *next;
260 * How long until the current signature expires? (ZERO if the
261 * signature was never created).
263 struct GNUNET_TIME_Absolute pong_sig_expires;
266 * Signature for a 'struct TransportPongMessage' for this address.
268 struct GNUNET_CRYPTO_RsaSignature pong_signature;
279 * Entry in linked list of all of our plugins.
281 struct TransportPlugin
284 * This is a linked list.
286 struct TransportPlugin *next;
289 * API of the transport as returned by the plugin's
290 * initialization function.
292 struct GNUNET_TRANSPORT_PluginFunctions *api;
295 * Short name for the plugin (i.e. "tcp").
300 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
305 * List of our known addresses for this transport.
307 struct OwnAddressList *addresses;
310 * Environment this transport service is using
313 struct GNUNET_TRANSPORT_PluginEnvironment env;
316 * ID of task that is used to clean up expired addresses.
318 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
321 * Set to GNUNET_YES if we need to scrap the existing list of
322 * "addresses" and start fresh when we receive the next address
323 * update from a transport. Set to GNUNET_NO if we should just add
324 * the new address to the list and wait for the commit call.
328 struct ATS_plugin * rc;
331 * Hashmap of blacklisted peers for this particular transport.
333 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
336 struct NeighbourList;
339 * For each neighbour we keep a list of messages
340 * that we still want to transmit to the neighbour.
346 * This is a doubly linked list.
348 struct MessageQueue *next;
351 * This is a doubly linked list.
353 struct MessageQueue *prev;
356 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
357 * stuck together in memory. Allocated at the end of this struct.
359 const char *message_buf;
362 * Size of the message buf
364 size_t message_buf_size;
367 * Client responsible for queueing the message;
368 * used to check that a client has no two messages
369 * pending for the same target. Can be NULL.
371 struct TransportClient *client;
374 * Using which specific address should we send this message?
376 struct ForeignAddressList *specific_address;
379 * Peer ID of the Neighbour this entry belongs to.
381 struct GNUNET_PeerIdentity neighbour_id;
384 * Plugin that we used for the transmission.
385 * NULL until we scheduled a transmission.
387 struct TransportPlugin *plugin;
390 * At what time should we fail?
392 struct GNUNET_TIME_Absolute timeout;
395 * Internal message of the transport system that should not be
396 * included in the usual SEND-SEND_OK transmission confirmation
397 * traffic management scheme. Typically, "internal_msg" will
398 * be set whenever "client" is NULL (but it is not strictly
404 * How important is the message?
406 unsigned int priority;
412 * For a given Neighbour, which plugins are available
413 * to talk to this peer and what are their costs?
418 * This is a linked list.
420 struct ReadyList *next;
423 * Which of our transport plugins does this entry
426 struct TransportPlugin *plugin;
429 * Transport addresses, latency, and readiness for
430 * this particular plugin.
432 struct ForeignAddressList *addresses;
435 * To which neighbour does this ready list belong to?
437 struct NeighbourList *neighbour;
442 * Entry in linked list of all of our current neighbours.
448 * This is a linked list.
450 struct NeighbourList *next;
453 * Which of our transports is connected to this peer
454 * and what is their status?
456 struct ReadyList *plugins;
459 * Head of list of messages we would like to send to this peer;
460 * must contain at most one message per client.
462 struct MessageQueue *messages_head;
465 * Tail of list of messages we would like to send to this peer; must
466 * contain at most one message per client.
468 struct MessageQueue *messages_tail;
471 * Head of list of messages of messages we expected the continuation
472 * to be called to destroy the message
474 struct MessageQueue *cont_head;
477 * Tail of list of messages of messages we expected the continuation
478 * to be called to destroy the message
480 struct MessageQueue *cont_tail;
483 * Buffer for at most one payload message used when we receive
484 * payload data before our PING-PONG has succeeded. We then
485 * store such messages in this intermediary buffer until the
486 * connection is fully up.
488 struct GNUNET_MessageHeader *pre_connect_message_buffer;
491 * Context for peerinfo iteration.
492 * NULL after we are done processing peerinfo's information.
494 struct GNUNET_PEERINFO_IteratorContext *piter;
497 * Public key for this peer. Valid only if the respective flag is set below.
499 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
502 * Identity of this neighbour.
504 struct GNUNET_PeerIdentity id;
507 * ID of task scheduled to run when this peer is about to
508 * time out (will free resources associated with the peer).
510 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
513 * ID of task scheduled to run when we should retry transmitting
514 * the head of the message queue. Actually triggered when the
515 * transmission is timing out (we trigger instantly when we have
516 * a chance of success).
518 GNUNET_SCHEDULER_TaskIdentifier retry_task;
521 * How long until we should consider this peer dead
522 * (if we don't receive another message in the
525 struct GNUNET_TIME_Absolute peer_timeout;
528 * Tracker for inbound bandwidth.
530 struct GNUNET_BANDWIDTH_Tracker in_tracker;
533 * The latency we have seen for this particular address for
534 * this particular peer. This latency may have been calculated
535 * over multiple transports. This value reflects how long it took
536 * us to receive a response when SENDING via this particular
537 * transport/neighbour/address combination!
539 * FIXME: we need to periodically send PINGs to update this
540 * latency (at least more often than the current "huge" (11h?)
543 struct GNUNET_TIME_Relative latency;
546 * How often has the other peer (recently) violated the
547 * inbound traffic limit? Incremented by 10 per violation,
548 * decremented by 1 per non-violation (for each
551 unsigned int quota_violation_count;
554 * DV distance to this peer (1 if no DV is used).
559 * Have we seen an PONG from this neighbour in the past (and
560 * not had a disconnect since)?
565 * Do we have a valid public key for this neighbour?
567 int public_key_valid;
570 * Are we already in the process of disconnecting this neighbour?
575 * Performance data for the peer.
577 struct GNUNET_TRANSPORT_ATS_Information *ats;
581 * Message used to ask a peer to validate receipt (to check an address
582 * from a HELLO). Followed by the address we are trying to validate,
583 * or an empty address if we are just sending a PING to confirm that a
584 * connection which the receiver (of the PING) initiated is still valid.
586 struct TransportPingMessage
590 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
592 struct GNUNET_MessageHeader header;
595 * Challenge code (to ensure fresh reply).
597 uint32_t challenge GNUNET_PACKED;
600 * Who is the intended recipient?
602 struct GNUNET_PeerIdentity target;
608 * Message used to validate a HELLO. The challenge is included in the
609 * confirmation to make matching of replies to requests possible. The
610 * signature signs our public key, an expiration time and our address.<p>
612 * This message is followed by our transport address that the PING tried
613 * to confirm (if we liked it). The address can be empty (zero bytes)
614 * if the PING had not address either (and we received the request via
615 * a connection that we initiated).
617 struct TransportPongMessage
621 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
623 struct GNUNET_MessageHeader header;
626 * Challenge code from PING (showing freshness). Not part of what
627 * is signed so that we can re-use signatures.
629 uint32_t challenge GNUNET_PACKED;
634 struct GNUNET_CRYPTO_RsaSignature signature;
637 * What are we signing and why? Two possible reason codes can be here:
638 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
639 * plausible address for this peer (pid is set to identity of signer); or
640 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
641 * an address we used to connect to the peer with the given pid.
643 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
646 * When does this signature expire?
648 struct GNUNET_TIME_AbsoluteNBO expiration;
651 * Either the identity of the peer Who signed this message, or the
652 * identity of the peer that we're connected to using the given
653 * address (depending on purpose.type).
655 struct GNUNET_PeerIdentity pid;
658 * Size of address appended to this message (part of what is
659 * being signed, hence not redundant).
667 * Linked list of messages to be transmitted to the client. Each
668 * entry is followed by the actual message.
670 struct ClientMessageQueueEntry
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *next;
678 * This is a doubly-linked list.
680 struct ClientMessageQueueEntry *prev;
685 * Client connected to the transport service.
687 struct TransportClient
691 * This is a linked list.
693 struct TransportClient *next;
696 * Handle to the client.
698 struct GNUNET_SERVER_Client *client;
701 * Linked list of messages yet to be transmitted to
704 struct ClientMessageQueueEntry *message_queue_head;
707 * Tail of linked list of messages yet to be transmitted to the
710 struct ClientMessageQueueEntry *message_queue_tail;
713 * Current transmit request handle.
715 struct GNUNET_CONNECTION_TransmitHandle *th;
718 * Is a call to "transmit_send_continuation" pending? If so, we
719 * must not free this struct (even if the corresponding client
720 * disconnects) and instead only remove it from the linked list and
721 * set the "client" field to NULL.
726 * Length of the list of messages pending for this client.
728 unsigned int message_count;
734 * Context of currently active requests to peerinfo
735 * for validation of HELLOs.
737 struct CheckHelloValidatedContext;
741 * Entry in map of all HELLOs awaiting validation.
743 struct ValidationEntry
747 * NULL if this entry is not part of a larger HELLO validation.
749 struct CheckHelloValidatedContext *chvc;
752 * The address, actually a pointer to the end
753 * of this struct. Do not free!
758 * Name of the transport.
760 char *transport_name;
763 * The public key of the peer.
765 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
768 * ID of task that will clean up this entry if we don't succeed
769 * with the validation first.
771 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
774 * At what time did we send this validation?
776 struct GNUNET_TIME_Absolute send_time;
779 * Session being validated (or NULL for none).
781 struct Session *session;
784 * Challenge number we used.
797 * Context of currently active requests to peerinfo
798 * for validation of HELLOs.
800 struct CheckHelloValidatedContext
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *next;
809 * This is a doubly-linked list.
811 struct CheckHelloValidatedContext *prev;
814 * Hello that we are validating.
816 const struct GNUNET_HELLO_Message *hello;
819 * Context for peerinfo iteration.
820 * NULL after we are done processing peerinfo's information.
822 struct GNUNET_PEERINFO_IteratorContext *piter;
825 * Was a HELLO known for this peer to peerinfo?
830 * Number of validation entries currently referring to this
833 unsigned int ve_count;
838 * All zero hash for comparison.
840 static GNUNET_HashCode null_hash;
845 static struct GNUNET_HELLO_Message *our_hello;
850 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
855 static struct GNUNET_PeerIdentity my_identity;
860 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
865 const struct GNUNET_CONFIGURATION_Handle *cfg;
868 * Linked list of all clients to this service.
870 static struct TransportClient *clients;
873 * All loaded plugins.
875 static struct TransportPlugin *plugins;
878 * Handle to peerinfo service.
880 static struct GNUNET_PEERINFO_Handle *peerinfo;
883 * All known neighbours and their HELLOs.
885 static struct NeighbourList *neighbours;
888 * Number of neighbours we'd like to have.
890 static uint32_t max_connect_per_transport;
893 * Head of linked list.
895 static struct CheckHelloValidatedContext *chvc_head;
898 * Tail of linked list.
900 static struct CheckHelloValidatedContext *chvc_tail;
903 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
904 * of the given peer that we are currently validating).
906 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
909 * Handle for reporting statistics.
911 static struct GNUNET_STATISTICS_Handle *stats;
914 * Identifier of 'refresh_hello' task.
916 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
919 * Identifier of ats scheduler task.
921 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
924 * Is transport service shutting down ?
926 static int shutdown_in_progress;
929 * Handle for ats information
931 static struct ATS_Handle *ats;
934 * Time of last ats execution
936 struct GNUNET_TIME_Absolute last_ats_execution;
938 * Minimum interval between two ATS executions
940 struct GNUNET_TIME_Relative ats_minimum_interval;
942 * Regular interval when ATS execution is triggered
944 struct GNUNET_TIME_Relative ats_regular_interval;
947 * The peer specified by the given neighbour has timed-out or a plugin
948 * has disconnected. We may either need to do nothing (other plugins
949 * still up), or trigger a full disconnect and clean up. This
950 * function updates our state and do the necessary notifications.
951 * Also notifies our clients that the neighbour is now officially
954 * @param n the neighbour list entry for the peer
955 * @param check should we just check if all plugins
956 * disconnected or must we ask all plugins to
959 static void disconnect_neighbour (struct NeighbourList *n, int check);
962 * Check the ready list for the given neighbour and if a plugin is
963 * ready for transmission (and if we have a message), do so!
965 * @param nexi target peer for which to transmit
967 static void try_transmission_to_peer (struct NeighbourList *n);
969 struct ForeignAddressList * get_preferred_ats_address (
970 struct NeighbourList *n);
973 * Find an entry in the neighbour list for a particular peer.
975 * @return NULL if not found.
977 static struct NeighbourList *
978 find_neighbour (const struct GNUNET_PeerIdentity *key)
980 struct NeighbourList *head = neighbours;
982 while ((head != NULL) &&
983 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
988 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
992 for (c=0; c<available_quality_metrics; c++)
994 if (ats_index == qm[c].atis_index)
996 fal->quality[c].values[0] = fal->quality[c].values[1];
997 fal->quality[c].values[1] = fal->quality[c].values[2];
998 fal->quality[c].values[2] = value;
1001 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1005 if (set == GNUNET_NO)
1007 for (c=0; c<available_ressources; c++)
1009 if (ats_index == ressources[c].atis_index)
1011 fal->ressources[c].c = value;
1014 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1023 update_addr_ats (struct ForeignAddressList *fal,
1024 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1029 for (c1=0; c1<ats_count; c1++)
1031 set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1037 * Find an entry in the transport list for a particular transport.
1039 * @return NULL if not found.
1041 static struct TransportPlugin *
1042 find_transport (const char *short_name)
1044 struct TransportPlugin *head = plugins;
1045 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1051 * Is a particular peer blacklisted for a particular transport?
1053 * @param peer the peer to check for
1054 * @param plugin the plugin used to connect to the peer
1056 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1059 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1062 if (plugin->blacklist != NULL)
1064 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Peer `%s:%s' is blacklisted!\n",
1069 plugin->short_name, GNUNET_i2s (peer));
1072 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1082 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer,
1083 char *transport_name)
1085 struct TransportPlugin *plugin;
1087 plugin = find_transport(transport_name);
1088 if (plugin == NULL) /* Nothing to do */
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 "Adding peer `%s' with plugin `%s' to blacklist\n",
1096 if (plugin->blacklist == NULL)
1097 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1098 GNUNET_assert(plugin->blacklist != NULL);
1099 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1106 * Read the blacklist file, containing transport:peer entries.
1107 * Provided the transport is loaded, set up hashmap with these
1108 * entries to blacklist peers by transport.
1112 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1119 struct GNUNET_PeerIdentity pid;
1121 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1122 unsigned int entries_found;
1123 char *transport_name;
1126 GNUNET_CONFIGURATION_get_value_filename (cfg,
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Option `%s' in section `%s' not specified!\n",
1139 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1140 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1141 | GNUNET_DISK_PERM_USER_WRITE);
1142 if (0 != STAT (fn, &frstat))
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 _("Could not read blacklist file `%s'\n"), fn);
1149 if (frstat.st_size == 0)
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 _("Blacklist file `%s' is empty.\n"),
1159 /* FIXME: use mmap */
1160 data = GNUNET_malloc_large (frstat.st_size);
1161 GNUNET_assert(data != NULL);
1162 if (frstat.st_size !=
1163 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _("Failed to read blacklist from `%s'\n"), fn);
1173 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1175 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1176 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1179 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1182 if (colon_pos >= frstat.st_size)
1184 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1185 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1186 (unsigned long long) colon_pos);
1192 if (isspace( (unsigned char) data[colon_pos]))
1194 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1195 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1196 (unsigned long long) colon_pos);
1198 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1202 tsize = colon_pos - pos;
1203 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1206 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1207 (unsigned long long) colon_pos);
1216 transport_name = GNUNET_malloc(tsize + 1);
1217 memcpy(transport_name, &data[pos], tsize);
1218 pos = colon_pos + 1;
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Read transport name %s in blacklist file.\n",
1224 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1225 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1227 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1228 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1229 (unsigned long long) pos);
1231 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1233 GNUNET_free_non_null(transport_name);
1236 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1237 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1239 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1240 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1241 (unsigned long long) pos,
1246 if (0 != memcmp (&pid,
1248 sizeof (struct GNUNET_PeerIdentity)))
1251 add_peer_to_blacklist (&pid,
1256 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1257 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1261 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1262 GNUNET_free_non_null(transport_name);
1263 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1266 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1273 * Function called to notify a client about the socket being ready to
1274 * queue more data. "buf" will be NULL and "size" zero if the socket
1275 * was closed for writing in the meantime.
1277 * @param cls closure
1278 * @param size number of bytes available in buf
1279 * @param buf where the callee should write the message
1280 * @return number of bytes written to buf
1283 transmit_to_client_callback (void *cls, size_t size, void *buf)
1285 struct TransportClient *client = cls;
1286 struct ClientMessageQueueEntry *q;
1289 const struct GNUNET_MessageHeader *msg;
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Transmission to client failed, closing connection.\n");
1299 /* fatal error with client, free message queue! */
1300 while (NULL != (q = client->message_queue_head))
1302 GNUNET_STATISTICS_update (stats,
1303 gettext_noop ("# bytes discarded (could not transmit to client)"),
1304 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1306 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1307 client->message_queue_tail,
1311 client->message_count = 0;
1316 while (NULL != (q = client->message_queue_head))
1318 msg = (const struct GNUNET_MessageHeader *) &q[1];
1319 msize = ntohs (msg->size);
1320 if (msize + tsize > size)
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "Transmitting message of type %u to client.\n",
1327 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1328 client->message_queue_tail,
1330 memcpy (&cbuf[tsize], msg, msize);
1333 client->message_count--;
1337 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1338 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1340 GNUNET_TIME_UNIT_FOREVER_REL,
1341 &transmit_to_client_callback,
1343 GNUNET_assert (client->th != NULL);
1350 * Convert an address to a string.
1352 * @param plugin name of the plugin responsible for the address
1353 * @param addr binary address
1354 * @param addr_len number of bytes in addr
1355 * @return NULL on error, otherwise address string
1358 a2s (const char *plugin,
1362 struct TransportPlugin *p;
1366 p = find_transport (plugin);
1367 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1370 return p->api->address_to_string (NULL,
1380 * Iterator to free entries in the validation_map.
1382 * @param cls closure (unused)
1383 * @param key current key code
1384 * @param value value in the hash map (validation to abort)
1385 * @return GNUNET_YES (always)
1388 abort_validation (void *cls,
1389 const GNUNET_HashCode * key,
1392 struct ValidationEntry *va = value;
1394 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1395 GNUNET_SCHEDULER_cancel (va->timeout_task);
1396 GNUNET_free (va->transport_name);
1397 if (va->chvc != NULL)
1399 va->chvc->ve_count--;
1400 if (va->chvc->ve_count == 0)
1402 GNUNET_CONTAINER_DLL_remove (chvc_head,
1405 GNUNET_free (va->chvc);
1415 * HELLO validation cleanup task (validation failed).
1417 * @param cls the 'struct ValidationEntry' that failed
1418 * @param tc scheduler context (unused)
1421 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1423 struct ValidationEntry *va = cls;
1424 struct GNUNET_PeerIdentity pid;
1426 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1427 GNUNET_STATISTICS_update (stats,
1428 gettext_noop ("# address validation timeouts"),
1431 GNUNET_CRYPTO_hash (&va->publicKey,
1433 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1435 GNUNET_break (GNUNET_OK ==
1436 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1439 abort_validation (NULL, NULL, va);
1445 * Send the specified message to the specified client. Since multiple
1446 * messages may be pending for the same client at a time, this code
1447 * makes sure that no message is lost.
1449 * @param client client to transmit the message to
1450 * @param msg the message to send
1451 * @param may_drop can this message be dropped if the
1452 * message queue for this client is getting far too large?
1455 transmit_to_client (struct TransportClient *client,
1456 const struct GNUNET_MessageHeader *msg, int may_drop)
1458 struct ClientMessageQueueEntry *q;
1461 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1463 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1465 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1468 client->message_count,
1470 GNUNET_STATISTICS_update (stats,
1471 gettext_noop ("# messages dropped due to slow client"),
1476 msize = ntohs (msg->size);
1477 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1478 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1479 memcpy (&q[1], msg, msize);
1480 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1481 client->message_queue_tail,
1483 client->message_count++;
1484 if (client->th == NULL)
1486 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1488 GNUNET_TIME_UNIT_FOREVER_REL,
1489 &transmit_to_client_callback,
1491 GNUNET_assert (client->th != NULL);
1497 * Transmit a 'SEND_OK' notification to the given client for the
1500 * @param client who to notify
1501 * @param n neighbour to notify about, can be NULL (on failure)
1502 * @param target target of the transmission
1503 * @param result status code for the transmission request
1506 transmit_send_ok (struct TransportClient *client,
1507 struct NeighbourList *n,
1508 const struct GNUNET_PeerIdentity *target,
1511 struct SendOkMessage send_ok_msg;
1513 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1514 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1515 send_ok_msg.success = htonl (result);
1517 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1519 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1520 send_ok_msg.peer = *target;
1521 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1526 * Mark the given FAL entry as 'connected' (and hence preferred for
1527 * sending); also mark all others for the same peer as 'not connected'
1528 * (since only one can be preferred).
1530 * @param fal address to set to 'connected'
1533 mark_address_connected (struct ForeignAddressList *fal);
1538 * We should re-try transmitting to the given peer,
1539 * hopefully we've learned something in the meantime.
1542 retry_transmission_task (void *cls,
1543 const struct GNUNET_SCHEDULER_TaskContext *tc)
1545 struct NeighbourList *n = cls;
1547 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1548 try_transmission_to_peer (n);
1553 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1554 * upon "completion" of a send request. This tells the API
1555 * that it is now legal to send another message to the given
1558 * @param cls closure, identifies the entry on the
1559 * message queue that was transmitted and the
1560 * client responsible for queuing the message
1561 * @param target the peer receiving the message
1562 * @param result GNUNET_OK on success, if the transmission
1563 * failed, we should not tell the client to transmit
1567 transmit_send_continuation (void *cls,
1568 const struct GNUNET_PeerIdentity *target,
1571 struct MessageQueue *mq = cls;
1572 struct NeighbourList *n;
1574 GNUNET_STATISTICS_update (stats,
1575 gettext_noop ("# bytes pending with plugins"),
1576 - (int64_t) mq->message_buf_size,
1578 if (result == GNUNET_OK)
1580 GNUNET_STATISTICS_update (stats,
1581 gettext_noop ("# bytes successfully transmitted by plugins"),
1582 mq->message_buf_size,
1587 GNUNET_STATISTICS_update (stats,
1588 gettext_noop ("# bytes with transmission failure by plugins"),
1589 mq->message_buf_size,
1592 if (mq->specific_address != NULL)
1594 if (result == GNUNET_OK)
1596 mq->specific_address->timeout =
1597 GNUNET_TIME_relative_to_absolute
1598 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1599 if (mq->specific_address->validated == GNUNET_YES)
1600 mark_address_connected (mq->specific_address);
1604 if (mq->specific_address->connected == GNUNET_YES)
1607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1609 a2s (mq->specific_address->ready_list->plugin->short_name,
1610 mq->specific_address->addr,
1611 mq->specific_address->addrlen));
1613 GNUNET_STATISTICS_update (stats,
1614 gettext_noop ("# connected addresses"),
1617 mq->specific_address->connected = GNUNET_NO;
1620 if (! mq->internal_msg)
1621 mq->specific_address->in_transmit = GNUNET_NO;
1623 n = find_neighbour (&mq->neighbour_id);
1624 if (mq->client != NULL)
1625 transmit_send_ok (mq->client, n, target, result);
1626 GNUNET_assert (n != NULL);
1627 GNUNET_CONTAINER_DLL_remove (n->cont_head,
1631 if (result == GNUNET_OK)
1632 try_transmission_to_peer (n);
1633 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1634 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1640 * Check the ready list for the given neighbour and if a plugin is
1641 * ready for transmission (and if we have a message), do so!
1643 * @param neighbour target peer for which to transmit
1646 try_transmission_to_peer (struct NeighbourList *n)
1648 struct ReadyList *rl;
1649 struct MessageQueue *mq;
1650 struct GNUNET_TIME_Relative timeout;
1654 if (n->messages_head == NULL)
1657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1658 "Transmission queue for `%4s' is empty\n",
1659 GNUNET_i2s (&n->id));
1661 return; /* nothing to do */
1664 mq = n->messages_head;
1665 force_address = GNUNET_YES;
1666 if (mq->specific_address == NULL)
1669 mq->specific_address = get_preferred_ats_address(n);
1670 GNUNET_STATISTICS_update (stats,
1671 gettext_noop ("# transport selected peer address freely"),
1674 force_address = GNUNET_NO;
1676 if (mq->specific_address == NULL)
1678 GNUNET_STATISTICS_update (stats,
1679 gettext_noop ("# transport failed to selected peer address"),
1682 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1683 if (timeout.rel_value == 0)
1686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1687 "No destination address available to transmit message of size %u to peer `%4s'\n",
1688 mq->message_buf_size,
1689 GNUNET_i2s (&mq->neighbour_id));
1691 GNUNET_STATISTICS_update (stats,
1692 gettext_noop ("# bytes in message queue for other peers"),
1693 - (int64_t) mq->message_buf_size,
1695 GNUNET_STATISTICS_update (stats,
1696 gettext_noop ("# bytes discarded (no destination address available)"),
1697 mq->message_buf_size,
1699 if (mq->client != NULL)
1700 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1701 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1705 return; /* nobody ready */
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# message delivery deferred (no address)"),
1711 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1712 GNUNET_SCHEDULER_cancel (n->retry_task);
1713 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1714 &retry_transmission_task,
1717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1718 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1719 mq->message_buf_size,
1720 GNUNET_i2s (&mq->neighbour_id),
1723 /* FIXME: might want to trigger peerinfo lookup here
1724 (unless that's already pending...) */
1727 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1730 if (mq->specific_address->connected == GNUNET_NO)
1731 mq->specific_address->connect_attempts++;
1732 rl = mq->specific_address->ready_list;
1733 mq->plugin = rl->plugin;
1734 if (!mq->internal_msg)
1735 mq->specific_address->in_transmit = GNUNET_YES;
1737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1738 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1739 mq->message_buf_size,
1740 GNUNET_i2s (&n->id),
1741 (mq->specific_address->addr != NULL)
1742 ? a2s (mq->plugin->short_name,
1743 mq->specific_address->addr,
1744 mq->specific_address->addrlen)
1746 rl->plugin->short_name);
1748 GNUNET_STATISTICS_update (stats,
1749 gettext_noop ("# bytes in message queue for other peers"),
1750 - (int64_t) mq->message_buf_size,
1752 GNUNET_STATISTICS_update (stats,
1753 gettext_noop ("# bytes pending with plugins"),
1754 mq->message_buf_size,
1757 GNUNET_CONTAINER_DLL_insert (n->cont_head,
1761 ret = rl->plugin->api->send (rl->plugin->api->cls,
1764 mq->message_buf_size,
1766 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1767 mq->specific_address->session,
1768 mq->specific_address->addr,
1769 mq->specific_address->addrlen,
1771 &transmit_send_continuation, mq);
1774 /* failure, but 'send' would not call continuation in this case,
1775 so we need to do it here! */
1776 transmit_send_continuation (mq,
1784 * Send the specified message to the specified peer.
1786 * @param client source of the transmission request (can be NULL)
1787 * @param peer_address ForeignAddressList where we should send this message
1788 * @param priority how important is the message
1789 * @param timeout how long do we have to transmit?
1790 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1791 * @param message_buf_size total size of all messages in message_buf
1792 * @param is_internal is this an internal message; these are pre-pended and
1793 * also do not count for plugins being "ready" to transmit
1794 * @param neighbour handle to the neighbour for transmission
1797 transmit_to_peer (struct TransportClient *client,
1798 struct ForeignAddressList *peer_address,
1799 unsigned int priority,
1800 struct GNUNET_TIME_Relative timeout,
1801 const char *message_buf,
1802 size_t message_buf_size,
1803 int is_internal, struct NeighbourList *neighbour)
1805 struct MessageQueue *mq;
1810 /* check for duplicate submission */
1811 mq = neighbour->messages_head;
1814 if (mq->client == client)
1816 /* client transmitted to same peer twice
1817 before getting SEND_OK! */
1825 GNUNET_STATISTICS_update (stats,
1826 gettext_noop ("# bytes in message queue for other peers"),
1829 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1830 mq->specific_address = peer_address;
1831 mq->client = client;
1832 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1833 memcpy (&mq[1], message_buf, message_buf_size);
1834 mq->message_buf = (const char*) &mq[1];
1835 mq->message_buf_size = message_buf_size;
1836 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1837 mq->internal_msg = is_internal;
1838 mq->priority = priority;
1839 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1841 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1842 neighbour->messages_tail,
1845 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1846 neighbour->messages_tail,
1847 neighbour->messages_tail,
1849 try_transmission_to_peer (neighbour);
1854 * Send a plain PING (without address or our HELLO) to the given
1855 * foreign address to try to establish a connection (and validate
1856 * that the other peer is really who he claimed he is).
1858 * @param n neighbour to PING
1861 transmit_plain_ping (struct NeighbourList *n)
1863 struct ValidationEntry *ve;
1864 struct TransportPingMessage ping;
1865 struct ReadyList *rl;
1866 struct TransportPlugin *plugin;
1867 struct ForeignAddressList *fal;
1869 if (! n->public_key_valid)
1871 /* This should not happen since the other peer
1872 should send us a HELLO prior to sending his
1874 GNUNET_break_op (0);
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Could not transmit plain PING to `%s': public key not known\n",
1877 GNUNET_i2s (&n->id));
1880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881 "Looking for addresses to transmit plain PING to `%s'\n",
1882 GNUNET_i2s (&n->id));
1883 for (rl = n->plugins; rl != NULL; rl = rl->next)
1885 plugin = rl->plugin;
1886 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1888 if (! fal->connected)
1890 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1891 ve->transport_name = GNUNET_strdup (plugin->short_name);
1892 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1894 ve->send_time = GNUNET_TIME_absolute_get();
1895 ve->session = fal->session;
1896 memcpy(&ve->publicKey,
1898 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1899 ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1900 &timeout_hello_validation,
1902 GNUNET_CONTAINER_multihashmap_put (validation_map,
1905 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1906 ping.header.size = htons(sizeof(struct TransportPingMessage));
1907 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1908 ping.challenge = htonl(ve->challenge);
1909 memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1910 GNUNET_STATISTICS_update (stats,
1911 gettext_noop ("# PING without HELLO messages sent"),
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "Transmitting plain PING to `%s'\n",
1916 GNUNET_i2s (&n->id));
1917 transmit_to_peer (NULL,
1919 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1920 HELLO_VERIFICATION_TIMEOUT,
1921 (const char*) &ping, sizeof (ping),
1929 * Mark the given FAL entry as 'connected' (and hence preferred for
1930 * sending); also mark all others for the same peer as 'not connected'
1931 * (since only one can be preferred).
1933 * @param fal address to set to 'connected'
1936 mark_address_connected(struct ForeignAddressList *fal)
1938 struct ForeignAddressList *pos;
1939 struct ForeignAddressList *inbound;
1940 struct ForeignAddressList *outbound;
1942 GNUNET_assert (GNUNET_YES == fal->validated);
1943 if (fal->connected == GNUNET_YES)
1944 return; /* nothing to do */
1948 pos = fal->ready_list->addresses;
1951 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1952 if ( (GNUNET_YES == pos->connected) &&
1953 (0 == pos->addrlen) &&
1954 (0 == fal->addrlen) )
1956 if ( (0 == pos->addrlen) &&
1957 (GNUNET_YES == pos->connected) )
1962 pos = fal->ready_list->addresses;
1965 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1966 if ( (GNUNET_YES == pos->connected) &&
1967 (0 < pos->addrlen) &&
1968 (0 < fal->addrlen) )
1970 if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
1976 if (inbound != NULL)
1977 fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
1978 if (outbound != NULL)
1979 fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
1982 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1983 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1984 == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
1985 &my_identity.hashPubKey, &null_hash)))
1988 fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
1992 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1993 == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
1994 &my_identity.hashPubKey, &null_hash))))
1997 fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
2002 pos = fal->ready_list->addresses;
2005 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
2008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2009 "Marking address `%s' as no longer connected (due to connect on other address)\n",
2010 a2s (pos->ready_list->plugin->short_name, pos->addr,
2015 "Peer: %s, setting %s connection to disconnected.\n",
2016 GNUNET_i2s(&my_identity),
2017 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
2019 pos->connected = GNUNET_NO;
2020 GNUNET_STATISTICS_update (stats,
2021 gettext_noop ("# connected addresses"), -1,
2026 GNUNET_assert (GNUNET_NO == fal->connected);
2027 fal->connected = GNUNET_YES;
2028 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2034 * Find an address in any of the available transports for
2035 * the given neighbour that would be good for message
2036 * transmission. This is essentially the transport selection
2039 * @param neighbour for whom to select an address
2040 * @return selected address, NULL if we have none
2042 struct ForeignAddressList *
2043 find_ready_address(struct NeighbourList *neighbour)
2045 struct ReadyList *head = neighbour->plugins;
2046 struct ForeignAddressList *addresses;
2047 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2048 struct ForeignAddressList *best_address;
2050 /* Hack to prefer unix domain sockets */
2051 struct ForeignAddressList *unix_address = NULL;
2053 best_address = NULL;
2054 while (head != NULL)
2056 addresses = head->addresses;
2057 while (addresses != NULL)
2059 if ( (addresses->timeout.abs_value < now.abs_value) &&
2060 (addresses->connected == GNUNET_YES) )
2063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2064 "Marking long-time inactive connection to `%4s' as down.\n",
2065 GNUNET_i2s (&neighbour->id));
2067 GNUNET_STATISTICS_update (stats,
2068 gettext_noop ("# connected addresses"),
2071 addresses->connected = GNUNET_NO;
2073 addresses = addresses->next;
2076 addresses = head->addresses;
2077 while (addresses != NULL)
2080 if (addresses->addr != NULL)
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2083 a2s (head->plugin->short_name,
2085 addresses->addrlen),
2086 GNUNET_i2s (&neighbour->id),
2087 addresses->connected,
2088 addresses->in_transmit,
2089 addresses->validated,
2090 addresses->connect_attempts,
2091 (unsigned long long) addresses->timeout.abs_value,
2092 (unsigned int) addresses->distance);
2094 if (0==strcmp(head->plugin->short_name,"unix"))
2096 if ( (unix_address == NULL) ||
2097 ( (unix_address != NULL) &&
2098 (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2099 unix_address = addresses;
2101 if ( ( (best_address == NULL) ||
2102 (addresses->connected == GNUNET_YES) ||
2103 (best_address->connected == GNUNET_NO) ) &&
2104 (addresses->in_transmit == GNUNET_NO) &&
2105 ( (best_address == NULL) ||
2106 (addresses->latency.rel_value < best_address->latency.rel_value)) )
2107 best_address = addresses;
2108 /* FIXME: also give lower-latency addresses that are not
2109 connected a chance some times... */
2110 addresses = addresses->next;
2112 if (unix_address != NULL)
2116 if (unix_address != NULL)
2118 best_address = unix_address;
2120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121 "Found UNIX address, forced this address\n");
2124 if (best_address != NULL)
2127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2128 "Best address found (`%s') has latency of %llu ms.\n",
2129 (best_address->addrlen > 0)
2130 ? a2s (best_address->ready_list->plugin->short_name,
2132 best_address->addrlen)
2134 best_address->latency.rel_value);
2139 GNUNET_STATISTICS_update (stats,
2140 gettext_noop ("# transmission attempts failed (no address)"),
2145 return best_address;
2152 struct GeneratorContext
2154 struct TransportPlugin *plug_pos;
2155 struct OwnAddressList *addr_pos;
2156 struct GNUNET_TIME_Absolute expiration;
2164 address_generator (void *cls, size_t max, void *buf)
2166 struct GeneratorContext *gc = cls;
2169 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2171 gc->plug_pos = gc->plug_pos->next;
2172 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2174 if (NULL == gc->plug_pos)
2179 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2182 gc->addr_pos->addrlen, buf, max);
2183 gc->addr_pos = gc->addr_pos->next;
2189 * Construct our HELLO message from all of the addresses of
2190 * all of the transports.
2193 * @param tc scheduler context
2196 refresh_hello_task (void *cls,
2197 const struct GNUNET_SCHEDULER_TaskContext *tc)
2199 struct GNUNET_HELLO_Message *hello;
2200 struct TransportClient *cpos;
2201 struct NeighbourList *npos;
2202 struct GeneratorContext gc;
2204 hello_task = GNUNET_SCHEDULER_NO_TASK;
2205 gc.plug_pos = plugins;
2206 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2207 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2208 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2211 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2213 GNUNET_STATISTICS_update (stats,
2214 gettext_noop ("# refreshed my HELLO"),
2218 while (cpos != NULL)
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221 "Transmitting my HELLO to client!\n");
2222 transmit_to_client (cpos,
2223 (const struct GNUNET_MessageHeader *) hello,
2228 GNUNET_free_non_null (our_hello);
2230 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2231 for (npos = neighbours; npos != NULL; npos = npos->next)
2233 if (GNUNET_YES != npos->received_pong)
2236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2237 "Transmitting updated `%s' to neighbour `%4s'\n",
2238 "HELLO", GNUNET_i2s (&npos->id));
2240 GNUNET_STATISTICS_update (stats,
2241 gettext_noop ("# transmitted my HELLO to other peers"),
2244 transmit_to_peer (NULL, NULL, 0,
2245 HELLO_ADDRESS_EXPIRATION,
2246 (const char *) our_hello,
2247 GNUNET_HELLO_size(our_hello),
2254 * Schedule task to refresh hello (unless such a
2255 * task exists already).
2260 #if DEBUG_TRANSPORT_HELLO
2261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2262 "refresh_hello() called!\n");
2264 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2267 = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2273 * Iterator over hash map entries that NULLs the session of validation
2274 * entries that match the given session.
2276 * @param cls closure (the 'struct Session*' to match against)
2277 * @param key current key code (peer ID, not used)
2278 * @param value value in the hash map ('struct ValidationEntry*')
2279 * @return GNUNET_YES (we should continue to iterate)
2282 remove_session_validations (void *cls,
2283 const GNUNET_HashCode * key,
2286 struct Session *session = cls;
2287 struct ValidationEntry *ve = value;
2289 if (session == ve->session)
2296 * We've been disconnected from the other peer (for some
2297 * connection-oriented transport). Either quickly
2298 * re-establish the connection or signal the disconnect
2301 * Only signal CORE level disconnect if ALL addresses
2302 * for the peer are exhausted.
2304 * @param p overall plugin context
2305 * @param nl neighbour that was disconnected
2308 try_fast_reconnect (struct TransportPlugin *p,
2309 struct NeighbourList *nl)
2311 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2313 "try_fast_reconnect not implemented!\n");
2314 /* Note: the idea here is to hide problems with transports (or
2315 switching between plugins) from the core to eliminate the need to
2316 re-negotiate session keys and the like; OTOH, we should tell core
2317 quickly (much faster than timeout) `if a connection was lost and
2318 could not be re-established (i.e. other peer went down or is
2319 unable / refuses to communicate);
2321 So we should consider:
2322 1) ideally: our own willingness / need to connect
2323 2) prior failures to connect to this peer (by plugin)
2324 3) ideally: reasons why other peer terminated (as far as knowable)
2326 Most importantly, it must be POSSIBLE for another peer to terminate
2327 a connection for a while (without us instantly re-establishing it).
2328 Similarly, if another peer is gone we should quickly notify CORE.
2329 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2330 on the other end), we should reconnect in such a way that BOTH CORE
2331 services never even notice.
2332 Furthermore, the same mechanism (or small variation) could be used
2333 to switch to a better-performing plugin (ATS).
2335 Finally, this needs to be tested throughly... */
2338 * GNUNET_NO in the call below makes transport disconnect the peer,
2339 * even if only a single address (out of say, six) went away. This
2340 * function must be careful to ONLY disconnect if the peer is gone,
2341 * not just a specific address.
2343 * More specifically, half the places it was used had it WRONG.
2346 /* No reconnect, signal disconnect instead! */
2349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2350 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2351 "try_fast_reconnect");
2353 GNUNET_STATISTICS_update (stats,
2354 gettext_noop ("# disconnects due to try_fast_reconnect"),
2358 disconnect_neighbour (nl, GNUNET_YES);
2364 * Function that will be called whenever the plugin internally
2365 * cleans up a session pointer and hence the service needs to
2366 * discard all of those sessions as well. Plugins that do not
2367 * use sessions can simply omit calling this function and always
2368 * use NULL wherever a session pointer is needed.
2370 * @param cls closure
2371 * @param peer which peer was the session for
2372 * @param session which session is being destoyed
2375 plugin_env_session_end (void *cls,
2376 const struct GNUNET_PeerIdentity *peer,
2377 struct Session *session)
2379 struct TransportPlugin *p = cls;
2380 struct NeighbourList *nl;
2381 struct ReadyList *rl;
2382 struct ForeignAddressList *pos;
2383 struct ForeignAddressList *prev;
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Session ended with peer `%4s', %s\n",
2389 "plugin_env_session_end");
2391 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2392 &remove_session_validations,
2394 nl = find_neighbour (peer);
2398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399 "No neighbour record found for peer `%4s'\n",
2402 return; /* was never marked as connected */
2407 if (rl->plugin == p)
2414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2415 "Plugin was associated with peer `%4s'\n",
2418 GNUNET_STATISTICS_update (stats,
2419 gettext_noop ("# disconnects due to session end"),
2422 disconnect_neighbour (nl, GNUNET_YES);
2426 pos = rl->addresses;
2427 while ( (pos != NULL) &&
2428 (pos->session != session) )
2436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2437 "Session was never marked as ready for peer `%4s'\n",
2441 int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2443 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2444 if (validations_pending ==GNUNET_YES)
2447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2448 "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2453 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2454 GNUNET_STATISTICS_update (stats,
2455 gettext_noop ("# disconnects due to unready session"),
2459 disconnect_neighbour (nl, GNUNET_YES);
2460 return; /* was never marked as connected */
2462 pos->session = NULL;
2463 if (GNUNET_YES == pos->connected)
2465 pos->connected = GNUNET_NO;
2466 GNUNET_STATISTICS_update (stats,
2467 gettext_noop ("# connected addresses"),
2471 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2473 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2474 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2477 if (pos->addrlen != 0)
2479 if (nl->received_pong != GNUNET_NO)
2481 GNUNET_STATISTICS_update (stats,
2482 gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2485 if (GNUNET_YES == pos->connected)
2486 try_fast_reconnect (p, nl);
2490 GNUNET_STATISTICS_update (stats,
2491 gettext_noop ("# disconnects due to missing pong"),
2494 /* FIXME this is never true?! See: line 2416*/
2495 if (GNUNET_YES == pos->connected)
2496 disconnect_neighbour (nl, GNUNET_YES);
2501 /* was inbound connection, free 'pos' */
2503 rl->addresses = pos->next;
2505 prev->next = pos->next;
2506 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2508 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2509 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2511 GNUNET_free_non_null(pos->ressources);
2512 GNUNET_free_non_null(pos->quality);
2514 ats_modify_problem_state (ats, ATS_MODIFIED);
2516 if (GNUNET_YES != pos->connected)
2518 /* nothing else to do, connection was never up... */
2524 if (nl->received_pong == GNUNET_NO)
2526 GNUNET_STATISTICS_update (stats,
2527 gettext_noop ("# disconnects due to NO pong"),
2530 disconnect_neighbour (nl, GNUNET_YES);
2531 return; /* nothing to do, never connected... */
2533 /* check if we have any validated addresses left */
2534 pos = rl->addresses;
2537 if (GNUNET_YES == pos->validated)
2539 GNUNET_STATISTICS_update (stats,
2540 gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2543 try_fast_reconnect (p, nl);
2548 /* no valid addresses left, signal disconnect! */
2551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2552 "Disconnecting peer `%4s', %s\n",
2554 "plugin_env_session_end");
2556 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2557 * it means there aren't any left for this PLUGIN/PEER combination! So
2558 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2559 * when it isn't necessary. Using GNUNET_YES at least checks to see
2560 * if there are any addresses that work first, so as not to overdo it.
2563 GNUNET_STATISTICS_update (stats,
2564 gettext_noop ("# disconnects due to plugin_env_session_end"),
2567 disconnect_neighbour (nl, GNUNET_YES);
2572 * Function that must be called by each plugin to notify the
2573 * transport service about the addresses under which the transport
2574 * provided by the plugin can be reached.
2576 * @param cls closure
2577 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2578 * @param addr one of the addresses of the host, NULL for the last address
2579 * the specific address format depends on the transport
2580 * @param addrlen length of the address
2583 plugin_env_notify_address (void *cls,
2588 struct TransportPlugin *p = cls;
2589 struct OwnAddressList *al;
2590 struct OwnAddressList *prev;
2592 GNUNET_assert (p->api != NULL);
2594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2595 (add_remove == GNUNET_YES)
2596 ? "Adding `%s':%s to the set of our addresses\n"
2597 : "Removing `%s':%s from the set of our addresses\n",
2602 GNUNET_assert (addr != NULL);
2603 if (GNUNET_NO == add_remove)
2609 if ( (addrlen == al->addrlen) &&
2610 (0 == memcmp (addr, &al[1], addrlen)) )
2613 p->addresses = al->next;
2615 prev->next = al->next;
2626 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2627 al->next = p->addresses;
2629 al->addrlen = addrlen;
2630 memcpy (&al[1], addr, addrlen);
2636 * Notify all of our clients about a peer connecting.
2639 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2640 struct GNUNET_TIME_Relative latency,
2643 struct ConnectInfoMessage * cim;
2644 struct TransportClient *cpos;
2648 if (0 == memcmp (peer,
2650 sizeof (struct GNUNET_PeerIdentity)))
2656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657 "Notifying clients about connection with `%s'\n",
2660 GNUNET_STATISTICS_update (stats,
2661 gettext_noop ("# peers connected"),
2666 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2667 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2668 cim = GNUNET_malloc (size);
2669 cim->header.size = htons (size);
2670 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2671 cim->ats_count = htonl(2);
2672 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2673 (&cim->ats)[0].value = htonl (distance);
2674 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2675 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2676 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2677 (&cim->ats)[2].value = htonl (0);
2678 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2680 /* notify ats about connecting peer */
2681 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2684 ats_modify_problem_state(ats, ATS_MODIFIED);
2685 ats_calculate_bandwidth_distribution (ats);
2689 while (cpos != NULL)
2691 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2699 * Notify all of our clients about a peer disconnecting.
2702 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2704 struct DisconnectInfoMessage dim;
2705 struct TransportClient *cpos;
2707 if (0 == memcmp (peer,
2709 sizeof (struct GNUNET_PeerIdentity)))
2715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2716 "Notifying clients about lost connection to `%s'\n",
2719 GNUNET_STATISTICS_update (stats,
2720 gettext_noop ("# peers connected"),
2723 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2724 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2725 dim.reserved = htonl (0);
2726 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2728 /* notify ats about connecting peer */
2729 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2732 ats_modify_problem_state(ats, ATS_MODIFIED);
2733 ats_calculate_bandwidth_distribution (ats);
2738 while (cpos != NULL)
2740 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2747 * Find a ForeignAddressList entry for the given neighbour
2748 * that matches the given address and transport.
2750 * @param neighbour which peer we care about
2751 * @param tname name of the transport plugin
2752 * @param session session to look for, NULL for 'any'; otherwise
2753 * can be used for the service to "learn" this session ID
2755 * @param addr binary address
2756 * @param addrlen length of addr
2757 * @return NULL if no such entry exists
2759 static struct ForeignAddressList *
2760 find_peer_address(struct NeighbourList *neighbour,
2762 struct Session *session,
2766 struct ReadyList *head;
2767 struct ForeignAddressList *pos;
2769 head = neighbour->plugins;
2770 while (head != NULL)
2772 if (0 == strcmp (tname, head->plugin->short_name))
2778 pos = head->addresses;
2779 while ( (pos != NULL) &&
2780 ( (pos->addrlen != addrlen) ||
2781 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2783 if ( (session != NULL) &&
2784 (pos->session == session) )
2788 if ( (session != NULL) && (pos != NULL) )
2789 pos->session = session; /* learn it! */
2795 * Get the peer address struct for the given neighbour and
2796 * address. If it doesn't yet exist, create it.
2798 * @param neighbour which peer we care about
2799 * @param tname name of the transport plugin
2800 * @param session session of the plugin, or NULL for none
2801 * @param addr binary address
2802 * @param addrlen length of addr
2803 * @return NULL if we do not have a transport plugin for 'tname'
2805 static struct ForeignAddressList *
2806 add_peer_address (struct NeighbourList *neighbour,
2808 struct Session *session,
2812 struct ReadyList *head;
2813 struct ForeignAddressList *ret;
2816 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2819 head = neighbour->plugins;
2821 while (head != NULL)
2823 if (0 == strcmp (tname, head->plugin->short_name))
2829 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2830 ret->session = session;
2831 if ((addrlen > 0) && (addr != NULL))
2833 ret->addr = (const char*) &ret[1];
2834 memcpy (&ret[1], addr, addrlen);
2841 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2842 for (c=0; c<available_ressources; c++)
2844 struct ATS_ressource_entry *r = ret->ressources;
2846 r[c].atis_index = ressources[c].atis_index;
2847 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2849 r[c].c = ressources[c].c_unix;
2851 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2853 r[c].c = ressources[c].c_udp;
2855 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2857 r[c].c = ressources[c].c_tcp;
2859 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2861 r[c].c = ressources[c].c_http;
2863 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2865 r[c].c = ressources[c].c_https;
2867 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2869 r[c].c = ressources[c].c_wlan;
2873 r[c].c = ressources[c].c_default;
2874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2875 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2876 GNUNET_i2s(&neighbour->id),
2877 neighbour->plugins->plugin->short_name);
2881 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2882 ret->addrlen = addrlen;
2883 ret->expires = GNUNET_TIME_relative_to_absolute
2884 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2885 ret->latency = GNUNET_TIME_relative_get_forever();
2887 ret->timeout = GNUNET_TIME_relative_to_absolute
2888 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2889 ret->ready_list = head;
2890 ret->next = head->addresses;
2891 head->addresses = ret;
2897 * Closure for 'add_validated_address'.
2899 struct AddValidatedAddressContext
2902 * Entry that has been validated.
2904 const struct ValidationEntry *ve;
2907 * Flag set after we have added the address so
2908 * that we terminate the iteration next time.
2915 * Callback function used to fill a buffer of max bytes with a list of
2916 * addresses in the format used by HELLOs. Should use
2917 * "GNUNET_HELLO_add_address" as a helper function.
2919 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2920 * @param max maximum number of bytes that can be written to buf
2921 * @param buf where to write the address information
2922 * @return number of bytes written, 0 to signal the
2923 * end of the iteration.
2926 add_validated_address (void *cls,
2927 size_t max, void *buf)
2929 struct AddValidatedAddressContext *avac = cls;
2930 const struct ValidationEntry *ve = avac->ve;
2932 if (GNUNET_YES == avac->done)
2934 avac->done = GNUNET_YES;
2935 return GNUNET_HELLO_add_address (ve->transport_name,
2936 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2946 * Closure for 'check_address_exists'.
2948 struct CheckAddressExistsClosure
2951 * Address to check for.
2956 * Name of the transport.
2963 struct Session *session;
2966 * Set to GNUNET_YES if the address exists.
2979 * Iterator over hash map entries. Checks if the given
2980 * validation entry is for the same address as what is given
2983 * @param cls the 'struct CheckAddressExistsClosure*'
2984 * @param key current key code (ignored)
2985 * @param value value in the hash map ('struct ValidationEntry')
2986 * @return GNUNET_YES if we should continue to
2987 * iterate (mismatch), GNUNET_NO if not (entry matched)
2990 check_address_exists (void *cls,
2991 const GNUNET_HashCode * key,
2994 struct CheckAddressExistsClosure *caec = cls;
2995 struct ValidationEntry *ve = value;
2997 if ( (0 == strcmp (caec->tname,
2998 ve->transport_name)) &&
2999 (caec->addrlen == ve->addrlen) &&
3000 (0 == memcmp (caec->addr,
3004 caec->exists = GNUNET_YES;
3007 if ( (ve->session != NULL) &&
3008 (caec->session == ve->session) )
3010 caec->exists = GNUNET_YES;
3018 neighbour_timeout_task (void *cls,
3019 const struct GNUNET_SCHEDULER_TaskContext *tc)
3021 struct NeighbourList *n = cls;
3024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3025 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3027 GNUNET_STATISTICS_update (stats,
3028 gettext_noop ("# disconnects due to timeout"),
3031 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3032 disconnect_neighbour (n, GNUNET_NO);
3037 * Schedule the job that will cause us to send a PING to the
3038 * foreign address to evaluate its validity and latency.
3040 * @param fal address to PING
3043 schedule_next_ping (struct ForeignAddressList *fal);
3047 * Add the given address to the list of foreign addresses
3048 * available for the given peer (check for duplicates).
3050 * @param cls the respective 'struct NeighbourList' to update
3051 * @param tname name of the transport
3052 * @param expiration expiration time
3053 * @param addr the address
3054 * @param addrlen length of the address
3055 * @return GNUNET_OK (always)
3058 add_to_foreign_address_list (void *cls,
3060 struct GNUNET_TIME_Absolute expiration,
3064 struct NeighbourList *n = cls;
3065 struct ForeignAddressList *fal;
3068 GNUNET_STATISTICS_update (stats,
3069 gettext_noop ("# valid peer addresses returned by PEERINFO"),
3073 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3076 #if DEBUG_TRANSPORT_HELLO
3077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3078 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3079 a2s (tname, addr, addrlen),
3081 GNUNET_i2s (&n->id),
3082 expiration.abs_value);
3084 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3087 GNUNET_STATISTICS_update (stats,
3088 gettext_noop ("# previously validated addresses lacking transport"),
3094 fal->expires = GNUNET_TIME_absolute_max (expiration,
3096 schedule_next_ping (fal);
3102 fal->expires = GNUNET_TIME_absolute_max (expiration,
3108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3109 "Failed to add new address for `%4s'\n",
3110 GNUNET_i2s (&n->id));
3114 if (fal->validated == GNUNET_NO)
3116 fal->validated = GNUNET_YES;
3117 GNUNET_STATISTICS_update (stats,
3118 gettext_noop ("# peer addresses considered valid"),
3122 if (try == GNUNET_YES)
3125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3126 "Have new addresses, will try to trigger transmissions.\n");
3128 try_transmission_to_peer (n);
3135 * Add addresses in validated HELLO "h" to the set of addresses
3136 * we have for this peer.
3138 * @param cls closure ('struct NeighbourList*')
3139 * @param peer id of the peer, NULL for last call
3140 * @param h hello message for the peer (can be NULL)
3141 * @param err_msg NULL if successful, otherwise contains error message
3144 add_hello_for_peer (void *cls,
3145 const struct GNUNET_PeerIdentity *peer,
3146 const struct GNUNET_HELLO_Message *h,
3147 const char *err_msg)
3149 struct NeighbourList *n = cls;
3151 if (err_msg != NULL)
3154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3155 _("Error in communication with PEERINFO service: %s\n"),
3162 GNUNET_STATISTICS_update (stats,
3163 gettext_noop ("# outstanding peerinfo iterate requests"),
3170 return; /* no HELLO available */
3172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3177 if (GNUNET_YES != n->public_key_valid)
3179 GNUNET_HELLO_get_key (h, &n->publicKey);
3180 n->public_key_valid = GNUNET_YES;
3182 GNUNET_HELLO_iterate_addresses (h,
3184 &add_to_foreign_address_list,
3190 * Create a fresh entry in our neighbour list for the given peer.
3191 * Will try to transmit our current HELLO to the new neighbour.
3192 * Do not call this function directly, use 'setup_peer_check_blacklist.
3194 * @param peer the peer for which we create the entry
3195 * @param do_hello should we schedule transmitting a HELLO
3196 * @return the new neighbour list entry
3198 static struct NeighbourList *
3199 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3202 struct NeighbourList *n;
3203 struct TransportPlugin *tp;
3204 struct ReadyList *rl;
3206 GNUNET_assert (0 != memcmp (peer,
3208 sizeof (struct GNUNET_PeerIdentity)));
3210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211 "Setting up state for neighbour `%4s'\n",
3214 GNUNET_STATISTICS_update (stats,
3215 gettext_noop ("# active neighbours"),
3218 n = GNUNET_malloc (sizeof (struct NeighbourList));
3219 n->next = neighbours;
3223 GNUNET_TIME_relative_to_absolute
3224 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3225 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3226 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3227 MAX_BANDWIDTH_CARRY_S);
3231 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3233 rl = GNUNET_malloc (sizeof (struct ReadyList));
3235 rl->next = n->plugins;
3238 rl->addresses = NULL;
3242 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3244 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3245 &neighbour_timeout_task, n);
3248 GNUNET_STATISTICS_update (stats,
3249 gettext_noop ("# peerinfo new neighbor iterate requests"),
3252 GNUNET_STATISTICS_update (stats,
3253 gettext_noop ("# outstanding peerinfo iterate requests"),
3256 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3257 GNUNET_TIME_UNIT_FOREVER_REL,
3258 &add_hello_for_peer, n);
3260 GNUNET_STATISTICS_update (stats,
3261 gettext_noop ("# HELLO's sent to new neighbors"),
3264 if (NULL != our_hello)
3265 transmit_to_peer (NULL, NULL, 0,
3266 HELLO_ADDRESS_EXPIRATION,
3267 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3275 * Function called after we have checked if communicating
3276 * with a given peer is acceptable.
3278 * @param cls closure
3279 * @param n NULL if communication is not acceptable
3281 typedef void (*SetupContinuation)(void *cls,
3282 struct NeighbourList *n);
3286 * Information kept for each client registered to perform
3292 * This is a linked list.
3294 struct Blacklisters *next;
3297 * This is a linked list.
3299 struct Blacklisters *prev;
3302 * Client responsible for this entry.
3304 struct GNUNET_SERVER_Client *client;
3307 * Blacklist check that we're currently performing.
3309 struct BlacklistCheck *bc;
3315 * Head of DLL of blacklisting clients.
3317 static struct Blacklisters *bl_head;
3320 * Tail of DLL of blacklisting clients.
3322 static struct Blacklisters *bl_tail;
3326 * Context we use when performing a blacklist check.
3328 struct BlacklistCheck
3332 * This is a linked list.
3334 struct BlacklistCheck *next;
3337 * This is a linked list.
3339 struct BlacklistCheck *prev;
3342 * Peer being checked.
3344 struct GNUNET_PeerIdentity peer;
3347 * Option for setup neighbour afterwards.
3352 * Continuation to call with the result.
3354 SetupContinuation cont;
3362 * Current transmission request handle for this client, or NULL if no
3363 * request is pending.
3365 struct GNUNET_CONNECTION_TransmitHandle *th;
3368 * Our current position in the blacklisters list.
3370 struct Blacklisters *bl_pos;
3373 * Current task performing the check.
3375 GNUNET_SCHEDULER_TaskIdentifier task;
3380 * Head of DLL of active blacklisting queries.
3382 static struct BlacklistCheck *bc_head;
3385 * Tail of DLL of active blacklisting queries.
3387 static struct BlacklistCheck *bc_tail;
3391 * Perform next action in the blacklist check.
3393 * @param cls the 'struct BlacklistCheck*'
3397 do_blacklist_check (void *cls,
3398 const struct GNUNET_SCHEDULER_TaskContext *tc);
3401 * Transmit blacklist query to the client.
3403 * @param cls the 'struct BlacklistCheck'
3404 * @param size number of bytes allowed
3405 * @param buf where to copy the message
3406 * @return number of bytes copied to buf
3409 transmit_blacklist_message (void *cls,
3413 struct BlacklistCheck *bc = cls;
3414 struct Blacklisters *bl;
3415 struct BlacklistMessage bm;
3420 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3421 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3423 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3424 "Failed to send blacklist test for peer `%s' to client\n",
3425 GNUNET_i2s (&bc->peer));
3429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3430 "Sending blacklist test for peer `%s' to client\n",
3431 GNUNET_i2s (&bc->peer));
3434 bm.header.size = htons (sizeof (struct BlacklistMessage));
3435 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3436 bm.is_allowed = htonl (0);
3438 memcpy (buf, &bm, sizeof (bm));
3439 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3445 * Perform next action in the blacklist check.
3447 * @param cls the 'struct BlacklistCheck*'
3451 do_blacklist_check (void *cls,
3452 const struct GNUNET_SCHEDULER_TaskContext *tc)
3454 struct BlacklistCheck *bc = cls;
3455 struct Blacklisters *bl;
3457 bc->task = GNUNET_SCHEDULER_NO_TASK;
3462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3464 GNUNET_i2s (&bc->peer));
3466 bc->cont (bc->cont_cls,
3467 setup_new_neighbour (&bc->peer, bc->do_hello));
3474 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3475 sizeof (struct BlacklistMessage),
3476 GNUNET_TIME_UNIT_FOREVER_REL,
3477 &transmit_blacklist_message,
3484 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3485 * does not yet exist, check the blacklist. If the blacklist says creating
3486 * one is acceptable, create one and call the continuation; otherwise
3487 * call the continuation with NULL.
3489 * @param peer peer to setup or look up a struct NeighbourList for
3490 * @param do_hello should we also schedule sending our HELLO to the peer
3491 * if this is a new record
3492 * @param cont function to call with the 'struct NeigbhbourList*'
3493 * @param cont_cls closure for cont
3496 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3498 SetupContinuation cont,
3501 struct NeighbourList *n;
3502 struct BlacklistCheck *bc;
3504 n = find_neighbour(peer);
3508 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3509 "Neighbour record exists for peer `%s'\n",
3516 if (bl_head == NULL)
3519 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3521 setup_new_neighbour(peer, do_hello);
3524 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3525 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3527 bc->do_hello = do_hello;
3529 bc->cont_cls = cont_cls;
3530 bc->bl_pos = bl_head;
3531 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3537 * Function called with the result of querying a new blacklister about
3538 * it being allowed (or not) to continue to talk to an existing neighbour.
3540 * @param cls the original 'struct NeighbourList'
3541 * @param n NULL if we need to disconnect
3544 confirm_or_drop_neighbour (void *cls,
3545 struct NeighbourList *n)
3547 struct NeighbourList * orig = cls;
3552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3553 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3554 "confirm_or_drop_neighboUr");
3556 GNUNET_STATISTICS_update (stats,
3557 gettext_noop ("# disconnects due to blacklist"),
3560 disconnect_neighbour (orig, GNUNET_NO);
3566 * Handle a request to start a blacklist.
3568 * @param cls closure (always NULL)
3569 * @param client identification of the client
3570 * @param message the actual message
3573 handle_blacklist_init (void *cls,
3574 struct GNUNET_SERVER_Client *client,
3575 const struct GNUNET_MessageHeader *message)
3577 struct Blacklisters *bl;
3578 struct BlacklistCheck *bc;
3579 struct NeighbourList *n;
3584 if (bl->client == client)
3587 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3592 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3593 bl->client = client;
3594 GNUNET_SERVER_client_keep (client);
3595 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3596 /* confirm that all existing connections are OK! */
3600 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3601 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3603 bc->do_hello = GNUNET_NO;
3604 bc->cont = &confirm_or_drop_neighbour;
3607 if (n == neighbours) /* all would wait for the same client, no need to
3608 create more than just the first task right now */
3609 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3617 * Handle a request to blacklist a peer.
3619 * @param cls closure (always NULL)
3620 * @param client identification of the client
3621 * @param message the actual message
3624 handle_blacklist_reply (void *cls,
3625 struct GNUNET_SERVER_Client *client,
3626 const struct GNUNET_MessageHeader *message)
3628 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3629 struct Blacklisters *bl;
3630 struct BlacklistCheck *bc;
3633 while ( (bl != NULL) &&
3634 (bl->client != client) )
3639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3640 "Blacklist client disconnected\n");
3642 /* FIXME: other error handling here!? */
3643 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3648 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3652 "Blacklist check failed, peer not allowed\n");
3654 bc->cont (bc->cont_cls, NULL);
3655 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3662 "Blacklist check succeeded, continuing with checks\n");
3664 bc->bl_pos = bc->bl_pos->next;
3665 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3668 /* check if any other bc's are waiting for this blacklister */
3672 if ( (bc->bl_pos == bl) &&
3673 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3674 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3682 * Send periodic PING messages to a given foreign address.
3684 * @param cls our 'struct PeriodicValidationContext*'
3685 * @param tc task context
3688 send_periodic_ping (void *cls,
3689 const struct GNUNET_SCHEDULER_TaskContext *tc)
3691 struct ForeignAddressList *peer_address = cls;
3692 struct TransportPlugin *tp;
3693 struct ValidationEntry *va;
3694 struct NeighbourList *neighbour;
3695 struct TransportPingMessage ping;
3696 struct CheckAddressExistsClosure caec;
3698 uint16_t hello_size;
3702 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3703 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3705 GNUNET_assert (peer_address != NULL);
3706 tp = peer_address->ready_list->plugin;
3707 neighbour = peer_address->ready_list->neighbour;
3708 if (GNUNET_YES != neighbour->public_key_valid)
3710 /* no public key yet, try again later */
3711 schedule_next_ping (peer_address);
3714 caec.addr = peer_address->addr;
3715 caec.addrlen = peer_address->addrlen;
3716 caec.tname = tp->short_name;
3717 caec.session = peer_address->session;
3718 caec.exists = GNUNET_NO;
3720 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3721 &check_address_exists,
3723 if (caec.exists == GNUNET_YES)
3725 /* During validation attempts we will likely trigger the other
3726 peer trying to validate our address which in turn will cause
3727 it to send us its HELLO, so we expect to hit this case rather
3728 frequently. Only print something if we are very verbose. */
3729 #if DEBUG_TRANSPORT > 1
3730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3731 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3732 (peer_address->addr != NULL)
3733 ? a2s (tp->short_name,
3735 peer_address->addrlen)
3738 GNUNET_i2s (&neighbour->id));
3740 schedule_next_ping (peer_address);
3743 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3744 va->transport_name = GNUNET_strdup (tp->short_name);
3745 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3747 va->send_time = GNUNET_TIME_absolute_get();
3748 va->session = peer_address->session;
3749 if (peer_address->addr != NULL)
3751 va->addr = (const void*) &va[1];
3752 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3753 va->addrlen = peer_address->addrlen;
3755 memcpy(&va->publicKey,
3756 &neighbour->publicKey,
3757 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3759 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3760 &timeout_hello_validation,
3762 GNUNET_CONTAINER_multihashmap_put (validation_map,
3763 &neighbour->id.hashPubKey,
3765 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3767 if (peer_address->validated != GNUNET_YES)
3768 hello_size = GNUNET_HELLO_size(our_hello);
3772 tsize = sizeof(struct TransportPingMessage) + hello_size;
3774 if (peer_address->addr != NULL)
3776 slen = strlen (tp->short_name) + 1;
3777 tsize += slen + peer_address->addrlen;
3781 slen = 0; /* make gcc happy */
3783 message_buf = GNUNET_malloc(tsize);
3784 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3785 ping.challenge = htonl(va->challenge);
3786 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3787 if (peer_address->validated != GNUNET_YES)
3789 memcpy(message_buf, our_hello, hello_size);
3792 if (peer_address->addr != NULL)
3794 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3795 peer_address->addrlen +
3797 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3800 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3802 peer_address->addrlen);
3806 ping.header.size = htons(sizeof(struct TransportPingMessage));
3809 memcpy(&message_buf[hello_size],
3811 sizeof(struct TransportPingMessage));
3813 #if DEBUG_TRANSPORT_REVALIDATION
3814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3815 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3816 (peer_address->addr != NULL)
3817 ? a2s (peer_address->plugin->short_name,
3819 peer_address->addrlen)
3822 GNUNET_i2s (&neighbour->id),
3823 "HELLO", hello_size,
3826 if (peer_address->validated != GNUNET_YES)
3827 GNUNET_STATISTICS_update (stats,
3828 gettext_noop ("# PING with HELLO messages sent"),
3832 GNUNET_STATISTICS_update (stats,
3833 gettext_noop ("# PING without HELLO messages sent"),
3836 GNUNET_STATISTICS_update (stats,
3837 gettext_noop ("# PING messages sent for re-validation"),
3840 transmit_to_peer (NULL, peer_address,
3841 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3842 HELLO_VERIFICATION_TIMEOUT,
3844 GNUNET_YES, neighbour);
3845 GNUNET_free(message_buf);
3846 schedule_next_ping (peer_address);
3851 * Schedule the job that will cause us to send a PING to the
3852 * foreign address to evaluate its validity and latency.
3854 * @param fal address to PING
3857 schedule_next_ping (struct ForeignAddressList *fal)
3859 struct GNUNET_TIME_Relative delay;
3861 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3863 GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3864 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3866 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3867 delay.rel_value /= 2; /* do before expiration */
3868 delay = GNUNET_TIME_relative_min (delay,
3869 LATENCY_EVALUATION_MAX_DELAY);
3870 if (GNUNET_YES != fal->estimated)
3872 delay = GNUNET_TIME_UNIT_ZERO;
3873 fal->estimated = GNUNET_YES;
3876 if (GNUNET_YES == fal->connected)
3878 delay = GNUNET_TIME_relative_min (delay,
3879 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3881 /* FIXME: also adjust delay based on how close the last
3882 observed latency is to the latency of the best alternative */
3883 /* bound how fast we can go */
3884 delay = GNUNET_TIME_relative_max (delay,
3885 GNUNET_TIME_UNIT_SECONDS);
3886 /* randomize a bit (to avoid doing all at the same time) */
3887 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3889 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3890 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3891 &send_periodic_ping,
3899 * Function that will be called if we receive some payload
3900 * from another peer.
3902 * @param message the payload
3903 * @param n peer who claimed to be the sender
3906 handle_payload_message (const struct GNUNET_MessageHeader *message,
3907 struct NeighbourList *n)
3909 struct InboundMessage *im;
3910 struct TransportClient *cpos;
3913 msize = ntohs (message->size);
3914 if (n->received_pong == GNUNET_NO)
3917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3918 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3919 ntohs (message->type),
3920 ntohs (message->size),
3921 GNUNET_i2s (&n->id));
3923 GNUNET_free_non_null (n->pre_connect_message_buffer);
3924 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3925 memcpy (n->pre_connect_message_buffer, message, msize);
3930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3931 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3932 ntohs (message->type),
3933 ntohs (message->size),
3934 GNUNET_i2s (&n->id));
3936 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3939 n->quota_violation_count++;
3941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3942 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3943 n->in_tracker.available_bytes_per_s__,
3944 n->quota_violation_count);
3946 /* Discount 32k per violation */
3947 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3952 if (n->quota_violation_count > 0)
3954 /* try to add 32k back */
3955 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3957 n->quota_violation_count--;
3960 GNUNET_STATISTICS_update (stats,
3961 gettext_noop ("# payload received from other peers"),
3964 /* transmit message to all clients */
3965 uint32_t ats_count = 2;
3966 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3967 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3970 im = GNUNET_malloc (size);
3971 im->header.size = htons (size);
3972 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3974 im->ats_count = htonl(ats_count);
3975 /* Setting ATS data */
3976 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3977 (&(im->ats))[0].value = htonl (n->distance);
3978 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3979 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3980 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3981 (&(im->ats))[ats_count].value = htonl (0);
3983 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3985 while (cpos != NULL)
3987 transmit_to_client (cpos, &im->header, GNUNET_YES);
3995 * Iterator over hash map entries. Checks if the given validation
3996 * entry is for the same challenge as what is given in the PONG.
3998 * @param cls the 'struct TransportPongMessage*'
3999 * @param key peer identity
4000 * @param value value in the hash map ('struct ValidationEntry')
4001 * @return GNUNET_YES if we should continue to
4002 * iterate (mismatch), GNUNET_NO if not (entry matched)
4005 check_pending_validation (void *cls,
4006 const GNUNET_HashCode * key,
4009 const struct TransportPongMessage *pong = cls;
4010 struct ValidationEntry *ve = value;
4011 struct AddValidatedAddressContext avac;
4012 unsigned int challenge = ntohl(pong->challenge);
4013 struct GNUNET_HELLO_Message *hello;
4014 struct GNUNET_PeerIdentity target;
4015 struct NeighbourList *n;
4016 struct ForeignAddressList *fal;
4017 struct OwnAddressList *oal;
4018 struct TransportPlugin *tp;
4019 struct GNUNET_MessageHeader *prem;
4025 ps = ntohs (pong->header.size);
4026 if (ps < sizeof (struct TransportPongMessage))
4028 GNUNET_break_op (0);
4031 addr = (const char*) &pong[1];
4032 slen = strlen (ve->transport_name) + 1;
4033 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4034 (ve->challenge != challenge) ||
4035 (addr[slen-1] != '\0') ||
4036 (0 != strcmp (addr, ve->transport_name)) ||
4037 (ntohl (pong->purpose.size)
4038 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4040 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4041 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4046 alen = ps - sizeof (struct TransportPongMessage) - slen;
4047 switch (ntohl (pong->purpose.purpose))
4049 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4050 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4051 (0 != memcmp (&addr[slen],
4055 return GNUNET_YES; /* different entry, keep trying! */
4057 if (0 != memcmp (&pong->pid,
4059 sizeof (struct GNUNET_PeerIdentity)))
4061 GNUNET_break_op (0);
4065 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4070 GNUNET_break_op (0);
4075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4076 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4078 a2s (ve->transport_name,
4079 (const struct sockaddr *) ve->addr,
4081 ve->transport_name);
4084 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4085 if (0 != memcmp (&pong->pid,
4087 sizeof (struct GNUNET_PeerIdentity)))
4091 GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4094 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4095 GNUNET_i2s (&my_identity),
4101 if (ve->addrlen != 0)
4103 /* must have been for a different validation entry */
4106 tp = find_transport (ve->transport_name);
4112 oal = tp->addresses;
4115 if ( (oal->addrlen == alen) &&
4116 (0 == memcmp (&oal[1],
4124 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4125 _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4126 GNUNET_i2s (&pong->pid),
4127 a2s (ve->transport_name,
4130 /* FIXME: since the sender of the PONG currently uses the
4131 wrong address (see FIMXE there!), we cannot run a
4132 proper check here... */
4138 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4143 GNUNET_break_op (0);
4148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4149 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4151 a2s (ve->transport_name,
4154 ve->transport_name);
4158 GNUNET_break_op (0);
4161 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4164 _("Received expired signature. Check system time.\n"));
4167 GNUNET_STATISTICS_update (stats,
4168 gettext_noop ("# address validation successes"),
4171 /* create the updated HELLO */
4172 GNUNET_CRYPTO_hash (&ve->publicKey,
4173 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4174 &target.hashPubKey);
4175 if (ve->addr != NULL)
4177 avac.done = GNUNET_NO;
4179 hello = GNUNET_HELLO_create (&ve->publicKey,
4180 &add_validated_address,
4182 GNUNET_PEERINFO_add_peer (peerinfo,
4184 GNUNET_free (hello);
4186 n = find_neighbour (&target);
4189 n->publicKey = ve->publicKey;
4190 n->public_key_valid = GNUNET_YES;
4191 fal = add_peer_address (n,
4196 GNUNET_assert (fal != NULL);
4197 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4198 fal->validated = GNUNET_YES;
4199 mark_address_connected (fal);
4200 GNUNET_STATISTICS_update (stats,
4201 gettext_noop ("# peer addresses considered valid"),
4204 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4205 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4207 schedule_next_ping (fal);
4208 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4209 n->latency = fal->latency;
4211 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4213 n->distance = fal->distance;
4214 if (GNUNET_NO == n->received_pong)
4216 n->received_pong = GNUNET_YES;
4217 notify_clients_connect (&target, n->latency, n->distance);
4218 if (NULL != (prem = n->pre_connect_message_buffer))
4220 n->pre_connect_message_buffer = NULL;
4221 handle_payload_message (prem, n);
4225 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4227 GNUNET_SCHEDULER_cancel (n->retry_task);
4228 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4229 try_transmission_to_peer (n);
4233 /* clean up validation entry */
4234 GNUNET_assert (GNUNET_YES ==
4235 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4238 abort_validation (NULL, NULL, ve);
4244 * Function that will be called if we receive a validation
4245 * of an address challenge that we transmitted to another
4246 * peer. Note that the validation should only be considered
4247 * acceptable if the challenge matches AND if the sender
4248 * address is at least a plausible address for this peer
4249 * (otherwise we may be seeing a MiM attack).
4251 * @param cls closure
4252 * @param message the pong message
4253 * @param peer who responded to our challenge
4254 * @param sender_address string describing our sender address (as observed
4255 * by the other peer in binary format)
4256 * @param sender_address_len number of bytes in 'sender_address'
4259 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4260 const struct GNUNET_PeerIdentity *peer,
4261 const char *sender_address,
4262 size_t sender_address_len)
4264 if (0 == memcmp (peer,
4266 sizeof (struct GNUNET_PeerIdentity)))
4268 /* PONG send to self, ignore */
4269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4270 "Receiving `%s' message from myself\n",
4274 #if DEBUG_TRANSPORT > 1
4275 /* we get tons of these that just get discarded, only log
4276 if we are quite verbose */
4277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4278 "Receiving `%s' message from `%4s'.\n", "PONG",
4281 GNUNET_STATISTICS_update (stats,
4282 gettext_noop ("# PONG messages received"),
4285 if (GNUNET_SYSERR !=
4286 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4288 &check_pending_validation,
4291 /* This is *expected* to happen a lot since we send
4292 PONGs to *all* known addresses of the sender of
4293 the PING, so most likely we get multiple PONGs
4294 per PING, and all but the first PONG will end up
4295 here. So really we should not print anything here
4296 unless we want to be very, very verbose... */
4297 #if DEBUG_TRANSPORT > 2
4298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4299 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4311 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4313 * @param cls the 'struct ValidationEntry*'
4314 * @param neighbour neighbour to validate, NULL if validation failed
4317 transmit_hello_and_ping (void *cls,
4318 struct NeighbourList *neighbour)
4320 struct ValidationEntry *va = cls;
4321 struct ForeignAddressList *peer_address;
4322 struct TransportPingMessage ping;
4323 uint16_t hello_size;
4326 struct GNUNET_PeerIdentity id;
4329 GNUNET_CRYPTO_hash (&va->publicKey,
4330 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4332 if (neighbour == NULL)
4334 /* FIXME: stats... */
4335 GNUNET_break (GNUNET_OK ==
4336 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4339 abort_validation (NULL, NULL, va);
4342 neighbour->publicKey = va->publicKey;
4343 neighbour->public_key_valid = GNUNET_YES;
4344 peer_address = add_peer_address (neighbour,
4345 va->transport_name, NULL,
4346 (const void*) &va[1],
4348 if (peer_address == NULL)
4350 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4351 "Failed to add peer `%4s' for plugin `%s'\n",
4352 GNUNET_i2s (&neighbour->id),
4353 va->transport_name);
4354 GNUNET_break (GNUNET_OK ==
4355 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4358 abort_validation (NULL, NULL, va);
4361 if (NULL == our_hello)
4362 refresh_hello_task (NULL, NULL);
4363 hello_size = GNUNET_HELLO_size(our_hello);
4364 slen = strlen(va->transport_name) + 1;
4365 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4366 message_buf = GNUNET_malloc(tsize);
4367 ping.challenge = htonl(va->challenge);
4368 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4369 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4370 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4371 memcpy(message_buf, our_hello, hello_size);
4372 memcpy(&message_buf[hello_size],
4374 sizeof(struct TransportPingMessage));
4375 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4378 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4383 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4386 : a2s (va->transport_name,
4387 (const void*) &va[1], va->addrlen),
4389 GNUNET_i2s (&neighbour->id),
4390 "HELLO", hello_size,
4391 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4394 GNUNET_STATISTICS_update (stats,
4395 gettext_noop ("# PING messages sent for initial validation"),
4398 transmit_to_peer (NULL, peer_address,
4399 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4400 HELLO_VERIFICATION_TIMEOUT,
4402 GNUNET_YES, neighbour);
4403 GNUNET_free(message_buf);
4408 * Check if the given address is already being validated; if not,
4409 * append the given address to the list of entries that are being be
4410 * validated and initiate validation.
4412 * @param cls closure ('struct CheckHelloValidatedContext *')
4413 * @param tname name of the transport
4414 * @param expiration expiration time
4415 * @param addr the address
4416 * @param addrlen length of the address
4417 * @return GNUNET_OK (always)
4420 run_validation (void *cls,
4422 struct GNUNET_TIME_Absolute expiration,
4426 struct CheckHelloValidatedContext *chvc = cls;
4427 struct GNUNET_PeerIdentity id;
4428 struct TransportPlugin *tp;
4429 struct ValidationEntry *va;
4430 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4431 struct CheckAddressExistsClosure caec;
4432 struct OwnAddressList *oal;
4434 GNUNET_assert (addr != NULL);
4436 GNUNET_STATISTICS_update (stats,
4437 gettext_noop ("# peer addresses scheduled for validation"),
4440 tp = find_transport (tname);
4443 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4444 GNUNET_ERROR_TYPE_BULK,
4446 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4448 GNUNET_STATISTICS_update (stats,
4449 gettext_noop ("# peer addresses not validated (plugin not available)"),
4454 /* check if this is one of our own addresses */
4455 oal = tp->addresses;
4458 if ( (oal->addrlen == addrlen) &&
4459 (0 == memcmp (&oal[1],
4463 /* not plausible, this address is equivalent to our own address! */
4464 GNUNET_STATISTICS_update (stats,
4465 gettext_noop ("# peer addresses not validated (loopback)"),
4472 GNUNET_HELLO_get_key (chvc->hello, &pk);
4473 GNUNET_CRYPTO_hash (&pk,
4475 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4478 if (is_blacklisted(&id, tp))
4481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4482 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4490 caec.addrlen = addrlen;
4491 caec.session = NULL;
4493 caec.exists = GNUNET_NO;
4494 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4495 &check_address_exists,
4497 if (caec.exists == GNUNET_YES)
4499 /* During validation attempts we will likely trigger the other
4500 peer trying to validate our address which in turn will cause
4501 it to send us its HELLO, so we expect to hit this case rather
4502 frequently. Only print something if we are very verbose. */
4503 #if DEBUG_TRANSPORT > 1
4504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4505 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4506 a2s (tname, addr, addrlen),
4510 GNUNET_STATISTICS_update (stats,
4511 gettext_noop ("# peer addresses not validated (in progress)"),
4516 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4519 va->transport_name = GNUNET_strdup (tname);
4520 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4522 va->send_time = GNUNET_TIME_absolute_get();
4523 va->addr = (const void*) &va[1];
4524 memcpy (&va[1], addr, addrlen);
4525 va->addrlen = addrlen;
4526 GNUNET_HELLO_get_key (chvc->hello,
4528 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4529 &timeout_hello_validation,
4531 GNUNET_CONTAINER_multihashmap_put (validation_map,
4534 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4535 setup_peer_check_blacklist (&id, GNUNET_NO,
4536 &transmit_hello_and_ping,
4543 * Check if addresses in validated hello "h" overlap with
4544 * those in "chvc->hello" and validate the rest.
4546 * @param cls closure
4547 * @param peer id of the peer, NULL for last call
4548 * @param h hello message for the peer (can be NULL)
4549 * @param err_msg NULL if successful, otherwise contains error message
4552 check_hello_validated (void *cls,
4553 const struct GNUNET_PeerIdentity *peer,
4554 const struct GNUNET_HELLO_Message *h,
4555 const char *err_msg)
4557 struct CheckHelloValidatedContext *chvc = cls;
4558 struct GNUNET_HELLO_Message *plain_hello;
4559 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4560 struct GNUNET_PeerIdentity target;
4561 struct NeighbourList *n;
4563 if (err_msg != NULL)
4566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4567 _("Error in communication with PEERINFO service: %s\n"),
4575 GNUNET_STATISTICS_update (stats,
4576 gettext_noop ("# outstanding peerinfo iterate requests"),
4580 if (GNUNET_NO == chvc->hello_known)
4582 /* notify PEERINFO about the peer now, so that we at least
4583 have the public key if some other component needs it */
4584 GNUNET_HELLO_get_key (chvc->hello, &pk);
4585 GNUNET_CRYPTO_hash (&pk,
4586 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4587 &target.hashPubKey);
4588 plain_hello = GNUNET_HELLO_create (&pk,
4591 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4592 GNUNET_free (plain_hello);
4593 #if DEBUG_TRANSPORT_HELLO
4594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4595 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4597 GNUNET_i2s (&target));
4599 GNUNET_STATISTICS_update (stats,
4600 gettext_noop ("# new HELLOs requiring full validation"),
4603 GNUNET_HELLO_iterate_addresses (chvc->hello,
4610 GNUNET_STATISTICS_update (stats,
4611 gettext_noop ("# duplicate HELLO (peer known)"),
4616 if (chvc->ve_count == 0)
4618 GNUNET_CONTAINER_DLL_remove (chvc_head,
4627 #if DEBUG_TRANSPORT_HELLO
4628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4629 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4633 chvc->hello_known = GNUNET_YES;
4634 n = find_neighbour (peer);
4637 #if DEBUG_TRANSPORT_HELLO
4638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4639 "Calling hello_iterate_addresses for %s!\n",
4642 GNUNET_HELLO_iterate_addresses (h,
4644 &add_to_foreign_address_list,
4646 try_transmission_to_peer (n);
4650 #if DEBUG_TRANSPORT_HELLO
4651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4652 "No existing neighbor record for %s!\n",
4655 GNUNET_STATISTICS_update (stats,
4656 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4660 GNUNET_STATISTICS_update (stats,
4661 gettext_noop ("# HELLO validations (update case)"),
4664 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4666 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4673 * Process HELLO-message.
4675 * @param plugin transport involved, may be NULL
4676 * @param message the actual message
4677 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4680 process_hello (struct TransportPlugin *plugin,
4681 const struct GNUNET_MessageHeader *message)
4684 struct GNUNET_PeerIdentity target;
4685 const struct GNUNET_HELLO_Message *hello;
4686 struct CheckHelloValidatedContext *chvc;
4687 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4688 struct NeighbourList *n;
4689 #if DEBUG_TRANSPORT_HELLO > 2
4693 hsize = ntohs (message->size);
4694 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4695 (hsize < sizeof (struct GNUNET_MessageHeader)))
4698 return GNUNET_SYSERR;
4700 GNUNET_STATISTICS_update (stats,
4701 gettext_noop ("# HELLOs received for validation"),
4705 hello = (const struct GNUNET_HELLO_Message *) message;
4706 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4708 #if DEBUG_TRANSPORT_HELLO
4709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4710 "Unable to get public key from `%s' for `%4s'!\n",
4712 GNUNET_i2s (&target));
4714 GNUNET_break_op (0);
4715 return GNUNET_SYSERR;
4717 GNUNET_CRYPTO_hash (&publicKey,
4718 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4719 &target.hashPubKey);
4721 #if DEBUG_TRANSPORT_HELLO
4722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4723 "Received `%s' message for `%4s'\n",
4725 GNUNET_i2s (&target));
4727 if (0 == memcmp (&my_identity,
4729 sizeof (struct GNUNET_PeerIdentity)))
4731 GNUNET_STATISTICS_update (stats,
4732 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4737 n = find_neighbour (&target);
4739 (! n->public_key_valid) )
4741 GNUNET_HELLO_get_key (hello, &n->publicKey);
4742 n->public_key_valid = GNUNET_YES;
4745 /* check if load is too high before doing expensive stuff */
4746 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4748 GNUNET_STATISTICS_update (stats,
4749 gettext_noop ("# HELLOs ignored due to high load"),
4752 #if DEBUG_TRANSPORT_HELLO
4753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4754 "Ignoring `%s' for `%4s', load too high.\n",
4756 GNUNET_i2s (&target));
4763 while (NULL != chvc)
4765 if (GNUNET_HELLO_equals (hello,
4767 GNUNET_TIME_absolute_get ()).abs_value > 0)
4769 #if DEBUG_TRANSPORT_HELLO > 2
4770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4771 "Received duplicate `%s' message for `%4s'; ignored\n",
4773 GNUNET_i2s (&target));
4775 return GNUNET_OK; /* validation already pending */
4777 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4778 GNUNET_break (0 != memcmp (hello, chvc->hello,
4779 GNUNET_HELLO_size(hello)));
4784 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4785 if ((NULL != temp_neighbor))
4787 fprintf(stderr, "Already know peer, ignoring hello\n");
4792 #if DEBUG_TRANSPORT_HELLO > 2
4795 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4798 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4801 GNUNET_i2s (&target),
4803 GNUNET_HELLO_size(hello));
4808 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4810 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4811 memcpy (&chvc[1], hello, hsize);
4812 GNUNET_CONTAINER_DLL_insert (chvc_head,
4815 /* finally, check if HELLO was previously validated
4816 (continuation will then schedule actual validation) */
4817 GNUNET_STATISTICS_update (stats,
4818 gettext_noop ("# peerinfo process hello iterate requests"),
4821 GNUNET_STATISTICS_update (stats,
4822 gettext_noop ("# outstanding peerinfo iterate requests"),
4825 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4827 HELLO_VERIFICATION_TIMEOUT,
4828 &check_hello_validated, chvc);
4834 * The peer specified by the given neighbour has timed-out or a plugin
4835 * has disconnected. We may either need to do nothing (other plugins
4836 * still up), or trigger a full disconnect and clean up. This
4837 * function updates our state and does the necessary notifications.
4838 * Also notifies our clients that the neighbour is now officially
4841 * @param n the neighbour list entry for the peer
4842 * @param check GNUNET_YES to check if ALL addresses for this peer
4843 * are gone, GNUNET_NO to force a disconnect of the peer
4844 * regardless of whether other addresses exist.
4847 disconnect_neighbour (struct NeighbourList *n, int check)
4849 struct ReadyList *rpos;
4850 struct NeighbourList *npos;
4851 struct NeighbourList *nprev;
4852 struct MessageQueue *mq;
4853 struct ForeignAddressList *peer_addresses;
4854 struct ForeignAddressList *peer_pos;
4856 if (GNUNET_YES == n->in_disconnect)
4858 if (GNUNET_YES == check)
4861 while (NULL != rpos)
4863 peer_addresses = rpos->addresses;
4864 while (peer_addresses != NULL)
4866 /* Do not disconnect if: an address is connected or an inbound address exists */
4867 if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4871 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4872 GNUNET_i2s (&n->id),
4873 a2s (peer_addresses->ready_list->plugin->short_name,
4874 peer_addresses->addr,
4875 peer_addresses->addrlen));
4877 return; /* still connected */
4879 peer_addresses = peer_addresses->next;
4885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4886 "Disconnecting from `%4s'\n",
4887 GNUNET_i2s (&n->id));
4889 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4891 /* notify all clients about disconnect */
4892 if (GNUNET_YES == n->received_pong)
4894 n->received_pong = GNUNET_NO;
4895 notify_clients_disconnect (&n->id);
4898 ats_modify_problem_state(ats, ATS_MODIFIED);
4900 /* clean up all plugins, cancel connections and pending transmissions */
4901 while (NULL != (rpos = n->plugins))
4903 n->plugins = rpos->next;
4904 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4905 while (rpos->addresses != NULL)
4907 peer_pos = rpos->addresses;
4908 rpos->addresses = peer_pos->next;
4909 if (peer_pos->connected == GNUNET_YES)
4911 GNUNET_STATISTICS_update (stats,
4912 gettext_noop ("# connected addresses"),
4915 peer_pos->connected = GNUNET_NO;
4917 if (GNUNET_YES == peer_pos->validated)
4918 GNUNET_STATISTICS_update (stats,
4919 gettext_noop ("# peer addresses considered valid"),
4922 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4924 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4925 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4927 GNUNET_free(peer_pos->ressources);
4928 peer_pos->ressources = NULL;
4929 GNUNET_free(peer_pos->quality);
4930 peer_pos->ressources = NULL;
4931 GNUNET_free(peer_pos);
4936 /* free all messages on the queue */
4937 while (NULL != (mq = n->messages_head))
4939 GNUNET_STATISTICS_update (stats,
4940 gettext_noop ("# bytes in message queue for other peers"),
4941 - (int64_t) mq->message_buf_size,
4943 GNUNET_STATISTICS_update (stats,
4944 gettext_noop ("# bytes discarded due to disconnect"),
4945 mq->message_buf_size,
4947 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4950 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4952 sizeof(struct GNUNET_PeerIdentity)));
4956 while (NULL != (mq = n->cont_head))
4959 GNUNET_CONTAINER_DLL_remove (n->cont_head,
4962 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4964 sizeof(struct GNUNET_PeerIdentity)));
4968 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4970 GNUNET_SCHEDULER_cancel (n->timeout_task);
4971 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4973 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4975 GNUNET_SCHEDULER_cancel (n->retry_task);
4976 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4978 if (n->piter != NULL)
4980 GNUNET_PEERINFO_iterate_cancel (n->piter);
4981 GNUNET_STATISTICS_update (stats,
4982 gettext_noop ("# outstanding peerinfo iterate requests"),
4988 /* remove n from neighbours list */
4991 while ((npos != NULL) && (npos != n))
4996 GNUNET_assert (npos != NULL);
4998 neighbours = n->next;
5000 nprev->next = n->next;
5002 /* finally, free n itself */
5003 GNUNET_STATISTICS_update (stats,
5004 gettext_noop ("# active neighbours"),
5007 GNUNET_free_non_null (n->pre_connect_message_buffer);
5013 * We have received a PING message from someone. Need to send a PONG message
5014 * in response to the peer by any means necessary.
5017 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
5018 const struct GNUNET_PeerIdentity *peer,
5019 struct Session *session,
5020 const char *sender_address,
5021 uint16_t sender_address_len)
5023 struct TransportPlugin *plugin = cls;
5024 struct SessionHeader *session_header = (struct SessionHeader*) session;
5025 struct TransportPingMessage *ping;
5026 struct TransportPongMessage *pong;
5027 struct NeighbourList *n;
5028 struct ReadyList *rl;
5029 struct ForeignAddressList *fal;
5030 struct OwnAddressList *oal;
5036 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5038 GNUNET_break_op (0);
5039 return GNUNET_SYSERR;
5042 ping = (struct TransportPingMessage *) message;
5043 if (0 != memcmp (&ping->target,
5044 plugin->env.my_identity,
5045 sizeof (struct GNUNET_PeerIdentity)))
5048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5049 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5051 (sender_address != NULL)
5052 ? a2s (plugin->short_name,
5053 (const struct sockaddr *)sender_address,
5056 GNUNET_i2s (&ping->target));
5058 return GNUNET_SYSERR;
5061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5062 "Processing `%s' from `%s'\n",
5064 (sender_address != NULL)
5065 ? a2s (plugin->short_name,
5066 (const struct sockaddr *)sender_address,
5070 GNUNET_STATISTICS_update (stats,
5071 gettext_noop ("# PING messages received"),
5074 addr = (const char*) &ping[1];
5075 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5076 slen = strlen (plugin->short_name) + 1;
5079 /* peer wants to confirm that we have an outbound connection to him */
5080 if (session == NULL)
5082 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5083 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5085 return GNUNET_SYSERR;
5087 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5088 1) it is NULL when we need to have a real value
5089 2) it is documented to be the address of the sender (source-IP), where
5090 what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5094 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5095 a2s (plugin->short_name,
5097 sender_address_len),
5100 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5101 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5102 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5103 pong->purpose.size =
5104 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5106 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5107 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5108 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5109 pong->challenge = ping->challenge;
5110 pong->addrlen = htonl(sender_address_len + slen);
5113 sizeof(struct GNUNET_PeerIdentity));
5117 if ((sender_address!=NULL) && (sender_address_len > 0))
5118 memcpy (&((char*)&pong[1])[slen],
5120 sender_address_len);
5121 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5123 /* create / update cached sig */
5125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5126 "Creating PONG signature to indicate active connection.\n");
5128 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5129 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5130 GNUNET_assert (GNUNET_OK ==
5131 GNUNET_CRYPTO_rsa_sign (my_private_key,
5133 &session_header->pong_signature));
5137 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5139 memcpy (&pong->signature,
5140 &session_header->pong_signature,
5141 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5147 /* peer wants to confirm that this is one of our addresses */
5151 plugin->api->check_address (plugin->api->cls,
5155 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5156 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5157 a2s (plugin->short_name,
5162 oal = plugin->addresses;
5165 if ( (oal->addrlen == alen) &&
5172 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5173 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5174 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5175 pong->purpose.size =
5176 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5178 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5179 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5180 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5181 pong->challenge = ping->challenge;
5182 pong->addrlen = htonl(alen + slen);
5185 sizeof(struct GNUNET_PeerIdentity));
5186 memcpy (&pong[1], plugin->short_name, slen);
5187 memcpy (&((char*)&pong[1])[slen], addr, alen);
5188 if ( (oal != NULL) &&
5189 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5191 /* create / update cached sig */
5193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5194 "Creating PONG signature to indicate ownership.\n");
5196 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5197 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5198 GNUNET_assert (GNUNET_OK ==
5199 GNUNET_CRYPTO_rsa_sign (my_private_key,
5201 &oal->pong_signature));
5202 memcpy (&pong->signature,
5203 &oal->pong_signature,
5204 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5206 else if (oal == NULL)
5208 /* not using cache (typically DV-only) */
5209 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5210 GNUNET_assert (GNUNET_OK ==
5211 GNUNET_CRYPTO_rsa_sign (my_private_key,
5217 /* can used cached version */
5218 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5219 memcpy (&pong->signature,
5220 &oal->pong_signature,
5221 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5224 n = find_neighbour(peer);
5225 GNUNET_assert (n != NULL);
5226 did_pong = GNUNET_NO;
5227 /* first try reliable response transmission */
5231 fal = rl->addresses;
5234 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5237 ntohs (pong->header.size),
5238 TRANSPORT_PONG_PRIORITY,
5239 HELLO_VERIFICATION_TIMEOUT,
5246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5247 "Transmitted PONG to `%s' via reliable mechanism\n",
5250 GNUNET_STATISTICS_update (stats,
5251 gettext_noop ("# PONGs unicast via reliable transport"),
5257 did_pong = GNUNET_YES;
5262 /* no reliable method found, do multicast */
5263 GNUNET_STATISTICS_update (stats,
5264 gettext_noop ("# PONGs multicast to all available addresses"),
5270 fal = rl->addresses;
5273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5274 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5276 a2s (rl->plugin->short_name,
5279 rl->plugin->short_name);
5280 transmit_to_peer(NULL, fal,
5281 TRANSPORT_PONG_PRIORITY,
5282 HELLO_VERIFICATION_TIMEOUT,
5284 ntohs(pong->header.size),
5287 did_pong = GNUNET_YES;
5293 if (GNUNET_YES != did_pong)
5294 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5295 _("Could not send PONG to `%s': no address available\n"),
5302 * Function called by the plugin for each received message. Update
5303 * data volumes, possibly notify plugins about reducing the rate at
5304 * which they read from the socket and generally forward to our
5307 * @param cls the "struct TransportPlugin *" we gave to the plugin
5308 * @param peer (claimed) identity of the other peer
5309 * @param message the message, NULL if we only care about
5310 * learning about the delay until we should receive again
5311 * @param ats_data information for automatic transport selection
5312 * @param ats_count number of elements in ats not including 0-terminator
5313 * @param session identifier used for this session (can be NULL)
5314 * @param sender_address binary address of the sender (if observed)
5315 * @param sender_address_len number of bytes in sender_address
5316 * @return how long in ms the plugin should wait until receiving more data
5317 * (plugins that do not support this, can ignore the return value)
5319 static struct GNUNET_TIME_Relative
5320 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5321 const struct GNUNET_MessageHeader *message,
5322 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5324 struct Session *session,
5325 const char *sender_address,
5326 uint16_t sender_address_len)
5328 struct TransportPlugin *plugin = cls;
5329 struct ReadyList *service_context;
5330 struct ForeignAddressList *peer_address;
5332 struct NeighbourList *n;
5333 struct GNUNET_TIME_Relative ret;
5337 if (0 == memcmp (peer,
5339 sizeof (struct GNUNET_PeerIdentity)))
5341 /* refuse to receive from myself */
5343 return GNUNET_TIME_UNIT_FOREVER_REL;
5345 if (is_blacklisted (peer, plugin))
5346 return GNUNET_TIME_UNIT_FOREVER_REL;
5347 n = find_neighbour (peer);
5349 n = setup_new_neighbour (peer, GNUNET_YES);
5350 service_context = n->plugins;
5351 while ((service_context != NULL) && (plugin != service_context->plugin))
5352 service_context = service_context->next;
5353 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5354 peer_address = NULL;
5357 for (c=0; c<ats_count; c++)
5358 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5359 distance = ntohl(ats_data[c].value);
5362 if (message != NULL)
5364 if ( (session != NULL) ||
5365 (sender_address != NULL) )
5366 peer_address = add_peer_address (n,
5370 sender_address_len);
5371 if (peer_address != NULL)
5373 update_addr_ats(peer_address, ats_data, ats_count);
5374 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5376 peer_address->distance = distance;
5377 if (GNUNET_YES == peer_address->validated)
5379 mark_address_connected (peer_address);
5380 schedule_next_ping (peer_address);
5385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5386 "New address is unvalidated, trying to validate it now\n");
5388 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5390 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5391 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5393 peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5396 peer_address->timeout
5397 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5399 /* update traffic received amount ... */
5400 msize = ntohs (message->size);
5402 GNUNET_STATISTICS_update (stats,
5403 gettext_noop ("# bytes received from other peers"),
5406 n->distance = distance;
5408 GNUNET_TIME_relative_to_absolute
5409 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5410 GNUNET_SCHEDULER_cancel (n->timeout_task);
5412 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5413 &neighbour_timeout_task, n);
5414 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5416 /* dropping message due to frequent inbound volume violations! */
5417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5418 GNUNET_ERROR_TYPE_BULK,
5420 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5421 n->in_tracker.available_bytes_per_s__,
5422 n->quota_violation_count);
5423 GNUNET_STATISTICS_update (stats,
5424 gettext_noop ("# bandwidth quota violations by other peers"),
5427 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5429 if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5430 (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5433 uint32_t value = ntohl(*((uint32_t *) &message[1]));
5434 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5435 /* Force ressource and quality update */
5436 if ((value == 4) && (ats != NULL))
5437 ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5438 /* Force cost update */
5439 if ((value == 3) && (ats != NULL))
5440 ats_modify_problem_state(ats, ATS_COST_UPDATED);
5441 /* Force quality update */
5442 if ((value == 2) && (ats != NULL))
5443 ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5444 /* Force full rebuild */
5445 if ((value == 1) && (ats != NULL))
5446 ats_modify_problem_state(ats, ATS_MODIFIED);
5451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5452 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5453 ntohs (message->type),
5454 ntohs (message->size),
5457 switch (ntohs (message->type))
5459 case GNUNET_MESSAGE_TYPE_HELLO:
5460 GNUNET_STATISTICS_update (stats,
5461 gettext_noop ("# HELLO messages received from other peers"),
5464 process_hello (plugin, message);
5466 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5467 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5468 if (GNUNET_YES != n->received_pong)
5469 transmit_plain_ping (n);
5471 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5472 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5474 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5477 handle_payload_message (message, n);
5481 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5482 if (ret.rel_value > 0)
5485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5486 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5487 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5488 (unsigned int) n->in_tracker.available_bytes_per_s__,
5489 (unsigned long long) ret.rel_value);
5491 GNUNET_STATISTICS_update (stats,
5492 gettext_noop ("# ms throttling suggested"),
5493 (int64_t) ret.rel_value,
5500 * Handle START-message. This is the first message sent to us
5501 * by any client which causes us to add it to our list.
5503 * @param cls closure (always NULL)
5504 * @param client identification of the client
5505 * @param message the actual message
5508 handle_start (void *cls,
5509 struct GNUNET_SERVER_Client *client,
5510 const struct GNUNET_MessageHeader *message)
5512 const struct StartMessage *start;
5513 struct TransportClient *c;
5514 struct ConnectInfoMessage * cim;
5515 struct NeighbourList *n;
5519 start = (const struct StartMessage*) message;
5521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5522 "Received `%s' request from client\n", "START");
5527 if (c->client == client)
5529 /* client already on our list! */
5531 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5536 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5537 (0 != memcmp (&start->self,
5539 sizeof (struct GNUNET_PeerIdentity))) )
5541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5542 _("Rejecting control connection from peer `%s', which is not me!\n"),
5543 GNUNET_i2s (&start->self));
5544 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5547 c = GNUNET_malloc (sizeof (struct TransportClient));
5551 if (our_hello != NULL)
5554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5555 "Sending our own `%s' to new client\n", "HELLO");
5557 transmit_to_client (c,
5558 (const struct GNUNET_MessageHeader *) our_hello,
5560 /* tell new client about all existing connections */
5562 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5563 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5567 cim = GNUNET_malloc (size);
5568 cim->header.size = htons (size);
5569 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5570 cim->ats_count = htonl(ats_count);
5571 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5572 (&(cim->ats))[2].value = htonl (0);
5576 if (GNUNET_YES == n->received_pong)
5578 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5579 (&cim->ats)[0].value = htonl (n->distance);
5580 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5581 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5583 transmit_to_client (c, &cim->header, GNUNET_NO);
5591 #if DEBUG_TRANSPORT_HELLO
5592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5593 "No HELLO created yet, will transmit HELLO to client later!\n");
5597 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5602 * Handle HELLO-message.
5604 * @param cls closure (always NULL)
5605 * @param client identification of the client
5606 * @param message the actual message
5609 handle_hello (void *cls,
5610 struct GNUNET_SERVER_Client *client,
5611 const struct GNUNET_MessageHeader *message)
5615 GNUNET_STATISTICS_update (stats,
5616 gettext_noop ("# HELLOs received from clients"),
5619 ret = process_hello (NULL, message);
5620 GNUNET_SERVER_receive_done (client, ret);
5625 * Closure for 'transmit_client_message'; followed by
5626 * 'msize' bytes of the actual message.
5628 struct TransmitClientMessageContext
5631 * Client on whom's behalf we are sending.
5633 struct GNUNET_SERVER_Client *client;
5636 * Timeout for the transmission.
5638 struct GNUNET_TIME_Absolute timeout;
5646 * Size of the message in bytes.
5653 * Schedule transmission of a message we got from a client to a peer.
5655 * @param cls the 'struct TransmitClientMessageContext*'
5656 * @param n destination, or NULL on error (in that case, drop the message)
5659 transmit_client_message (void *cls,
5660 struct NeighbourList *n)
5662 struct TransmitClientMessageContext *tcmc = cls;
5663 struct TransportClient *tc;
5666 while ((tc != NULL) && (tc->client != tcmc->client))
5671 transmit_to_peer (tc, NULL, tcmc->priority,
5672 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5674 tcmc->msize, GNUNET_NO, n);
5676 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5677 GNUNET_SERVER_client_drop (tcmc->client);
5683 * Handle SEND-message.
5685 * @param cls closure (always NULL)
5686 * @param client identification of the client
5687 * @param message the actual message
5690 handle_send (void *cls,
5691 struct GNUNET_SERVER_Client *client,
5692 const struct GNUNET_MessageHeader *message)
5694 const struct OutboundMessage *obm;
5695 const struct GNUNET_MessageHeader *obmm;
5696 struct TransmitClientMessageContext *tcmc;
5700 size = ntohs (message->size);
5702 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5705 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5708 GNUNET_STATISTICS_update (stats,
5709 gettext_noop ("# payload received for other peers"),
5712 obm = (const struct OutboundMessage *) message;
5713 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5714 msize = size - sizeof (struct OutboundMessage);
5716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5717 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5718 "SEND", GNUNET_i2s (&obm->peer),
5722 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5723 tcmc->client = client;
5724 tcmc->priority = ntohl (obm->priority);
5725 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5726 tcmc->msize = msize;
5727 /* FIXME: this memcpy can be up to 7% of our total runtime */
5728 memcpy (&tcmc[1], obmm, msize);
5729 GNUNET_SERVER_client_keep (client);
5730 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5731 &transmit_client_message,
5737 * Handle request connect message
5739 * @param cls closure (always NULL)
5740 * @param client identification of the client
5741 * @param message the actual message
5744 handle_request_connect (void *cls,
5745 struct GNUNET_SERVER_Client *client,
5746 const struct GNUNET_MessageHeader *message)
5748 const struct TransportRequestConnectMessage *trcm =
5749 (const struct TransportRequestConnectMessage *) message;
5751 GNUNET_STATISTICS_update (stats,
5752 gettext_noop ("# REQUEST CONNECT messages received"),
5756 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
5757 "Received a request connect message for peer `%s'\n",
5758 GNUNET_i2s(&trcm->peer));
5760 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5762 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5767 * Handle SET_QUOTA-message.
5769 * @param cls closure (always NULL)
5770 * @param client identification of the client
5771 * @param message the actual message
5774 handle_set_quota (void *cls,
5775 struct GNUNET_SERVER_Client *client,
5776 const struct GNUNET_MessageHeader *message)
5778 const struct QuotaSetMessage *qsm =
5779 (const struct QuotaSetMessage *) message;
5780 struct NeighbourList *n;
5782 GNUNET_STATISTICS_update (stats,
5783 gettext_noop ("# SET QUOTA messages received"),
5786 n = find_neighbour (&qsm->peer);
5789 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5790 GNUNET_STATISTICS_update (stats,
5791 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5798 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5800 (unsigned int) ntohl (qsm->quota.value__),
5801 (unsigned int) n->in_tracker.available_bytes_per_s__,
5802 GNUNET_i2s (&qsm->peer));
5804 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5806 if (0 == ntohl (qsm->quota.value__))
5809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5810 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5813 GNUNET_STATISTICS_update (stats,
5814 gettext_noop ("# disconnects due to quota of 0"),
5817 disconnect_neighbour (n, GNUNET_NO);
5819 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5824 * Take the given address and append it to the set of results sent back to
5827 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5828 * @param address the resolved name, NULL to indicate the last response
5831 transmit_address_to_client (void *cls, const char *address)
5833 struct GNUNET_SERVER_TransmitContext *tc = cls;
5836 if (NULL != address)
5838 slen = strlen (address) + 1;
5839 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5840 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5844 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5850 * Handle AddressLookup-message.
5852 * @param cls closure (always NULL)
5853 * @param client identification of the client
5854 * @param message the actual message
5857 handle_address_lookup (void *cls,
5858 struct GNUNET_SERVER_Client *client,
5859 const struct GNUNET_MessageHeader *message)
5861 const struct AddressLookupMessage *alum;
5862 struct TransportPlugin *lsPlugin;
5863 const char *nameTransport;
5864 const char *address;
5866 struct GNUNET_SERVER_TransmitContext *tc;
5867 struct GNUNET_TIME_Absolute timeout;
5868 struct GNUNET_TIME_Relative rtimeout;
5871 size = ntohs (message->size);
5872 if (size < sizeof (struct AddressLookupMessage))
5874 GNUNET_break_op (0);
5875 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5878 alum = (const struct AddressLookupMessage *) message;
5879 uint32_t addressLen = ntohl (alum->addrlen);
5880 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5882 GNUNET_break_op (0);
5883 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5886 address = (const char *) &alum[1];
5887 nameTransport = (const char *) &address[addressLen];
5889 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5891 GNUNET_break_op (0);
5892 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5895 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5896 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5897 numeric = ntohl (alum->numeric_only);
5898 lsPlugin = find_transport (nameTransport);
5899 if (NULL == lsPlugin)
5901 tc = GNUNET_SERVER_transmit_context_create (client);
5902 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5903 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5904 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5907 GNUNET_SERVER_disable_receive_done_warning (client);
5908 tc = GNUNET_SERVER_transmit_context_create (client);
5909 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5911 address, addressLen,
5914 &transmit_address_to_client, tc);
5918 * Handle PeerAddressLookupMessage.
5920 * @param cls closure (always NULL)
5921 * @param client identification of the client
5922 * @param message the actual message
5925 handle_peer_address_lookup (void *cls,
5926 struct GNUNET_SERVER_Client *client,
5927 const struct GNUNET_MessageHeader *message)
5929 const struct PeerAddressLookupMessage *peer_address_lookup;
5930 struct NeighbourList *neighbor_iterator;
5931 struct ReadyList *ready_iterator;
5932 struct ForeignAddressList *foreign_address_iterator;
5933 struct TransportPlugin *transport_plugin;
5936 struct GNUNET_SERVER_TransmitContext *tc;
5937 struct GNUNET_TIME_Absolute timeout;
5938 struct GNUNET_TIME_Relative rtimeout;
5941 size = ntohs (message->size);
5942 if (size < sizeof (struct PeerAddressLookupMessage))
5944 GNUNET_break_op (0);
5945 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5948 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5950 timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5951 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5953 neighbor_iterator = neighbours;
5954 while (neighbor_iterator != NULL)
5956 if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5958 neighbor_iterator = neighbor_iterator->next;
5961 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5962 if (neighbor_iterator == NULL)
5965 tc = GNUNET_SERVER_transmit_context_create (client);
5966 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5967 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5968 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5972 ready_iterator = neighbor_iterator->plugins;
5973 GNUNET_SERVER_disable_receive_done_warning (client);
5974 tc = GNUNET_SERVER_transmit_context_create (client);
5975 while(ready_iterator != NULL)
5977 foreign_address_iterator = ready_iterator->addresses;
5978 while (foreign_address_iterator != NULL)
5980 transport_plugin = foreign_address_iterator->ready_list->plugin;
5981 if (foreign_address_iterator->addr != NULL)
5983 GNUNET_asprintf (&addr_buf, "%s --- %s",
5984 a2s (transport_plugin->short_name,
5985 foreign_address_iterator->addr,
5986 foreign_address_iterator->addrlen),
5987 (foreign_address_iterator->connected
5988 == GNUNET_YES) ? "CONNECTED"
5990 (foreign_address_iterator->validated
5991 == GNUNET_YES) ? "VALIDATED"
5993 transmit_address_to_client(tc, addr_buf);
5994 GNUNET_free(addr_buf);
5996 else if (foreign_address_iterator->addrlen == 0)
5998 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5999 (foreign_address_iterator->connected
6000 == GNUNET_YES) ? "CONNECTED"
6002 (foreign_address_iterator->validated
6003 == GNUNET_YES) ? "VALIDATED"
6005 transmit_address_to_client (tc, addr_buf);
6006 GNUNET_free(addr_buf);
6009 foreign_address_iterator = foreign_address_iterator->next;
6011 ready_iterator = ready_iterator->next;
6013 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6014 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6015 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6019 * Handle AddressIterateMessage
6021 * @param cls closure (always NULL)
6022 * @param client identification of the client
6023 * @param message the actual message
6026 handle_address_iterate (void *cls,
6027 struct GNUNET_SERVER_Client *client,
6028 const struct GNUNET_MessageHeader *message)
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;
6039 size = ntohs (message->size);
6040 if (size < sizeof (struct AddressIterateMessage))
6042 GNUNET_break_op (0);
6043 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
6046 GNUNET_SERVER_disable_receive_done_warning (client);
6047 tc = GNUNET_SERVER_transmit_context_create (client);
6049 neighbor_iterator = neighbours;
6050 while (neighbor_iterator != NULL)
6052 ready_iterator = neighbor_iterator->plugins;
6053 while (ready_iterator != NULL)
6055 foreign_address_iterator = ready_iterator->addresses;
6056 while (foreign_address_iterator != NULL)
6058 transport_plugin = foreign_address_iterator->ready_list->plugin;
6059 if (foreign_address_iterator->addr != NULL)
6061 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6062 GNUNET_i2s(&neighbor_iterator->id),
6063 a2s (transport_plugin->short_name,
6064 foreign_address_iterator->addr,
6065 foreign_address_iterator->addrlen),
6066 (foreign_address_iterator->connected
6067 == GNUNET_YES) ? "CONNECTED"
6069 (foreign_address_iterator->validated
6070 == GNUNET_YES) ? "VALIDATED"
6072 transmit_address_to_client (tc, addr_buf);
6073 GNUNET_free(addr_buf);
6075 else if (foreign_address_iterator->addrlen == 0)
6077 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
6078 GNUNET_i2s (&neighbor_iterator->id),
6080 (foreign_address_iterator->connected
6081 == GNUNET_YES) ? "CONNECTED"
6083 (foreign_address_iterator->validated
6084 == GNUNET_YES) ? "VALIDATED"
6086 transmit_address_to_client (tc, addr_buf);
6087 GNUNET_free(addr_buf);
6090 foreign_address_iterator = foreign_address_iterator->next;
6092 ready_iterator = ready_iterator->next;
6094 neighbor_iterator = neighbor_iterator->next;
6097 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6098 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6099 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6104 * Setup the environment for this plugin.
6107 create_environment (struct TransportPlugin *plug)
6109 plug->env.cfg = cfg;
6110 plug->env.my_identity = &my_identity;
6111 plug->env.our_hello = &our_hello;
6112 plug->env.cls = plug;
6113 plug->env.receive = &plugin_env_receive;
6114 plug->env.notify_address = &plugin_env_notify_address;
6115 plug->env.session_end = &plugin_env_session_end;
6116 plug->env.max_connections = max_connect_per_transport;
6117 plug->env.stats = stats;
6122 * Start the specified transport (load the plugin).
6125 start_transport (struct GNUNET_SERVER_Handle *server,
6128 struct TransportPlugin *plug;
6131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6132 _("Loading `%s' transport plugin\n"), name);
6133 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6134 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6135 create_environment (plug);
6136 plug->short_name = GNUNET_strdup (name);
6137 plug->lib_name = libname;
6138 plug->next = plugins;
6140 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6141 if (plug->api == NULL)
6143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6144 _("Failed to load transport plugin for `%s'\n"), name);
6145 GNUNET_free (plug->short_name);
6146 plugins = plug->next;
6147 GNUNET_free (libname);
6154 * Called whenever a client is disconnected. Frees our
6155 * resources associated with that client.
6157 * @param cls closure
6158 * @param client identification of the client
6161 client_disconnect_notification (void *cls,
6162 struct GNUNET_SERVER_Client *client)
6164 struct TransportClient *pos;
6165 struct TransportClient *prev;
6166 struct ClientMessageQueueEntry *mqe;
6167 struct Blacklisters *bl;
6168 struct BlacklistCheck *bc;
6169 struct NeighbourList *n;
6170 struct MessageQueue *mq;
6175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6176 "Client disconnected, cleaning up.\n");
6178 /* clean up blacklister */
6182 if (bl->client == client)
6187 if (bc->bl_pos == bl)
6189 bc->bl_pos = bl->next;
6192 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6195 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6196 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6202 GNUNET_CONTAINER_DLL_remove (bl_head,
6205 GNUNET_SERVER_client_drop (bl->client);
6211 /* clean up 'normal' clients */
6214 while ((pos != NULL) && (pos->client != client))
6221 while (NULL != (mqe = pos->message_queue_head))
6223 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6224 pos->message_queue_tail,
6226 pos->message_count--;
6229 for (n = neighbours; n != NULL; n = n->next)
6231 for (mq = n->messages_head; mq != NULL; mq = mq->next)
6233 if (mq->client == pos)
6234 mq->client = NULL; /* do not use anymore! */
6238 clients = pos->next;
6240 prev->next = pos->next;
6241 if (GNUNET_YES == pos->tcs_pending)
6246 if (pos->th != NULL)
6248 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6251 GNUNET_break (0 == pos->message_count);
6257 * Function called when the service shuts down. Unloads our plugins
6258 * and cancels pending validations.
6260 * @param cls closure, unused
6261 * @param tc task context (unused)
6264 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6266 struct TransportPlugin *plug;
6267 struct OwnAddressList *al;
6268 struct CheckHelloValidatedContext *chvc;
6270 shutdown_in_progress = GNUNET_YES;
6271 while (neighbours != NULL)
6274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6275 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6278 disconnect_neighbour (neighbours, GNUNET_NO);
6281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6282 "Transport service is unloading plugins...\n");
6284 while (NULL != (plug = plugins))
6286 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6288 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6289 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6291 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6292 GNUNET_free (plug->lib_name);
6293 GNUNET_free (plug->short_name);
6294 while (NULL != (al = plug->addresses))
6296 plug->addresses = al->next;
6299 plugins = plug->next;
6302 if (my_private_key != NULL)
6303 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6304 GNUNET_free_non_null (our_hello);
6306 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6309 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6310 validation_map = NULL;
6313 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6315 GNUNET_SCHEDULER_cancel(ats_task);
6316 ats_task = GNUNET_SCHEDULER_NO_TASK;
6323 /* free 'chvc' data structure */
6324 while (NULL != (chvc = chvc_head))
6326 chvc_head = chvc->next;
6327 if (chvc->piter != NULL)
6329 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6330 GNUNET_STATISTICS_update (stats,
6331 gettext_noop ("# outstanding peerinfo iterate requests"),
6338 GNUNET_assert (chvc->ve_count == 0);
6345 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6348 if (peerinfo != NULL)
6350 GNUNET_PEERINFO_disconnect (peerinfo);
6353 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6355 GNUNET_SCHEDULER_cancel (hello_task);
6356 hello_task = GNUNET_SCHEDULER_NO_TASK;
6358 /* Can we assume those are gone by now, or do we need to clean up
6360 GNUNET_break (bl_head == NULL);
6361 GNUNET_break (bc_head == NULL);
6365 void ats_result_cb ()
6367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6368 "ATS Result callback\n");
6373 create_ats_information ( struct ATS_peer **p,
6375 struct ATS_mechanism ** m,
6379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6380 "ATS requires clean address information\n");
6382 struct ATS_mechanism * mechanisms;
6383 struct ATS_peer *peers;
6386 struct NeighbourList *next = neighbours;
6390 int found_addresses = GNUNET_NO;
6391 struct ReadyList *r_next = next->plugins;
6392 while (r_next != NULL)
6394 struct ForeignAddressList * a_next = r_next->addresses;
6395 while (a_next != NULL)
6398 found_addresses = GNUNET_YES;
6399 a_next = a_next->next;
6401 r_next = r_next->next;
6403 if (found_addresses) c_peers++;
6408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6409 "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6412 if ((c_peers == 0) && (c_mechs == 0))
6421 mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6422 peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6430 int found_addresses = GNUNET_NO;
6431 struct ReadyList *r_next = next->plugins;
6432 while (r_next != NULL)
6434 struct ForeignAddressList * a_next = r_next->addresses;
6435 while (a_next != NULL)
6437 if (found_addresses == GNUNET_NO)
6439 peers[c_peers].peer = next->id;
6440 peers[c_peers].m_head = NULL;
6441 peers[c_peers].m_tail = NULL;
6442 peers[c_peers].f = 1.0 / c_mechs;
6444 mechanisms[c_mechs].addr = a_next;
6445 mechanisms[c_mechs].col_index = c_mechs;
6446 mechanisms[c_mechs].peer = &peers[c_peers];
6447 mechanisms[c_mechs].next = NULL;
6448 mechanisms[c_mechs].plugin = r_next->plugin;
6449 mechanisms[c_mechs].ressources = a_next->ressources;
6450 mechanisms[c_mechs].quality = a_next->quality;
6451 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6452 peers[c_peers].m_tail,
6453 &mechanisms[c_mechs]);
6454 found_addresses = GNUNET_YES;
6456 a_next = a_next->next;
6458 r_next = r_next->next;
6460 if (found_addresses == GNUNET_YES)
6474 schedule_ats (void *cls,
6475 const struct GNUNET_SCHEDULER_TaskContext *tc)
6477 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6481 ats_task = GNUNET_SCHEDULER_NO_TASK;
6482 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6485 if (shutdown_in_progress == GNUNET_YES)
6488 struct GNUNET_TIME_Relative delta =
6489 GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6490 if (delta.rel_value < ats_minimum_interval.rel_value)
6493 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6494 "Minimum time between cycles not reached\n");
6500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6503 ats_calculate_bandwidth_distribution (ats);
6505 last_ats_execution = GNUNET_TIME_absolute_get();
6507 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6508 &schedule_ats, ats);
6511 struct ForeignAddressList * get_preferred_ats_address (
6512 struct NeighbourList *n)
6514 // TODO get ATS prefered address
6515 return find_ready_address(n);
6519 * Initiate transport service.
6521 * @param cls closure
6522 * @param server the initialized server
6523 * @param c configuration to use
6527 struct GNUNET_SERVER_Handle *server,
6528 const struct GNUNET_CONFIGURATION_Handle *c)
6530 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6531 {&handle_start, NULL,
6532 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6533 {&handle_hello, NULL,
6534 GNUNET_MESSAGE_TYPE_HELLO, 0},
6535 {&handle_send, NULL,
6536 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6537 {&handle_request_connect, NULL,
6538 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6539 {&handle_set_quota, NULL,
6540 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6541 {&handle_address_lookup, NULL,
6542 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6544 {&handle_peer_address_lookup, NULL,
6545 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6547 {&handle_address_iterate, NULL,
6548 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6550 {&handle_blacklist_init, NULL,
6551 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6552 {&handle_blacklist_reply, NULL,
6553 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6559 unsigned long long tneigh;
6562 shutdown_in_progress = GNUNET_NO;
6564 stats = GNUNET_STATISTICS_create ("transport", cfg);
6565 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6566 /* parse configuration */
6568 GNUNET_CONFIGURATION_get_value_number (c,
6573 GNUNET_CONFIGURATION_get_value_filename (c,
6575 "HOSTKEY", &keyfile)))
6577 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6579 ("Transport service is lacking key configuration settings. Exiting.\n"));
6580 GNUNET_SCHEDULER_shutdown ();
6583 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6586 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6587 validation_map = NULL;
6591 max_connect_per_transport = (uint32_t) tneigh;
6592 peerinfo = GNUNET_PEERINFO_connect (cfg);
6593 if (peerinfo == NULL)
6595 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6596 _("Could not access PEERINFO service. Exiting.\n"));
6597 GNUNET_SCHEDULER_shutdown ();
6600 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6603 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6604 validation_map = NULL;
6605 GNUNET_free (keyfile);
6608 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6609 GNUNET_free (keyfile);
6610 if (my_private_key == NULL)
6612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6614 ("Transport service could not access hostkey. Exiting.\n"));
6615 GNUNET_SCHEDULER_shutdown ();
6618 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6621 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6622 validation_map = NULL;
6625 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6626 GNUNET_CRYPTO_hash (&my_public_key,
6627 sizeof (my_public_key), &my_identity.hashPubKey);
6628 /* setup notification */
6629 GNUNET_SERVER_disconnect_notify (server,
6630 &client_disconnect_notification, NULL);
6631 /* load plugins... */
6634 GNUNET_CONFIGURATION_get_value_string (c,
6635 "TRANSPORT", "PLUGINS", &plugs))
6637 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6638 _("Starting transport plugins `%s'\n"), plugs);
6639 pos = strtok (plugs, " ");
6642 start_transport (server, pos);
6644 pos = strtok (NULL, " ");
6646 GNUNET_free (plugs);
6648 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6649 &shutdown_task, NULL);
6653 /* Initializing ATS */
6656 unsigned long long value;
6661 int v_b_min = 64000;
6665 ats_minimum_interval = ATS_MIN_INTERVAL;
6666 ats_regular_interval = ATS_EXEC_INTERVAL;
6668 /* loading cost ressources */
6669 for (co=0; co<available_ressources; co++)
6671 GNUNET_asprintf(§ion,"%s_UP",ressources[co].cfg_param);
6672 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6674 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6680 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6681 "Found ressource cost: [%s] = %llu\n",
6684 ressources[co].c_max = value;
6687 GNUNET_free (section);
6688 GNUNET_asprintf(§ion,"%s_DOWN",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_min = value;
6704 GNUNET_free (section);
6707 ats = ats_init (D, U, R, v_b_min, v_n_min,
6708 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6709 create_ats_information,
6713 int log_problem = GNUNET_NO;
6714 int log_solution = GNUNET_NO;
6715 int overwrite_dump = GNUNET_NO;
6716 int minimum_peers = 0;
6717 int minimum_addresses = 0;
6719 log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6722 log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6725 overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6729 GNUNET_CONFIGURATION_get_value_number(cfg,
6733 minimum_peers = (int) value;
6735 GNUNET_CONFIGURATION_get_value_number(cfg,
6739 minimum_addresses = (int) value;
6740 GNUNET_break (GNUNET_OK ==
6741 GNUNET_CONFIGURATION_get_value_time (cfg,
6743 "ATS_EXEC_INTERVAL",
6744 &ats_regular_interval));
6745 GNUNET_break (GNUNET_OK ==
6746 GNUNET_CONFIGURATION_get_value_time (cfg,
6749 &ats_minimum_interval));
6751 ats_set_logging_options (ats,
6760 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6766 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6767 _("Transport service ready.\n"));
6769 /* If we have a blacklist file, read from it */
6770 read_blacklist_file(cfg);
6771 /* process client requests */
6772 GNUNET_SERVER_add_handlers (server, handlers);
6777 * The main function for the transport service.
6779 * @param argc number of arguments from the command line
6780 * @param argv command line arguments
6781 * @return 0 ok, 1 on error
6784 main (int argc, char *const *argv)
6786 a2s (NULL, NULL, 0); /* make compiler happy */
6787 return (GNUNET_OK ==
6788 GNUNET_SERVICE_run (argc,
6791 GNUNET_SERVICE_OPTION_NONE,
6792 &run, NULL)) ? 0 : 1;
6795 /* end of gnunet-service-transport.c */