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 NeighbourMapEntry;
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 NeighbourMapEntry *neighbour;
442 * Entry in neighbours.
444 struct NeighbourMapEntry
448 * Which of our transports is connected to this peer
449 * and what is their status?
451 struct ReadyList *plugins;
454 * Head of list of messages we would like to send to this peer;
455 * must contain at most one message per client.
457 struct MessageQueue *messages_head;
460 * Tail of list of messages we would like to send to this peer; must
461 * contain at most one message per client.
463 struct MessageQueue *messages_tail;
466 * Head of list of messages of messages we expected the continuation
467 * to be called to destroy the message
469 struct MessageQueue *cont_head;
472 * Tail of list of messages of messages we expected the continuation
473 * to be called to destroy the message
475 struct MessageQueue *cont_tail;
478 * Buffer for at most one payload message used when we receive
479 * payload data before our PING-PONG has succeeded. We then
480 * store such messages in this intermediary buffer until the
481 * connection is fully up.
483 struct GNUNET_MessageHeader *pre_connect_message_buffer;
486 * Context for peerinfo iteration.
487 * NULL after we are done processing peerinfo's information.
489 struct GNUNET_PEERINFO_IteratorContext *piter;
492 * Public key for this peer. Valid only if the respective flag is set below.
494 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
497 * Identity of this neighbour.
499 struct GNUNET_PeerIdentity id;
502 * ID of task scheduled to run when this peer is about to
503 * time out (will free resources associated with the peer).
505 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
508 * ID of task scheduled to run when we should retry transmitting
509 * the head of the message queue. Actually triggered when the
510 * transmission is timing out (we trigger instantly when we have
511 * a chance of success).
513 GNUNET_SCHEDULER_TaskIdentifier retry_task;
516 * How long until we should consider this peer dead
517 * (if we don't receive another message in the
520 struct GNUNET_TIME_Absolute peer_timeout;
523 * Tracker for inbound bandwidth.
525 struct GNUNET_BANDWIDTH_Tracker in_tracker;
528 * The latency we have seen for this particular address for
529 * this particular peer. This latency may have been calculated
530 * over multiple transports. This value reflects how long it took
531 * us to receive a response when SENDING via this particular
532 * transport/neighbour/address combination!
534 * FIXME: we need to periodically send PINGs to update this
535 * latency (at least more often than the current "huge" (11h?)
538 struct GNUNET_TIME_Relative latency;
541 * How often has the other peer (recently) violated the
542 * inbound traffic limit? Incremented by 10 per violation,
543 * decremented by 1 per non-violation (for each
546 unsigned int quota_violation_count;
549 * DV distance to this peer (1 if no DV is used).
554 * Have we seen an PONG from this neighbour in the past (and
555 * not had a disconnect since)?
560 * Do we have a valid public key for this neighbour?
562 int public_key_valid;
565 * Are we already in the process of disconnecting this neighbour?
570 * Performance data for the peer.
572 struct GNUNET_TRANSPORT_ATS_Information *ats;
576 * Message used to ask a peer to validate receipt (to check an address
577 * from a HELLO). Followed by the address we are trying to validate,
578 * or an empty address if we are just sending a PING to confirm that a
579 * connection which the receiver (of the PING) initiated is still valid.
581 struct TransportPingMessage
585 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
587 struct GNUNET_MessageHeader header;
590 * Challenge code (to ensure fresh reply).
592 uint32_t challenge GNUNET_PACKED;
595 * Who is the intended recipient?
597 struct GNUNET_PeerIdentity target;
603 * Message used to validate a HELLO. The challenge is included in the
604 * confirmation to make matching of replies to requests possible. The
605 * signature signs our public key, an expiration time and our address.<p>
607 * This message is followed by our transport address that the PING tried
608 * to confirm (if we liked it). The address can be empty (zero bytes)
609 * if the PING had not address either (and we received the request via
610 * a connection that we initiated).
612 struct TransportPongMessage
616 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
618 struct GNUNET_MessageHeader header;
621 * Challenge code from PING (showing freshness). Not part of what
622 * is signed so that we can re-use signatures.
624 uint32_t challenge GNUNET_PACKED;
629 struct GNUNET_CRYPTO_RsaSignature signature;
632 * What are we signing and why? Two possible reason codes can be here:
633 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
634 * plausible address for this peer (pid is set to identity of signer); or
635 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
636 * an address we used to connect to the peer with the given pid.
638 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
641 * When does this signature expire?
643 struct GNUNET_TIME_AbsoluteNBO expiration;
646 * Either the identity of the peer Who signed this message, or the
647 * identity of the peer that we're connected to using the given
648 * address (depending on purpose.type).
650 struct GNUNET_PeerIdentity pid;
653 * Size of address appended to this message (part of what is
654 * being signed, hence not redundant).
662 * Linked list of messages to be transmitted to the client. Each
663 * entry is followed by the actual message.
665 struct ClientMessageQueueEntry
668 * This is a doubly-linked list.
670 struct ClientMessageQueueEntry *next;
673 * This is a doubly-linked list.
675 struct ClientMessageQueueEntry *prev;
680 * Client connected to the transport service.
682 struct TransportClient
686 * This is a linked list.
688 struct TransportClient *next;
691 * Handle to the client.
693 struct GNUNET_SERVER_Client *client;
696 * Linked list of messages yet to be transmitted to
699 struct ClientMessageQueueEntry *message_queue_head;
702 * Tail of linked list of messages yet to be transmitted to the
705 struct ClientMessageQueueEntry *message_queue_tail;
708 * Current transmit request handle.
710 struct GNUNET_CONNECTION_TransmitHandle *th;
713 * Is a call to "transmit_send_continuation" pending? If so, we
714 * must not free this struct (even if the corresponding client
715 * disconnects) and instead only remove it from the linked list and
716 * set the "client" field to NULL.
721 * Length of the list of messages pending for this client.
723 unsigned int message_count;
729 * Context of currently active requests to peerinfo
730 * for validation of HELLOs.
732 struct CheckHelloValidatedContext;
736 * Entry in map of all HELLOs awaiting validation.
738 struct ValidationEntry
742 * NULL if this entry is not part of a larger HELLO validation.
744 struct CheckHelloValidatedContext *chvc;
747 * The address, actually a pointer to the end
748 * of this struct. Do not free!
753 * Name of the transport.
755 char *transport_name;
758 * The public key of the peer.
760 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
763 * ID of task that will clean up this entry if we don't succeed
764 * with the validation first.
766 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
769 * At what time did we send this validation?
771 struct GNUNET_TIME_Absolute send_time;
774 * Session being validated (or NULL for none).
776 struct Session *session;
779 * Challenge number we used.
792 * Context of currently active requests to peerinfo
793 * for validation of HELLOs.
795 struct CheckHelloValidatedContext
799 * This is a doubly-linked list.
801 struct CheckHelloValidatedContext *next;
804 * This is a doubly-linked list.
806 struct CheckHelloValidatedContext *prev;
809 * Hello that we are validating.
811 const struct GNUNET_HELLO_Message *hello;
814 * Context for peerinfo iteration.
815 * NULL after we are done processing peerinfo's information.
817 struct GNUNET_PEERINFO_IteratorContext *piter;
820 * Was a HELLO known for this peer to peerinfo?
825 * Number of validation entries currently referring to this
828 unsigned int ve_count;
833 * All zero hash for comparison.
835 static GNUNET_HashCode null_hash;
840 static struct GNUNET_HELLO_Message *our_hello;
845 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
850 static struct GNUNET_PeerIdentity my_identity;
855 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
860 const struct GNUNET_CONFIGURATION_Handle *cfg;
863 * Linked list of all clients to this service.
865 static struct TransportClient *clients;
868 * All loaded plugins.
870 static struct TransportPlugin *plugins;
873 * Handle to peerinfo service.
875 static struct GNUNET_PEERINFO_Handle *peerinfo;
878 * All known neighbours and their HELLOs.
880 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
883 * Number of neighbours we'd like to have.
885 static uint32_t max_connect_per_transport;
888 * Head of linked list.
890 static struct CheckHelloValidatedContext *chvc_head;
893 * Tail of linked list.
895 static struct CheckHelloValidatedContext *chvc_tail;
898 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
899 * of the given peer that we are currently validating).
901 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
904 * Handle for reporting statistics.
906 static struct GNUNET_STATISTICS_Handle *stats;
909 * Identifier of 'refresh_hello' task.
911 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
914 * Identifier of ats scheduler task.
916 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
919 * Is transport service shutting down ?
921 static int shutdown_in_progress;
924 * Handle for ats information
926 static struct ATS_Handle *ats;
929 * Time of last ats execution
931 struct GNUNET_TIME_Absolute last_ats_execution;
934 * Minimum interval between two ATS executions
936 struct GNUNET_TIME_Relative ats_minimum_interval;
939 * Regular interval when ATS execution is triggered
941 struct GNUNET_TIME_Relative ats_regular_interval;
944 * The peer specified by the given neighbour has timed-out or a plugin
945 * has disconnected. We may either need to do nothing (other plugins
946 * still up), or trigger a full disconnect and clean up. This
947 * function updates our state and do the necessary notifications.
948 * Also notifies our clients that the neighbour is now officially
951 * @param n the neighbour list entry for the peer
952 * @param check should we just check if all plugins
953 * disconnected or must we ask all plugins to
956 static void disconnect_neighbour (struct NeighbourMapEntry *n, int check);
959 * Check the ready list for the given neighbour and if a plugin is
960 * ready for transmission (and if we have a message), do so!
962 * @param nexi target peer for which to transmit
964 static void try_transmission_to_peer (struct NeighbourMapEntry *n);
966 struct ForeignAddressList *get_preferred_ats_address (struct NeighbourMapEntry
970 * Find an entry in the neighbour list for a particular peer.
972 * @return NULL if not found.
974 static struct NeighbourMapEntry *
975 find_neighbour (const struct GNUNET_PeerIdentity *key)
977 return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
981 update_addr_value (struct ForeignAddressList *fal, uint32_t value,
987 for (c = 0; c < available_quality_metrics; c++)
989 if (ats_index == qm[c].atis_index)
991 fal->quality[c].values[0] = fal->quality[c].values[1];
992 fal->quality[c].values[1] = fal->quality[c].values[2];
993 fal->quality[c].values[2] = value;
996 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1000 if (set == GNUNET_NO)
1002 for (c = 0; c < available_ressources; c++)
1004 if (ats_index == ressources[c].atis_index)
1006 fal->ressources[c].c = value;
1009 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1018 update_addr_ats (struct ForeignAddressList *fal,
1019 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1025 for (c1 = 0; c1 < ats_count; c1++)
1028 update_addr_value (fal, ntohl (ats_data[c1].value),
1029 ntohl (ats_data[c1].type));
1035 * Find an entry in the transport list for a particular transport.
1037 * @return NULL if not found.
1039 static struct TransportPlugin *
1040 find_transport (const char *short_name)
1042 struct TransportPlugin *head = plugins;
1044 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1050 * Is a particular peer blacklisted for a particular transport?
1052 * @param peer the peer to check for
1053 * @param plugin the plugin used to connect to the peer
1055 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1058 is_blacklisted (const struct GNUNET_PeerIdentity *peer,
1059 struct TransportPlugin *plugin)
1062 if (plugin->blacklist != NULL)
1064 if (GNUNET_CONTAINER_multihashmap_contains
1065 (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1069 "Peer `%s:%s' is blacklisted!\n",
1070 plugin->short_name, GNUNET_i2s (peer));
1073 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1,
1084 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1086 struct TransportPlugin *plugin;
1088 plugin = find_transport (transport_name);
1089 if (plugin == NULL) /* Nothing to do */
1092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1093 "Adding peer `%s' with plugin `%s' to blacklist\n",
1094 GNUNET_i2s (peer), transport_name);
1096 if (plugin->blacklist == NULL)
1098 GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE);
1099 GNUNET_assert (plugin->blacklist != NULL);
1100 GNUNET_CONTAINER_multihashmap_put (plugin->blacklist, &peer->hashPubKey,
1102 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1107 * Read the blacklist file, containing transport:peer entries.
1108 * Provided the transport is loaded, set up hashmap with these
1109 * entries to blacklist peers by transport.
1113 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1120 struct GNUNET_PeerIdentity pid;
1122 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1123 unsigned int entries_found;
1124 char *transport_name;
1127 GNUNET_CONFIGURATION_get_value_filename (cfg,
1129 "BLACKLIST_FILE", &fn))
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Option `%s' in section `%s' not specified!\n",
1134 "BLACKLIST_FILE", "TRANSPORT");
1138 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1139 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1140 | GNUNET_DISK_PERM_USER_WRITE);
1141 if (0 != STAT (fn, &frstat))
1143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144 _("Could not read blacklist file `%s'\n"), fn);
1148 if (frstat.st_size == 0)
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 _("Blacklist file `%s' is empty.\n"), fn);
1157 /* FIXME: use mmap */
1158 data = GNUNET_malloc_large (frstat.st_size);
1159 GNUNET_assert (data != NULL);
1160 if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163 _("Failed to read blacklist from `%s'\n"), fn);
1170 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1172 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1174 frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1177 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') &&
1178 !isspace ((unsigned char) data[colon_pos]))
1181 if (colon_pos >= frstat.st_size)
1183 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,
1196 ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1197 (unsigned long long) colon_pos);
1199 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1203 tsize = colon_pos - pos;
1204 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) ||
1207 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1209 ("Syntax error in blacklist file at offset %llu, giving up!\n"),
1210 (unsigned long long) colon_pos);
1219 transport_name = GNUNET_malloc (tsize + 1);
1220 memcpy (transport_name, &data[pos], tsize);
1221 pos = colon_pos + 1;
1223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224 "Read transport name %s in blacklist file.\n", transport_name);
1226 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1229 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1233 ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1234 (unsigned long long) pos);
1236 while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos])))
1238 GNUNET_free_non_null (transport_name);
1241 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1243 GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1245 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1247 ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1248 (unsigned long long) pos, &enc);
1252 if (0 != memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1255 add_peer_to_blacklist (&pid, transport_name);
1259 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1260 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1264 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1265 GNUNET_free_non_null (transport_name);
1266 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1269 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted",
1270 entries_found, GNUNET_NO);
1277 * Function called to notify a client about the socket being ready to
1278 * queue more data. "buf" will be NULL and "size" zero if the socket
1279 * was closed for writing in the meantime.
1281 * @param cls closure
1282 * @param size number of bytes available in buf
1283 * @param buf where the callee should write the message
1284 * @return number of bytes written to buf
1287 transmit_to_client_callback (void *cls, size_t size, void *buf)
1289 struct TransportClient *client = cls;
1290 struct ClientMessageQueueEntry *q;
1293 const struct GNUNET_MessageHeader *msg;
1300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301 "Transmission to client failed, closing connection.\n");
1303 /* fatal error with client, free message queue! */
1304 while (NULL != (q = client->message_queue_head))
1306 GNUNET_STATISTICS_update (stats,
1308 ("# bytes discarded (could not transmit to client)"),
1309 ntohs (((const struct GNUNET_MessageHeader *)
1310 &q[1])->size), GNUNET_NO);
1311 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1312 client->message_queue_tail, q);
1315 client->message_count = 0;
1320 while (NULL != (q = client->message_queue_head))
1322 msg = (const struct GNUNET_MessageHeader *) &q[1];
1323 msize = ntohs (msg->size);
1324 if (msize + tsize > size)
1327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1328 "Transmitting message of type %u to client.\n",
1331 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1332 client->message_queue_tail, q);
1333 memcpy (&cbuf[tsize], msg, msize);
1336 client->message_count--;
1340 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1341 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1343 GNUNET_TIME_UNIT_FOREVER_REL,
1344 &transmit_to_client_callback,
1346 GNUNET_assert (client->th != NULL);
1353 * Convert an address to a string.
1355 * @param plugin name of the plugin responsible for the address
1356 * @param addr binary address
1357 * @param addr_len number of bytes in addr
1358 * @return NULL on error, otherwise address string
1361 a2s (const char *plugin, const void *addr, uint16_t addr_len)
1363 struct TransportPlugin *p;
1367 p = find_transport (plugin);
1368 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1370 return p->api->address_to_string (NULL, addr, addr_len);
1377 * Iterator to free entries in the validation_map.
1379 * @param cls closure (unused)
1380 * @param key current key code
1381 * @param value value in the hash map (validation to abort)
1382 * @return GNUNET_YES (always)
1385 abort_validation (void *cls, const GNUNET_HashCode * key, void *value)
1387 struct ValidationEntry *va = value;
1389 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1390 GNUNET_SCHEDULER_cancel (va->timeout_task);
1391 GNUNET_free (va->transport_name);
1392 if (va->chvc != NULL)
1394 va->chvc->ve_count--;
1395 if (va->chvc->ve_count == 0)
1397 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, va->chvc);
1398 GNUNET_free (va->chvc);
1408 * HELLO validation cleanup task (validation failed).
1410 * @param cls the 'struct ValidationEntry' that failed
1411 * @param tc scheduler context (unused)
1414 timeout_hello_validation (void *cls,
1415 const struct GNUNET_SCHEDULER_TaskContext *tc)
1417 struct ValidationEntry *va = cls;
1418 struct GNUNET_PeerIdentity pid;
1420 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1421 GNUNET_STATISTICS_update (stats,
1422 gettext_noop ("# address validation timeouts"),
1424 GNUNET_CRYPTO_hash (&va->publicKey,
1426 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1428 GNUNET_break (GNUNET_OK ==
1429 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1430 &pid.hashPubKey, va));
1431 abort_validation (NULL, NULL, va);
1437 * Send the specified message to the specified client. Since multiple
1438 * messages may be pending for the same client at a time, this code
1439 * makes sure that no message is lost.
1441 * @param client client to transmit the message to
1442 * @param msg the message to send
1443 * @param may_drop can this message be dropped if the
1444 * message queue for this client is getting far too large?
1447 transmit_to_client (struct TransportClient *client,
1448 const struct GNUNET_MessageHeader *msg, int may_drop)
1450 struct ClientMessageQueueEntry *q;
1453 /* Client==NULL when GNUNET_SERVER_Client disconnected and was
1454 * freed in client_disconnect_notification
1456 if (client->client == NULL)
1462 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1464 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1466 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1468 ntohs (msg->size), client->message_count, MAX_PENDING);
1469 GNUNET_STATISTICS_update (stats,
1471 ("# messages dropped due to slow client"), 1,
1475 msize = ntohs (msg->size);
1476 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1477 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1478 memcpy (&q[1], msg, msize);
1479 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1480 client->message_queue_tail, q);
1481 client->message_count++;
1482 if (client->th == NULL)
1484 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1486 GNUNET_TIME_UNIT_FOREVER_REL,
1487 &transmit_to_client_callback,
1489 GNUNET_assert (client->th != NULL);
1495 * Transmit a 'SEND_OK' notification to the given client for the
1498 * @param client who to notify
1499 * @param n neighbour to notify about, can be NULL (on failure)
1500 * @param target target of the transmission
1501 * @param result status code for the transmission request
1504 transmit_send_ok (struct TransportClient *client,
1505 struct NeighbourMapEntry *n,
1506 const struct GNUNET_PeerIdentity *target, int result)
1508 struct SendOkMessage send_ok_msg;
1510 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1511 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1512 send_ok_msg.success = htonl (result);
1514 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1516 send_ok_msg.latency =
1517 GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1518 send_ok_msg.peer = *target;
1519 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1524 * Mark the given FAL entry as 'connected' (and hence preferred for
1525 * sending); also mark all others for the same peer as 'not connected'
1526 * (since only one can be preferred).
1528 * @param fal address to set to 'connected'
1530 static void mark_address_connected (struct ForeignAddressList *fal);
1535 * We should re-try transmitting to the given peer,
1536 * hopefully we've learned something in the meantime.
1539 retry_transmission_task (void *cls,
1540 const struct GNUNET_SCHEDULER_TaskContext *tc)
1542 struct NeighbourMapEntry *n = cls;
1544 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1545 try_transmission_to_peer (n);
1550 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1551 * upon "completion" of a send request. This tells the API
1552 * that it is now legal to send another message to the given
1555 * @param cls closure, identifies the entry on the
1556 * message queue that was transmitted and the
1557 * client responsible for queuing the message
1558 * @param target the peer receiving the message
1559 * @param result GNUNET_OK on success, if the transmission
1560 * failed, we should not tell the client to transmit
1564 transmit_send_continuation (void *cls,
1565 const struct GNUNET_PeerIdentity *target,
1568 struct MessageQueue *mq = cls;
1569 struct NeighbourMapEntry *n;
1571 GNUNET_STATISTICS_update (stats,
1572 gettext_noop ("# bytes pending with plugins"),
1573 -(int64_t) mq->message_buf_size, GNUNET_NO);
1574 if (result == GNUNET_OK)
1576 GNUNET_STATISTICS_update (stats,
1578 ("# bytes successfully transmitted by plugins"),
1579 mq->message_buf_size, GNUNET_NO);
1583 GNUNET_STATISTICS_update (stats,
1585 ("# bytes with transmission failure by plugins"),
1586 mq->message_buf_size, GNUNET_NO);
1588 if (mq->specific_address != NULL)
1590 if (result == GNUNET_OK)
1592 mq->specific_address->timeout =
1593 GNUNET_TIME_relative_to_absolute
1594 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1595 if (mq->specific_address->validated == GNUNET_YES)
1596 mark_address_connected (mq->specific_address);
1600 if (mq->specific_address->connected == GNUNET_YES)
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1605 a2s (mq->specific_address->ready_list->plugin->short_name,
1606 mq->specific_address->addr,
1607 mq->specific_address->addrlen));
1609 GNUNET_STATISTICS_update (stats,
1610 gettext_noop ("# connected addresses"),
1612 mq->specific_address->connected = GNUNET_NO;
1615 if (!mq->internal_msg)
1616 mq->specific_address->in_transmit = GNUNET_NO;
1618 n = find_neighbour (&mq->neighbour_id);
1619 if (mq->client != NULL)
1620 transmit_send_ok (mq->client, n, target, result);
1621 GNUNET_assert (n != NULL);
1622 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
1624 if (result == GNUNET_OK)
1625 try_transmission_to_peer (n);
1626 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1627 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, n);
1632 * Check the ready list for the given neighbour and if a plugin is
1633 * ready for transmission (and if we have a message), do so!
1635 * @param neighbour target peer for which to transmit
1638 try_transmission_to_peer (struct NeighbourMapEntry *n)
1640 struct ReadyList *rl;
1641 struct MessageQueue *mq;
1642 struct GNUNET_TIME_Relative timeout;
1646 if (n->messages_head == NULL)
1649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1650 "Transmission queue for `%4s' is empty\n", GNUNET_i2s (&n->id));
1652 return; /* nothing to do */
1655 mq = n->messages_head;
1656 force_address = GNUNET_YES;
1657 if (mq->specific_address == NULL)
1660 mq->specific_address = get_preferred_ats_address (n);
1661 GNUNET_STATISTICS_update (stats,
1663 ("# transport selected peer address freely"), 1,
1665 force_address = GNUNET_NO;
1667 if (mq->specific_address == NULL)
1669 GNUNET_STATISTICS_update (stats,
1671 ("# transport failed to selected peer address"),
1673 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1674 if (timeout.rel_value == 0)
1677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1678 "No destination address available to transmit message of size %u to peer `%4s'\n",
1679 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id));
1681 GNUNET_STATISTICS_update (stats,
1683 ("# bytes in message queue for other peers"),
1684 -(int64_t) mq->message_buf_size, GNUNET_NO);
1685 GNUNET_STATISTICS_update (stats,
1687 ("# bytes discarded (no destination address available)"),
1688 mq->message_buf_size, GNUNET_NO);
1689 if (mq->client != NULL)
1690 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1691 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1693 return; /* nobody ready */
1695 GNUNET_STATISTICS_update (stats,
1697 ("# message delivery deferred (no address)"), 1,
1699 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1700 GNUNET_SCHEDULER_cancel (n->retry_task);
1701 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1702 &retry_transmission_task, n);
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1706 mq->message_buf_size,
1707 GNUNET_i2s (&mq->neighbour_id), timeout.rel_value);
1709 /* FIXME: might want to trigger peerinfo lookup here
1710 * (unless that's already pending...) */
1713 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1714 if (mq->specific_address->connected == GNUNET_NO)
1715 mq->specific_address->connect_attempts++;
1716 rl = mq->specific_address->ready_list;
1717 mq->plugin = rl->plugin;
1718 if (!mq->internal_msg)
1719 mq->specific_address->in_transmit = GNUNET_YES;
1721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1722 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1723 mq->message_buf_size,
1724 GNUNET_i2s (&n->id),
1725 (mq->specific_address->addr != NULL)
1726 ? a2s (mq->plugin->short_name,
1727 mq->specific_address->addr,
1728 mq->specific_address->addrlen)
1729 : "<inbound>", rl->plugin->short_name);
1731 GNUNET_STATISTICS_update (stats,
1733 ("# bytes in message queue for other peers"),
1734 -(int64_t) mq->message_buf_size, GNUNET_NO);
1735 GNUNET_STATISTICS_update (stats,
1736 gettext_noop ("# bytes pending with plugins"),
1737 mq->message_buf_size, GNUNET_NO);
1739 GNUNET_CONTAINER_DLL_insert (n->cont_head, n->cont_tail, mq);
1741 ret = rl->plugin->api->send (rl->plugin->api->cls,
1744 mq->message_buf_size,
1746 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1747 mq->specific_address->session,
1748 mq->specific_address->addr,
1749 mq->specific_address->addrlen,
1750 force_address, &transmit_send_continuation, mq);
1753 /* failure, but 'send' would not call continuation in this case,
1754 * so we need to do it here! */
1755 transmit_send_continuation (mq, &mq->neighbour_id, GNUNET_SYSERR);
1761 * Send the specified message to the specified peer.
1763 * @param client source of the transmission request (can be NULL)
1764 * @param peer_address ForeignAddressList where we should send this message
1765 * @param priority how important is the message
1766 * @param timeout how long do we have to transmit?
1767 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1768 * @param message_buf_size total size of all messages in message_buf
1769 * @param is_internal is this an internal message; these are pre-pended and
1770 * also do not count for plugins being "ready" to transmit
1771 * @param neighbour handle to the neighbour for transmission
1774 transmit_to_peer (struct TransportClient *client,
1775 struct ForeignAddressList *peer_address,
1776 unsigned int priority,
1777 struct GNUNET_TIME_Relative timeout,
1778 const char *message_buf,
1779 size_t message_buf_size,
1780 int is_internal, struct NeighbourMapEntry *neighbour)
1782 struct MessageQueue *mq;
1787 /* check for duplicate submission */
1788 mq = neighbour->messages_head;
1791 if (mq->client == client)
1793 /* client transmitted to same peer twice
1794 * before getting SEND_OK! */
1802 GNUNET_STATISTICS_update (stats,
1804 ("# bytes in message queue for other peers"),
1805 message_buf_size, GNUNET_NO);
1806 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1807 mq->specific_address = peer_address;
1808 mq->client = client;
1809 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1810 memcpy (&mq[1], message_buf, message_buf_size);
1811 mq->message_buf = (const char *) &mq[1];
1812 mq->message_buf_size = message_buf_size;
1813 memcpy (&mq->neighbour_id, &neighbour->id,
1814 sizeof (struct GNUNET_PeerIdentity));
1815 mq->internal_msg = is_internal;
1816 mq->priority = priority;
1817 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1819 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1820 neighbour->messages_tail, mq);
1822 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1823 neighbour->messages_tail,
1824 neighbour->messages_tail, mq);
1825 try_transmission_to_peer (neighbour);
1830 * Send a plain PING (without address or our HELLO) to the given
1831 * foreign address to try to establish a connection (and validate
1832 * that the other peer is really who he claimed he is).
1834 * @param n neighbour to PING
1837 transmit_plain_ping (struct NeighbourMapEntry *n)
1839 struct ValidationEntry *ve;
1840 struct TransportPingMessage ping;
1841 struct ReadyList *rl;
1842 struct TransportPlugin *plugin;
1843 struct ForeignAddressList *fal;
1845 if (!n->public_key_valid)
1847 /* This should not happen since the other peer
1848 * should send us a HELLO prior to sending his
1850 GNUNET_break_op (0);
1851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1852 "Could not transmit plain PING to `%s': public key not known\n",
1853 GNUNET_i2s (&n->id));
1856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1857 "Looking for addresses to transmit plain PING to `%s'\n",
1858 GNUNET_i2s (&n->id));
1859 for (rl = n->plugins; rl != NULL; rl = rl->next)
1861 plugin = rl->plugin;
1862 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1864 if (!fal->connected)
1866 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1867 ve->transport_name = GNUNET_strdup (plugin->short_name);
1868 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1870 ve->send_time = GNUNET_TIME_absolute_get ();
1871 ve->session = fal->session;
1872 memcpy (&ve->publicKey,
1874 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1876 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1877 &timeout_hello_validation, ve);
1878 GNUNET_CONTAINER_multihashmap_put (validation_map, &n->id.hashPubKey, ve,
1879 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1880 ping.header.size = htons (sizeof (struct TransportPingMessage));
1881 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1882 ping.challenge = htonl (ve->challenge);
1883 memcpy (&ping.target, &n->id, sizeof (struct GNUNET_PeerIdentity));
1884 GNUNET_STATISTICS_update (stats,
1886 ("# PING without HELLO messages sent"), 1,
1888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s'\n",
1889 GNUNET_i2s (&n->id));
1890 transmit_to_peer (NULL, fal, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1891 HELLO_VERIFICATION_TIMEOUT, (const char *) &ping,
1892 sizeof (ping), GNUNET_YES, n);
1899 * Mark the given FAL entry as 'connected' (and hence preferred for
1900 * sending); also mark all others for the same peer as 'not connected'
1901 * (since only one can be preferred).
1903 * @param fal address to set to 'connected'
1906 mark_address_connected (struct ForeignAddressList *fal)
1908 struct ForeignAddressList *pos;
1909 struct ForeignAddressList *inbound;
1910 struct ForeignAddressList *outbound;
1912 GNUNET_assert (GNUNET_YES == fal->validated);
1913 if (fal->connected == GNUNET_YES)
1914 return; /* nothing to do */
1918 pos = fal->ready_list->addresses;
1921 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1922 if ((GNUNET_YES == pos->connected) &&
1923 (0 == pos->addrlen) && (0 == fal->addrlen))
1925 if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1930 pos = fal->ready_list->addresses;
1933 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1934 if ((GNUNET_YES == pos->connected) &&
1935 (0 < pos->addrlen) && (0 < fal->addrlen))
1937 if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1943 if (inbound != NULL)
1944 fprintf (stderr, "Peer: %s, have inbound connection.\n",
1945 GNUNET_i2s (&my_identity));
1946 if (outbound != NULL)
1947 fprintf (stderr, "Peer: %s, have outbound connection.\n",
1948 GNUNET_i2s (&my_identity));
1951 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1952 if ((inbound != NULL) && (0 != fal->addrlen) && (1
1954 GNUNET_CRYPTO_hash_xorcmp
1956 ready_list->neighbour->id.
1958 &my_identity.hashPubKey,
1962 fprintf (stderr, "Peer: %s, had inbound connection, ignoring outbound!\n",
1963 GNUNET_i2s (&my_identity));
1967 else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
1969 GNUNET_CRYPTO_hash_xorcmp
1970 (&outbound->ready_list->neighbour->
1972 &my_identity.hashPubKey,
1976 fprintf (stderr, "Peer: %s, have outbound connection, ignoring inbound!\n",
1977 GNUNET_i2s (&my_identity));
1982 pos = fal->ready_list->addresses;
1985 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1989 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1990 a2s (pos->ready_list->plugin->short_name, pos->addr,
1995 "Peer: %s, setting %s connection to disconnected.\n",
1996 GNUNET_i2s (&my_identity),
1997 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
1999 pos->connected = GNUNET_NO;
2000 GNUNET_STATISTICS_update (stats,
2001 gettext_noop ("# connected addresses"), -1,
2006 GNUNET_assert (GNUNET_NO == fal->connected);
2007 fal->connected = GNUNET_YES;
2008 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2014 * Find an address in any of the available transports for
2015 * the given neighbour that would be good for message
2016 * transmission. This is essentially the transport selection
2019 * @param neighbour for whom to select an address
2020 * @return selected address, NULL if we have none
2022 struct ForeignAddressList *
2023 find_ready_address (struct NeighbourMapEntry *neighbour)
2025 struct ReadyList *head = neighbour->plugins;
2026 struct ForeignAddressList *addresses;
2027 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2028 struct ForeignAddressList *best_address;
2030 /* Hack to prefer unix domain sockets */
2031 struct ForeignAddressList *unix_address = NULL;
2033 best_address = NULL;
2034 while (head != NULL)
2036 addresses = head->addresses;
2037 while (addresses != NULL)
2039 if ((addresses->timeout.abs_value < now.abs_value) &&
2040 (addresses->connected == GNUNET_YES))
2043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044 "Marking long-time inactive connection to `%4s' as down.\n",
2045 GNUNET_i2s (&neighbour->id));
2047 GNUNET_STATISTICS_update (stats,
2048 gettext_noop ("# connected addresses"),
2050 addresses->connected = GNUNET_NO;
2052 addresses = addresses->next;
2055 addresses = head->addresses;
2056 while (addresses != NULL)
2059 if (addresses->addr != NULL)
2060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2061 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2062 a2s (head->plugin->short_name,
2064 addresses->addrlen),
2065 GNUNET_i2s (&neighbour->id),
2066 addresses->connected,
2067 addresses->in_transmit,
2068 addresses->validated,
2069 addresses->connect_attempts,
2070 (unsigned long long) addresses->timeout.abs_value,
2071 (unsigned int) addresses->distance);
2073 if (0 == strcmp (head->plugin->short_name, "unix"))
2075 if ((unix_address == NULL) ||
2076 ((unix_address != NULL) &&
2077 (addresses->latency.rel_value < unix_address->latency.rel_value)))
2078 unix_address = addresses;
2080 if (((best_address == NULL) ||
2081 (addresses->connected == GNUNET_YES) ||
2082 (best_address->connected == GNUNET_NO)) &&
2083 (addresses->in_transmit == GNUNET_NO) &&
2084 ((best_address == NULL) ||
2085 (addresses->latency.rel_value < best_address->latency.rel_value)))
2086 best_address = addresses;
2087 /* FIXME: also give lower-latency addresses that are not
2088 * connected a chance some times... */
2089 addresses = addresses->next;
2091 if (unix_address != NULL)
2095 if (unix_address != NULL)
2097 best_address = unix_address;
2099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2100 "Found UNIX address, forced this address\n");
2103 if (best_address != NULL)
2106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2107 "Best address found (`%s') has latency of %llu ms.\n",
2108 (best_address->addrlen > 0)
2109 ? a2s (best_address->ready_list->plugin->short_name,
2111 best_address->addrlen)
2112 : "<inbound>", best_address->latency.rel_value);
2117 GNUNET_STATISTICS_update (stats,
2119 ("# transmission attempts failed (no address)"),
2123 return best_address;
2130 struct GeneratorContext
2132 struct TransportPlugin *plug_pos;
2133 struct OwnAddressList *addr_pos;
2134 struct GNUNET_TIME_Absolute expiration;
2142 address_generator (void *cls, size_t max, void *buf)
2144 struct GeneratorContext *gc = cls;
2147 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2149 gc->plug_pos = gc->plug_pos->next;
2150 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2152 if (NULL == gc->plug_pos)
2157 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2160 gc->addr_pos->addrlen, buf, max);
2161 gc->addr_pos = gc->addr_pos->next;
2168 transmit_our_hello_if_pong (void *cls, const GNUNET_HashCode * key, void *value)
2170 struct NeighbourMapEntry *npos = value;
2172 if (GNUNET_YES != npos->received_pong)
2175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2176 "Transmitting updated `%s' to neighbour `%4s'\n",
2177 "HELLO", GNUNET_i2s (&npos->id));
2179 GNUNET_STATISTICS_update (stats,
2181 ("# transmitted my HELLO to other peers"), 1,
2183 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
2184 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
2191 * Construct our HELLO message from all of the addresses of
2192 * all of the transports.
2195 * @param tc scheduler context
2198 refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2200 struct GNUNET_HELLO_Message *hello;
2201 struct TransportClient *cpos;
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",
2212 GNUNET_HELLO_size (hello));
2214 GNUNET_STATISTICS_update (stats,
2215 gettext_noop ("# refreshed my HELLO"),
2218 while (cpos != NULL)
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting my HELLO to client!\n");
2221 transmit_to_client (cpos,
2222 (const struct GNUNET_MessageHeader *) hello, GNUNET_NO);
2226 GNUNET_free_non_null (our_hello);
2228 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2229 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2230 &transmit_our_hello_if_pong, NULL);
2235 * Schedule task to refresh hello (unless such a
2236 * task exists already).
2241 #if DEBUG_TRANSPORT_HELLO
2242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refresh_hello() called!\n");
2244 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2246 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
2251 * Iterator over hash map entries that NULLs the session of validation
2252 * entries that match the given session.
2254 * @param cls closure (the 'struct Session*' to match against)
2255 * @param key current key code (peer ID, not used)
2256 * @param value value in the hash map ('struct ValidationEntry*')
2257 * @return GNUNET_YES (we should continue to iterate)
2260 remove_session_validations (void *cls, const GNUNET_HashCode * key, void *value)
2262 struct Session *session = cls;
2263 struct ValidationEntry *ve = value;
2265 if (session == ve->session)
2272 * We've been disconnected from the other peer (for some
2273 * connection-oriented transport). Either quickly
2274 * re-establish the connection or signal the disconnect
2277 * Only signal CORE level disconnect if ALL addresses
2278 * for the peer are exhausted.
2280 * @param p overall plugin context
2281 * @param nl neighbour that was disconnected
2284 try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl)
2286 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2287 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "try_fast_reconnect not implemented!\n");
2288 /* Note: the idea here is to hide problems with transports (or
2289 * switching between plugins) from the core to eliminate the need to
2290 * re-negotiate session keys and the like; OTOH, we should tell core
2291 * quickly (much faster than timeout) `if a connection was lost and
2292 * could not be re-established (i.e. other peer went down or is
2293 * unable / refuses to communicate);
2295 * So we should consider:
2296 * 1) ideally: our own willingness / need to connect
2297 * 2) prior failures to connect to this peer (by plugin)
2298 * 3) ideally: reasons why other peer terminated (as far as knowable)
2300 * Most importantly, it must be POSSIBLE for another peer to terminate
2301 * a connection for a while (without us instantly re-establishing it).
2302 * Similarly, if another peer is gone we should quickly notify CORE.
2303 * OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2304 * on the other end), we should reconnect in such a way that BOTH CORE
2305 * services never even notice.
2306 * Furthermore, the same mechanism (or small variation) could be used
2307 * to switch to a better-performing plugin (ATS).
2309 * Finally, this needs to be tested throughly... */
2312 * GNUNET_NO in the call below makes transport disconnect the peer,
2313 * even if only a single address (out of say, six) went away. This
2314 * function must be careful to ONLY disconnect if the peer is gone,
2315 * not just a specific address.
2317 * More specifically, half the places it was used had it WRONG.
2320 /* No reconnect, signal disconnect instead! */
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324 "Disconnecting peer `%4s', %s\n", GNUNET_i2s (&nl->id),
2325 "try_fast_reconnect");
2327 GNUNET_STATISTICS_update (stats,
2329 ("# disconnects due to try_fast_reconnect"), 1,
2332 disconnect_neighbour (nl, GNUNET_YES);
2338 * Function that will be called whenever the plugin internally
2339 * cleans up a session pointer and hence the service needs to
2340 * discard all of those sessions as well. Plugins that do not
2341 * use sessions can simply omit calling this function and always
2342 * use NULL wherever a session pointer is needed.
2344 * @param cls closure
2345 * @param peer which peer was the session for
2346 * @param session which session is being destoyed
2349 plugin_env_session_end (void *cls,
2350 const struct GNUNET_PeerIdentity *peer,
2351 struct Session *session)
2353 struct TransportPlugin *p = cls;
2354 struct NeighbourMapEntry *nl;
2355 struct ReadyList *rl;
2356 struct ForeignAddressList *pos;
2357 struct ForeignAddressList *prev;
2360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2361 "Session ended with peer `%4s', %s\n",
2362 GNUNET_i2s (peer), "plugin_env_session_end");
2364 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2365 &remove_session_validations, session);
2366 nl = find_neighbour (peer);
2370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2371 "No neighbour record found for peer `%4s'\n",
2374 return; /* was never marked as connected */
2379 if (rl->plugin == p)
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Plugin was associated with peer `%4s'\n", GNUNET_i2s (peer));
2389 GNUNET_STATISTICS_update (stats,
2390 gettext_noop ("# disconnects due to session end"),
2392 disconnect_neighbour (nl, GNUNET_YES);
2396 pos = rl->addresses;
2397 while ((pos != NULL) && (pos->session != session))
2405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2406 "Session was never marked as ready for peer `%4s'\n",
2410 int validations_pending =
2411 GNUNET_CONTAINER_multihashmap_contains (validation_map,
2414 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2415 if (validations_pending == GNUNET_YES)
2418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2419 "Not disconnecting from peer `%4s due to pending address validations\n",
2425 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2426 GNUNET_STATISTICS_update (stats,
2428 ("# disconnects due to unready session"), 1,
2431 disconnect_neighbour (nl, GNUNET_YES);
2432 return; /* was never marked as connected */
2434 pos->session = NULL;
2435 if (GNUNET_YES == pos->connected)
2437 pos->connected = GNUNET_NO;
2438 GNUNET_STATISTICS_update (stats,
2439 gettext_noop ("# connected addresses"),
2442 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2444 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2445 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2448 if (pos->addrlen != 0)
2450 if (nl->received_pong != GNUNET_NO)
2452 GNUNET_STATISTICS_update (stats,
2454 ("# try_fast_reconnect thanks to plugin_env_session_end"),
2456 if (GNUNET_YES == pos->connected)
2457 try_fast_reconnect (p, nl);
2461 GNUNET_STATISTICS_update (stats,
2463 ("# disconnects due to missing pong"), 1,
2465 /* FIXME this is never true?! See: line 2416 */
2466 if (GNUNET_YES == pos->connected)
2467 disconnect_neighbour (nl, GNUNET_YES);
2472 /* was inbound connection, free 'pos' */
2474 rl->addresses = pos->next;
2476 prev->next = pos->next;
2477 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2479 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2480 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2482 GNUNET_free_non_null (pos->ressources);
2483 GNUNET_free_non_null (pos->quality);
2485 ats_modify_problem_state (ats, ATS_MODIFIED);
2487 if (GNUNET_YES != pos->connected)
2489 /* nothing else to do, connection was never up... */
2493 pos->connected = GNUNET_NO;
2494 GNUNET_STATISTICS_update (stats,
2495 gettext_noop ("# connected addresses"),
2499 if (nl->received_pong == GNUNET_NO)
2501 GNUNET_STATISTICS_update (stats,
2502 gettext_noop ("# disconnects due to NO pong"),
2504 disconnect_neighbour (nl, GNUNET_YES);
2505 return; /* nothing to do, never connected... */
2507 /* check if we have any validated addresses left */
2508 pos = rl->addresses;
2511 if (GNUNET_YES == pos->validated)
2513 GNUNET_STATISTICS_update (stats,
2515 ("# try_fast_reconnect thanks to validated_address"),
2517 try_fast_reconnect (p, nl);
2522 /* no valid addresses left, signal disconnect! */
2525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2526 "Disconnecting peer `%4s', %s\n",
2527 GNUNET_i2s (peer), "plugin_env_session_end");
2529 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2530 * it means there aren't any left for this PLUGIN/PEER combination! So
2531 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2532 * when it isn't necessary. Using GNUNET_YES at least checks to see
2533 * if there are any addresses that work first, so as not to overdo it.
2536 GNUNET_STATISTICS_update (stats,
2538 ("# disconnects due to plugin_env_session_end"), 1,
2540 disconnect_neighbour (nl, GNUNET_YES);
2545 * Function that must be called by each plugin to notify the
2546 * transport service about the addresses under which the transport
2547 * provided by the plugin can be reached.
2549 * @param cls closure
2550 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2551 * @param addr one of the addresses of the host, NULL for the last address
2552 * the specific address format depends on the transport
2553 * @param addrlen length of the address
2556 plugin_env_notify_address (void *cls,
2557 int add_remove, const void *addr, size_t addrlen)
2559 struct TransportPlugin *p = cls;
2560 struct OwnAddressList *al;
2561 struct OwnAddressList *prev;
2563 GNUNET_assert (p->api != NULL);
2565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2566 (add_remove == GNUNET_YES)
2567 ? "Adding `%s':%s to the set of our addresses\n"
2568 : "Removing `%s':%s from the set of our addresses\n",
2569 a2s (p->short_name, addr, addrlen), p->short_name);
2571 GNUNET_assert (addr != NULL);
2572 if (GNUNET_NO == add_remove)
2578 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2581 p->addresses = al->next;
2583 prev->next = al->next;
2594 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2595 al->next = p->addresses;
2597 al->addrlen = addrlen;
2598 memcpy (&al[1], addr, addrlen);
2604 * Notify all of our clients about a peer connecting.
2607 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2608 struct GNUNET_TIME_Relative latency, uint32_t distance)
2610 struct ConnectInfoMessage *cim;
2611 struct TransportClient *cpos;
2615 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2622 "Notifying clients about connection with `%s'\n",
2625 GNUNET_STATISTICS_update (stats,
2626 gettext_noop ("# peers connected"), 1, GNUNET_NO);
2630 sizeof (struct ConnectInfoMessage) +
2631 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2632 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2633 cim = GNUNET_malloc (size);
2634 cim->header.size = htons (size);
2635 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2636 cim->ats_count = htonl (2);
2637 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2638 (&cim->ats)[0].value = htonl (distance);
2639 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2640 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2641 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2642 (&cim->ats)[2].value = htonl (0);
2643 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2645 /* notify ats about connecting peer */
2646 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2649 ats_modify_problem_state (ats, ATS_MODIFIED);
2650 ats_calculate_bandwidth_distribution (ats);
2654 while (cpos != NULL)
2656 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2664 * Notify all of our clients about a peer disconnecting.
2667 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2669 struct DisconnectInfoMessage dim;
2670 struct TransportClient *cpos;
2672 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2679 "Notifying clients about lost connection to `%s'\n",
2682 GNUNET_STATISTICS_update (stats,
2683 gettext_noop ("# peers connected"), -1, GNUNET_NO);
2684 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2685 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2686 dim.reserved = htonl (0);
2687 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2689 /* notify ats about connecting peer */
2690 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2693 ats_modify_problem_state (ats, ATS_MODIFIED);
2694 ats_calculate_bandwidth_distribution (ats);
2699 while (cpos != NULL)
2701 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2708 * Find a ForeignAddressList entry for the given neighbour
2709 * that matches the given address and transport.
2711 * @param neighbour which peer we care about
2712 * @param tname name of the transport plugin
2713 * @param session session to look for, NULL for 'any'; otherwise
2714 * can be used for the service to "learn" this session ID
2716 * @param addr binary address
2717 * @param addrlen length of addr
2718 * @return NULL if no such entry exists
2720 static struct ForeignAddressList *
2721 find_peer_address (struct NeighbourMapEntry *neighbour,
2723 struct Session *session, const char *addr, uint16_t addrlen)
2725 struct ReadyList *head;
2726 struct ForeignAddressList *pos;
2728 head = neighbour->plugins;
2729 while (head != NULL)
2731 if (0 == strcmp (tname, head->plugin->short_name))
2737 pos = head->addresses;
2738 while ((pos != NULL) &&
2739 ((pos->addrlen != addrlen) ||
2740 (memcmp (pos->addr, addr, addrlen) != 0)))
2742 if ((session != NULL) && (pos->session == session))
2746 if ((session != NULL) && (pos != NULL))
2747 pos->session = session; /* learn it! */
2753 * Get the peer address struct for the given neighbour and
2754 * address. If it doesn't yet exist, create it.
2756 * @param neighbour which peer we care about
2757 * @param tname name of the transport plugin
2758 * @param session session of the plugin, or NULL for none
2759 * @param addr binary address
2760 * @param addrlen length of addr
2761 * @return NULL if we do not have a transport plugin for 'tname'
2763 static struct ForeignAddressList *
2764 add_peer_address (struct NeighbourMapEntry *neighbour,
2766 struct Session *session, const char *addr, uint16_t addrlen)
2768 struct ReadyList *head;
2769 struct ForeignAddressList *ret;
2772 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2775 head = neighbour->plugins;
2777 while (head != NULL)
2779 if (0 == strcmp (tname, head->plugin->short_name))
2785 ret = GNUNET_malloc (sizeof (struct ForeignAddressList) + addrlen);
2786 ret->session = session;
2787 if ((addrlen > 0) && (addr != NULL))
2789 ret->addr = (const char *) &ret[1];
2790 memcpy (&ret[1], addr, addrlen);
2798 GNUNET_malloc (available_ressources *
2799 sizeof (struct ATS_ressource_entry));
2800 for (c = 0; c < available_ressources; c++)
2802 struct ATS_ressource_entry *r = ret->ressources;
2805 r[c].atis_index = ressources[c].atis_index;
2806 if (0 == strcmp (neighbour->plugins->plugin->short_name, "unix"))
2808 r[c].c = ressources[c].c_unix;
2810 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "udp"))
2812 r[c].c = ressources[c].c_udp;
2814 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "tcp"))
2816 r[c].c = ressources[c].c_tcp;
2818 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "http"))
2820 r[c].c = ressources[c].c_http;
2822 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "https"))
2824 r[c].c = ressources[c].c_https;
2826 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "wlan"))
2828 r[c].c = ressources[c].c_wlan;
2832 r[c].c = ressources[c].c_default;
2833 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2834 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2835 GNUNET_i2s (&neighbour->id),
2836 neighbour->plugins->plugin->short_name);
2841 GNUNET_malloc (available_quality_metrics *
2842 sizeof (struct ATS_quality_entry));
2843 ret->addrlen = addrlen;
2844 ret->expires = GNUNET_TIME_relative_to_absolute
2845 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2846 ret->latency = GNUNET_TIME_relative_get_forever ();
2848 ret->timeout = GNUNET_TIME_relative_to_absolute
2849 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2850 ret->ready_list = head;
2851 ret->next = head->addresses;
2852 head->addresses = ret;
2858 * Closure for 'add_validated_address'.
2860 struct AddValidatedAddressContext
2863 * Entry that has been validated.
2865 const struct ValidationEntry *ve;
2868 * Flag set after we have added the address so
2869 * that we terminate the iteration next time.
2876 * Callback function used to fill a buffer of max bytes with a list of
2877 * addresses in the format used by HELLOs. Should use
2878 * "GNUNET_HELLO_add_address" as a helper function.
2880 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2881 * @param max maximum number of bytes that can be written to buf
2882 * @param buf where to write the address information
2883 * @return number of bytes written, 0 to signal the
2884 * end of the iteration.
2887 add_validated_address (void *cls, size_t max, void *buf)
2889 struct AddValidatedAddressContext *avac = cls;
2890 const struct ValidationEntry *ve = avac->ve;
2892 if (GNUNET_YES == avac->done)
2894 avac->done = GNUNET_YES;
2895 return GNUNET_HELLO_add_address (ve->transport_name,
2896 GNUNET_TIME_relative_to_absolute
2897 (HELLO_ADDRESS_EXPIRATION), ve->addr,
2898 ve->addrlen, buf, max);
2904 * Closure for 'check_address_exists'.
2906 struct CheckAddressExistsClosure
2909 * Address to check for.
2914 * Name of the transport.
2921 struct Session *session;
2924 * Set to GNUNET_YES if the address exists.
2937 * Iterator over hash map entries. Checks if the given
2938 * validation entry is for the same address as what is given
2941 * @param cls the 'struct CheckAddressExistsClosure*'
2942 * @param key current key code (ignored)
2943 * @param value value in the hash map ('struct ValidationEntry')
2944 * @return GNUNET_YES if we should continue to
2945 * iterate (mismatch), GNUNET_NO if not (entry matched)
2948 check_address_exists (void *cls, const GNUNET_HashCode * key, void *value)
2950 struct CheckAddressExistsClosure *caec = cls;
2951 struct ValidationEntry *ve = value;
2953 if ((0 == strcmp (caec->tname,
2954 ve->transport_name)) &&
2955 (caec->addrlen == ve->addrlen) &&
2956 (0 == memcmp (caec->addr, ve->addr, caec->addrlen)))
2958 caec->exists = GNUNET_YES;
2961 if ((ve->session != NULL) && (caec->session == ve->session))
2963 caec->exists = GNUNET_YES;
2971 neighbour_timeout_task (void *cls,
2972 const struct GNUNET_SCHEDULER_TaskContext *tc)
2974 struct NeighbourMapEntry *n = cls;
2977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2978 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2980 GNUNET_STATISTICS_update (stats,
2981 gettext_noop ("# disconnects due to timeout"),
2983 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2984 disconnect_neighbour (n, GNUNET_NO);
2989 * Schedule the job that will cause us to send a PING to the
2990 * foreign address to evaluate its validity and latency.
2992 * @param fal address to PING
2994 static void schedule_next_ping (struct ForeignAddressList *fal);
2998 * Add the given address to the list of foreign addresses
2999 * available for the given peer (check for duplicates).
3001 * @param cls the respective 'struct NeighbourMapEntry' to update
3002 * @param tname name of the transport
3003 * @param expiration expiration time
3004 * @param addr the address
3005 * @param addrlen length of the address
3006 * @return GNUNET_OK (always)
3009 add_to_foreign_address_list (void *cls,
3011 struct GNUNET_TIME_Absolute expiration,
3012 const void *addr, uint16_t addrlen)
3014 struct NeighbourMapEntry *n = cls;
3015 struct ForeignAddressList *fal;
3018 GNUNET_STATISTICS_update (stats,
3020 ("# valid peer addresses returned by PEERINFO"), 1,
3023 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3026 #if DEBUG_TRANSPORT_HELLO
3027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3028 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3029 a2s (tname, addr, addrlen),
3030 tname, GNUNET_i2s (&n->id), expiration.abs_value);
3032 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3035 GNUNET_STATISTICS_update (stats,
3037 ("# previously validated addresses lacking transport"),
3042 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3043 schedule_next_ping (fal);
3049 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3055 "Failed to add new address for `%4s'\n", GNUNET_i2s (&n->id));
3059 if (fal->validated == GNUNET_NO)
3061 fal->validated = GNUNET_YES;
3062 GNUNET_STATISTICS_update (stats,
3064 ("# peer addresses considered valid"), 1,
3067 if (try == GNUNET_YES)
3070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071 "Have new addresses, will try to trigger transmissions.\n");
3073 try_transmission_to_peer (n);
3080 * Add addresses in validated HELLO "h" to the set of addresses
3081 * we have for this peer.
3083 * @param cls closure ('struct NeighbourMapEntry*')
3084 * @param peer id of the peer, NULL for last call
3085 * @param h hello message for the peer (can be NULL)
3086 * @param err_msg NULL if successful, otherwise contains error message
3089 add_hello_for_peer (void *cls,
3090 const struct GNUNET_PeerIdentity *peer,
3091 const struct GNUNET_HELLO_Message *h, const char *err_msg)
3093 struct NeighbourMapEntry *n = cls;
3095 if (err_msg != NULL)
3098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3099 _("Error in communication with PEERINFO service: %s\n"),
3106 GNUNET_STATISTICS_update (stats,
3108 ("# outstanding peerinfo iterate requests"), -1,
3114 return; /* no HELLO available */
3116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3117 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3118 "HELLO", GNUNET_i2s (peer));
3120 if (GNUNET_YES != n->public_key_valid)
3122 GNUNET_HELLO_get_key (h, &n->publicKey);
3123 n->public_key_valid = GNUNET_YES;
3125 GNUNET_HELLO_iterate_addresses (h,
3126 GNUNET_NO, &add_to_foreign_address_list, n);
3131 * Create a fresh entry in our neighbour list for the given peer.
3132 * Will try to transmit our current HELLO to the new neighbour.
3133 * Do not call this function directly, use 'setup_peer_check_blacklist.
3135 * @param peer the peer for which we create the entry
3136 * @param do_hello should we schedule transmitting a HELLO
3137 * @return the new neighbour list entry
3139 static struct NeighbourMapEntry *
3140 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer, int do_hello)
3142 struct NeighbourMapEntry *n;
3143 struct TransportPlugin *tp;
3144 struct ReadyList *rl;
3146 GNUNET_assert (0 != memcmp (peer,
3148 sizeof (struct GNUNET_PeerIdentity)));
3150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3151 "Setting up state for neighbour `%4s'\n", GNUNET_i2s (peer));
3153 GNUNET_STATISTICS_update (stats,
3154 gettext_noop ("# active neighbours"), 1, GNUNET_NO);
3155 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3158 GNUNET_TIME_relative_to_absolute
3159 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3160 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3161 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3162 MAX_BANDWIDTH_CARRY_S);
3166 if ((tp->api->send != NULL) && (!is_blacklisted (peer, tp)))
3168 rl = GNUNET_malloc (sizeof (struct ReadyList));
3170 rl->next = n->plugins;
3173 rl->addresses = NULL;
3177 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3180 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3181 &neighbour_timeout_task, n);
3182 GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n,
3183 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3186 GNUNET_STATISTICS_update (stats,
3188 ("# peerinfo new neighbor iterate requests"), 1,
3190 GNUNET_STATISTICS_update (stats,
3192 ("# outstanding peerinfo iterate requests"), 1,
3195 GNUNET_PEERINFO_iterate (peerinfo, peer, GNUNET_TIME_UNIT_FOREVER_REL,
3196 &add_hello_for_peer, n);
3198 GNUNET_STATISTICS_update (stats,
3199 gettext_noop ("# HELLO's sent to new neighbors"),
3201 if (NULL != our_hello)
3202 transmit_to_peer (NULL, NULL, 0,
3203 HELLO_ADDRESS_EXPIRATION,
3204 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
3212 * Function called after we have checked if communicating
3213 * with a given peer is acceptable.
3215 * @param cls closure
3216 * @param n NULL if communication is not acceptable
3218 typedef void (*SetupContinuation) (void *cls, struct NeighbourMapEntry * n);
3222 * Information kept for each client registered to perform
3228 * This is a linked list.
3230 struct Blacklisters *next;
3233 * This is a linked list.
3235 struct Blacklisters *prev;
3238 * Client responsible for this entry.
3240 struct GNUNET_SERVER_Client *client;
3243 * Blacklist check that we're currently performing.
3245 struct BlacklistCheck *bc;
3251 * Head of DLL of blacklisting clients.
3253 static struct Blacklisters *bl_head;
3256 * Tail of DLL of blacklisting clients.
3258 static struct Blacklisters *bl_tail;
3262 * Context we use when performing a blacklist check.
3264 struct BlacklistCheck
3268 * This is a linked list.
3270 struct BlacklistCheck *next;
3273 * This is a linked list.
3275 struct BlacklistCheck *prev;
3278 * Peer being checked.
3280 struct GNUNET_PeerIdentity peer;
3283 * Option for setup neighbour afterwards.
3288 * Continuation to call with the result.
3290 SetupContinuation cont;
3298 * Current transmission request handle for this client, or NULL if no
3299 * request is pending.
3301 struct GNUNET_CONNECTION_TransmitHandle *th;
3304 * Our current position in the blacklisters list.
3306 struct Blacklisters *bl_pos;
3309 * Current task performing the check.
3311 GNUNET_SCHEDULER_TaskIdentifier task;
3316 * Head of DLL of active blacklisting queries.
3318 static struct BlacklistCheck *bc_head;
3321 * Tail of DLL of active blacklisting queries.
3323 static struct BlacklistCheck *bc_tail;
3327 * Perform next action in the blacklist check.
3329 * @param cls the 'struct BlacklistCheck*'
3333 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3336 * Transmit blacklist query to the client.
3338 * @param cls the 'struct BlacklistCheck'
3339 * @param size number of bytes allowed
3340 * @param buf where to copy the message
3341 * @return number of bytes copied to buf
3344 transmit_blacklist_message (void *cls, size_t size, void *buf)
3346 struct BlacklistCheck *bc = cls;
3347 struct Blacklisters *bl;
3348 struct BlacklistMessage bm;
3353 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3354 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3355 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3356 "Failed to send blacklist test for peer `%s' to client\n",
3357 GNUNET_i2s (&bc->peer));
3361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3362 "Sending blacklist test for peer `%s' to client\n",
3363 GNUNET_i2s (&bc->peer));
3366 bm.header.size = htons (sizeof (struct BlacklistMessage));
3367 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3368 bm.is_allowed = htonl (0);
3370 memcpy (buf, &bm, sizeof (bm));
3371 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3377 * Perform next action in the blacklist check.
3379 * @param cls the 'struct BlacklistCheck*'
3383 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3385 struct BlacklistCheck *bc = cls;
3386 struct Blacklisters *bl;
3388 bc->task = GNUNET_SCHEDULER_NO_TASK;
3393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3394 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3395 GNUNET_i2s (&bc->peer));
3397 bc->cont (bc->cont_cls, setup_new_neighbour (&bc->peer, bc->do_hello));
3404 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3407 GNUNET_TIME_UNIT_FOREVER_REL,
3408 &transmit_blacklist_message,
3415 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3416 * does not yet exist, check the blacklist. If the blacklist says creating
3417 * one is acceptable, create one and call the continuation; otherwise
3418 * call the continuation with NULL.
3420 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3421 * @param do_hello should we also schedule sending our HELLO to the peer
3422 * if this is a new record
3423 * @param cont function to call with the 'struct NeigbhbourList*'
3424 * @param cont_cls closure for cont
3427 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3429 SetupContinuation cont, void *cont_cls)
3431 struct NeighbourMapEntry *n;
3432 struct BlacklistCheck *bc;
3434 n = find_neighbour (peer);
3438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3439 "Neighbour record exists for peer `%s'\n", GNUNET_i2s (peer));
3445 if (bl_head == NULL)
3448 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3450 setup_new_neighbour (peer, do_hello);
3453 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3454 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3456 bc->do_hello = do_hello;
3458 bc->cont_cls = cont_cls;
3459 bc->bl_pos = bl_head;
3460 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3465 * Function called with the result of querying a new blacklister about
3466 * it being allowed (or not) to continue to talk to an existing neighbour.
3468 * @param cls the original 'struct NeighbourMapEntry'
3469 * @param n NULL if we need to disconnect
3472 confirm_or_drop_neighbour (void *cls, struct NeighbourMapEntry *n)
3474 struct NeighbourMapEntry *orig = cls;
3479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3480 "Disconnecting peer `%4s', %s\n", GNUNET_i2s (&orig->id),
3481 "confirm_or_drop_neighboUr");
3483 GNUNET_STATISTICS_update (stats,
3484 gettext_noop ("# disconnects due to blacklist"),
3486 disconnect_neighbour (orig, GNUNET_NO);
3491 struct TestConnectionContext
3495 struct Blacklisters *bl;
3500 test_connection_ok (void *cls, const GNUNET_HashCode * key, void *value)
3502 struct TestConnectionContext *tcc = cls;
3503 struct NeighbourMapEntry *n = value;
3504 struct BlacklistCheck *bc;
3507 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3508 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3510 bc->do_hello = GNUNET_NO;
3511 bc->cont = &confirm_or_drop_neighbour;
3513 bc->bl_pos = tcc->bl;
3514 if (GNUNET_YES == tcc->first)
3516 /* all would wait for the same client, no need to
3517 * create more than just the first task right now */
3518 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3519 tcc->first = GNUNET_NO;
3526 * Handle a request to start a blacklist.
3528 * @param cls closure (always NULL)
3529 * @param client identification of the client
3530 * @param message the actual message
3533 handle_blacklist_init (void *cls,
3534 struct GNUNET_SERVER_Client *client,
3535 const struct GNUNET_MessageHeader *message)
3537 struct Blacklisters *bl;
3538 struct TestConnectionContext tcc;
3543 if (bl->client == client)
3546 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3551 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3552 bl->client = client;
3553 GNUNET_SERVER_client_keep (client);
3554 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3555 /* confirm that all existing connections are OK! */
3557 tcc.first = GNUNET_YES;
3558 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &test_connection_ok, &tcc);
3563 * Handle a request to blacklist a peer.
3565 * @param cls closure (always NULL)
3566 * @param client identification of the client
3567 * @param message the actual message
3570 handle_blacklist_reply (void *cls,
3571 struct GNUNET_SERVER_Client *client,
3572 const struct GNUNET_MessageHeader *message)
3574 const struct BlacklistMessage *msg =
3575 (const struct BlacklistMessage *) message;
3576 struct Blacklisters *bl;
3577 struct BlacklistCheck *bc;
3580 while ((bl != NULL) && (bl->client != client))
3585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
3587 /* FIXME: other error handling here!? */
3588 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3593 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3597 "Blacklist check failed, peer not allowed\n");
3599 bc->cont (bc->cont_cls, NULL);
3600 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3607 "Blacklist check succeeded, continuing with checks\n");
3609 bc->bl_pos = bc->bl_pos->next;
3610 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3612 /* check if any other bc's are waiting for this blacklister */
3616 if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
3617 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3624 * Send periodic PING messages to a given foreign address.
3626 * @param cls our 'struct PeriodicValidationContext*'
3627 * @param tc task context
3630 send_periodic_ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3632 struct ForeignAddressList *peer_address = cls;
3633 struct TransportPlugin *tp;
3634 struct ValidationEntry *va;
3635 struct NeighbourMapEntry *neighbour;
3636 struct TransportPingMessage ping;
3637 struct CheckAddressExistsClosure caec;
3639 uint16_t hello_size;
3643 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3644 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3646 GNUNET_assert (peer_address != NULL);
3647 tp = peer_address->ready_list->plugin;
3648 neighbour = peer_address->ready_list->neighbour;
3649 if (GNUNET_YES != neighbour->public_key_valid)
3651 /* no public key yet, try again later */
3652 schedule_next_ping (peer_address);
3655 caec.addr = peer_address->addr;
3656 caec.addrlen = peer_address->addrlen;
3657 caec.tname = tp->short_name;
3658 caec.session = peer_address->session;
3659 caec.exists = GNUNET_NO;
3661 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3662 &check_address_exists, &caec);
3663 if (caec.exists == GNUNET_YES)
3665 /* During validation attempts we will likely trigger the other
3666 * peer trying to validate our address which in turn will cause
3667 * it to send us its HELLO, so we expect to hit this case rather
3668 * frequently. Only print something if we are very verbose. */
3669 #if DEBUG_TRANSPORT > 1
3670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3671 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3672 (peer_address->addr != NULL)
3673 ? a2s (tp->short_name,
3675 peer_address->addrlen)
3676 : "<inbound>", tp->short_name, GNUNET_i2s (&neighbour->id));
3678 schedule_next_ping (peer_address);
3681 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3682 va->transport_name = GNUNET_strdup (tp->short_name);
3683 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3685 va->send_time = GNUNET_TIME_absolute_get ();
3686 va->session = peer_address->session;
3687 if (peer_address->addr != NULL)
3689 va->addr = (const void *) &va[1];
3690 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3691 va->addrlen = peer_address->addrlen;
3693 memcpy (&va->publicKey,
3694 &neighbour->publicKey,
3695 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3697 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3698 &timeout_hello_validation,
3700 GNUNET_CONTAINER_multihashmap_put (validation_map,
3701 &neighbour->id.hashPubKey,
3703 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3705 if (peer_address->validated != GNUNET_YES)
3706 hello_size = GNUNET_HELLO_size (our_hello);
3710 tsize = sizeof (struct TransportPingMessage) + hello_size;
3712 if (peer_address->addr != NULL)
3714 slen = strlen (tp->short_name) + 1;
3715 tsize += slen + peer_address->addrlen;
3719 slen = 0; /* make gcc happy */
3721 message_buf = GNUNET_malloc (tsize);
3722 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3723 ping.challenge = htonl (va->challenge);
3724 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
3725 if (peer_address->validated != GNUNET_YES)
3727 memcpy (message_buf, our_hello, hello_size);
3730 if (peer_address->addr != NULL)
3732 ping.header.size = htons (sizeof (struct TransportPingMessage) +
3733 peer_address->addrlen + slen);
3734 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3735 tp->short_name, slen);
3736 memcpy (&message_buf
3737 [hello_size + sizeof (struct TransportPingMessage) + slen],
3738 peer_address->addr, peer_address->addrlen);
3742 ping.header.size = htons (sizeof (struct TransportPingMessage));
3745 memcpy (&message_buf[hello_size],
3746 &ping, sizeof (struct TransportPingMessage));
3748 #if DEBUG_TRANSPORT_REVALIDATION
3749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3750 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3751 (peer_address->addr != NULL)
3752 ? a2s (peer_address->plugin->short_name,
3754 peer_address->addrlen)
3757 GNUNET_i2s (&neighbour->id), "HELLO", hello_size, "PING");
3759 if (peer_address->validated != GNUNET_YES)
3760 GNUNET_STATISTICS_update (stats,
3761 gettext_noop ("# PING with HELLO messages sent"),
3764 GNUNET_STATISTICS_update (stats,
3766 ("# PING without HELLO messages sent"), 1,
3768 GNUNET_STATISTICS_update (stats,
3770 ("# PING messages sent for re-validation"), 1,
3772 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3773 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
3775 GNUNET_free (message_buf);
3776 schedule_next_ping (peer_address);
3781 * Schedule the job that will cause us to send a PING to the
3782 * foreign address to evaluate its validity and latency.
3784 * @param fal address to PING
3787 schedule_next_ping (struct ForeignAddressList *fal)
3789 struct GNUNET_TIME_Relative delay;
3791 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3793 GNUNET_SCHEDULER_cancel (fal->revalidate_task);
3794 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3796 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3797 delay.rel_value /= 2; /* do before expiration */
3798 delay = GNUNET_TIME_relative_min (delay, LATENCY_EVALUATION_MAX_DELAY);
3799 if (GNUNET_YES != fal->estimated)
3801 delay = GNUNET_TIME_UNIT_ZERO;
3802 fal->estimated = GNUNET_YES;
3805 if (GNUNET_YES == fal->connected)
3807 delay = GNUNET_TIME_relative_min (delay,
3808 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3810 /* FIXME: also adjust delay based on how close the last
3811 * observed latency is to the latency of the best alternative */
3812 /* bound how fast we can go */
3813 delay = GNUNET_TIME_relative_max (delay, GNUNET_TIME_UNIT_SECONDS);
3814 /* randomize a bit (to avoid doing all at the same time) */
3816 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3818 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3819 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed (delay,
3820 &send_periodic_ping,
3828 * Function that will be called if we receive some payload
3829 * from another peer.
3831 * @param message the payload
3832 * @param n peer who claimed to be the sender
3835 handle_payload_message (const struct GNUNET_MessageHeader *message,
3836 struct NeighbourMapEntry *n)
3838 struct InboundMessage *im;
3839 struct TransportClient *cpos;
3842 msize = ntohs (message->size);
3843 if (n->received_pong == GNUNET_NO)
3846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3847 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3848 ntohs (message->type),
3849 ntohs (message->size), GNUNET_i2s (&n->id));
3851 GNUNET_free_non_null (n->pre_connect_message_buffer);
3852 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3853 memcpy (n->pre_connect_message_buffer, message, msize);
3858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3859 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3860 ntohs (message->type),
3861 ntohs (message->size), GNUNET_i2s (&n->id));
3863 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3866 n->quota_violation_count++;
3868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3869 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3870 n->in_tracker.available_bytes_per_s__,
3871 n->quota_violation_count);
3873 /* Discount 32k per violation */
3874 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
3878 if (n->quota_violation_count > 0)
3880 /* try to add 32k back */
3881 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
3882 n->quota_violation_count--;
3885 GNUNET_STATISTICS_update (stats,
3887 ("# payload received from other peers"), msize,
3889 /* transmit message to all clients */
3890 uint32_t ats_count = 2;
3892 sizeof (struct InboundMessage) +
3893 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3894 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3897 im = GNUNET_malloc (size);
3898 im->header.size = htons (size);
3899 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3901 im->ats_count = htonl (ats_count);
3902 /* Setting ATS data */
3903 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3904 (&(im->ats))[0].value = htonl (n->distance);
3905 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3906 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3907 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3908 (&(im->ats))[ats_count].value = htonl (0);
3910 memcpy (&((&(im->ats))[ats_count + 1]), message, msize);
3912 while (cpos != NULL)
3914 transmit_to_client (cpos, &im->header, GNUNET_YES);
3922 * Iterator over hash map entries. Checks if the given validation
3923 * entry is for the same challenge as what is given in the PONG.
3925 * @param cls the 'struct TransportPongMessage*'
3926 * @param key peer identity
3927 * @param value value in the hash map ('struct ValidationEntry')
3928 * @return GNUNET_YES if we should continue to
3929 * iterate (mismatch), GNUNET_NO if not (entry matched)
3932 check_pending_validation (void *cls, const GNUNET_HashCode * key, void *value)
3934 const struct TransportPongMessage *pong = cls;
3935 struct ValidationEntry *ve = value;
3936 struct AddValidatedAddressContext avac;
3937 unsigned int challenge = ntohl (pong->challenge);
3938 struct GNUNET_HELLO_Message *hello;
3939 struct GNUNET_PeerIdentity target;
3940 struct NeighbourMapEntry *n;
3941 struct ForeignAddressList *fal;
3942 struct OwnAddressList *oal;
3943 struct TransportPlugin *tp;
3944 struct GNUNET_MessageHeader *prem;
3950 ps = ntohs (pong->header.size);
3951 if (ps < sizeof (struct TransportPongMessage))
3953 GNUNET_break_op (0);
3956 addr = (const char *) &pong[1];
3957 slen = strlen (ve->transport_name) + 1;
3958 if ((ps - sizeof (struct TransportPongMessage) < slen) ||
3959 (ve->challenge != challenge) ||
3960 (addr[slen - 1] != '\0') ||
3961 (0 != strcmp (addr, ve->transport_name)) ||
3962 (ntohl (pong->purpose.size)
3963 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3965 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3966 sizeof (struct GNUNET_PeerIdentity) + ps -
3967 sizeof (struct TransportPongMessage)))
3972 alen = ps - sizeof (struct TransportPongMessage) - slen;
3973 switch (ntohl (pong->purpose.purpose))
3975 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3976 if ((ve->addrlen + slen != ntohl (pong->addrlen)) ||
3977 (0 != memcmp (&addr[slen], ve->addr, ve->addrlen)))
3979 return GNUNET_YES; /* different entry, keep trying! */
3981 if (0 != memcmp (&pong->pid, key, sizeof (struct GNUNET_PeerIdentity)))
3983 GNUNET_break_op (0);
3987 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3989 &pong->signature, &ve->publicKey))
3991 GNUNET_break_op (0);
3996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3997 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3999 a2s (ve->transport_name,
4000 (const struct sockaddr *) ve->addr,
4001 ve->addrlen), ve->transport_name);
4004 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4005 if (0 != memcmp (&pong->pid,
4006 &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4010 GNUNET_asprintf (&peer, "%s", GNUNET_i2s (&pong->pid));
4012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4013 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4014 GNUNET_i2s (&my_identity), peer);
4019 if (ve->addrlen != 0)
4021 /* must have been for a different validation entry */
4024 tp = find_transport (ve->transport_name);
4030 oal = tp->addresses;
4033 if ((oal->addrlen == alen) && (0 == memcmp (&oal[1], &addr[slen], alen)))
4039 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4041 ("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4042 GNUNET_i2s (&pong->pid), a2s (ve->transport_name, &addr[slen],
4044 /* FIXME: since the sender of the PONG currently uses the
4045 * wrong address (see FIMXE there!), we cannot run a
4046 * proper check here... */
4052 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4054 &pong->signature, &ve->publicKey))
4056 GNUNET_break_op (0);
4061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4062 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4064 a2s (ve->transport_name,
4065 &addr[slen], alen), ve->transport_name);
4069 GNUNET_break_op (0);
4072 if (GNUNET_TIME_absolute_get_remaining
4073 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4075 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4076 _("Received expired signature. Check system time.\n"));
4079 GNUNET_STATISTICS_update (stats,
4080 gettext_noop ("# address validation successes"),
4082 /* create the updated HELLO */
4083 GNUNET_CRYPTO_hash (&ve->publicKey,
4084 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4085 &target.hashPubKey);
4086 if (ve->addr != NULL)
4088 avac.done = GNUNET_NO;
4090 hello = GNUNET_HELLO_create (&ve->publicKey, &add_validated_address, &avac);
4091 GNUNET_PEERINFO_add_peer (peerinfo, hello);
4092 GNUNET_free (hello);
4094 n = find_neighbour (&target);
4097 n->publicKey = ve->publicKey;
4098 n->public_key_valid = GNUNET_YES;
4099 fal = add_peer_address (n,
4101 ve->session, ve->addr, ve->addrlen);
4102 GNUNET_assert (fal != NULL);
4103 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4104 fal->validated = GNUNET_YES;
4105 mark_address_connected (fal);
4106 GNUNET_STATISTICS_update (stats,
4108 ("# peer addresses considered valid"), 1,
4110 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4111 update_addr_value (fal,
4112 GNUNET_TIME_absolute_get_duration (ve->
4113 send_time).rel_value,
4114 GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4116 schedule_next_ping (fal);
4117 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4118 n->latency = fal->latency;
4120 n->latency.rel_value =
4121 (fal->latency.rel_value + n->latency.rel_value) / 2;
4123 n->distance = fal->distance;
4124 if (GNUNET_NO == n->received_pong)
4126 n->received_pong = GNUNET_YES;
4127 notify_clients_connect (&target, n->latency, n->distance);
4128 if (NULL != (prem = n->pre_connect_message_buffer))
4130 n->pre_connect_message_buffer = NULL;
4131 handle_payload_message (prem, n);
4135 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4137 GNUNET_SCHEDULER_cancel (n->retry_task);
4138 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4139 try_transmission_to_peer (n);
4143 /* clean up validation entry */
4144 GNUNET_assert (GNUNET_YES ==
4145 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4147 abort_validation (NULL, NULL, ve);
4153 * Function that will be called if we receive a validation
4154 * of an address challenge that we transmitted to another
4155 * peer. Note that the validation should only be considered
4156 * acceptable if the challenge matches AND if the sender
4157 * address is at least a plausible address for this peer
4158 * (otherwise we may be seeing a MiM attack).
4160 * @param cls closure
4161 * @param message the pong message
4162 * @param peer who responded to our challenge
4163 * @param sender_address string describing our sender address (as observed
4164 * by the other peer in binary format)
4165 * @param sender_address_len number of bytes in 'sender_address'
4168 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4169 const struct GNUNET_PeerIdentity *peer,
4170 const char *sender_address, size_t sender_address_len)
4172 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4174 /* PONG send to self, ignore */
4175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4176 "Receiving `%s' message from myself\n", "PONG");
4179 #if DEBUG_TRANSPORT > 1
4180 /* we get tons of these that just get discarded, only log
4181 * if we are quite verbose */
4182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4183 "Receiving `%s' message from `%4s'.\n", "PONG",
4186 GNUNET_STATISTICS_update (stats,
4187 gettext_noop ("# PONG messages received"),
4189 if (GNUNET_SYSERR !=
4190 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4192 &check_pending_validation,
4195 /* This is *expected* to happen a lot since we send
4196 * PONGs to *all* known addresses of the sender of
4197 * the PING, so most likely we get multiple PONGs
4198 * per PING, and all but the first PONG will end up
4199 * here. So really we should not print anything here
4200 * unless we want to be very, very verbose... */
4201 #if DEBUG_TRANSPORT > 2
4202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4203 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4204 "PONG", GNUNET_i2s (peer), "PING");
4213 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4215 * @param cls the 'struct ValidationEntry*'
4216 * @param neighbour neighbour to validate, NULL if validation failed
4219 transmit_hello_and_ping (void *cls, struct NeighbourMapEntry *neighbour)
4221 struct ValidationEntry *va = cls;
4222 struct ForeignAddressList *peer_address;
4223 struct TransportPingMessage ping;
4224 uint16_t hello_size;
4227 struct GNUNET_PeerIdentity id;
4230 GNUNET_CRYPTO_hash (&va->publicKey,
4231 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4233 if (neighbour == NULL)
4235 /* FIXME: stats... */
4236 GNUNET_break (GNUNET_OK ==
4237 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4238 &id.hashPubKey, va));
4239 abort_validation (NULL, NULL, va);
4242 neighbour->publicKey = va->publicKey;
4243 neighbour->public_key_valid = GNUNET_YES;
4244 peer_address = add_peer_address (neighbour,
4245 va->transport_name, NULL,
4246 (const void *) &va[1], va->addrlen);
4247 if (peer_address == NULL)
4249 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4250 "Failed to add peer `%4s' for plugin `%s'\n",
4251 GNUNET_i2s (&neighbour->id), va->transport_name);
4252 GNUNET_break (GNUNET_OK ==
4253 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4254 &id.hashPubKey, va));
4255 abort_validation (NULL, NULL, va);
4258 if (NULL == our_hello)
4259 refresh_hello_task (NULL, NULL);
4260 hello_size = GNUNET_HELLO_size (our_hello);
4261 slen = strlen (va->transport_name) + 1;
4263 sizeof (struct TransportPingMessage) + hello_size + va->addrlen + slen;
4264 message_buf = GNUNET_malloc (tsize);
4265 ping.challenge = htonl (va->challenge);
4267 htons (sizeof (struct TransportPingMessage) + slen + va->addrlen);
4268 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4269 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
4270 memcpy (message_buf, our_hello, hello_size);
4271 memcpy (&message_buf[hello_size],
4272 &ping, sizeof (struct TransportPingMessage));
4273 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4274 va->transport_name, slen);
4275 memcpy (&message_buf
4276 [hello_size + sizeof (struct TransportPingMessage) + slen], &va[1],
4279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4280 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4283 : a2s (va->transport_name,
4284 (const void *) &va[1], va->addrlen),
4286 GNUNET_i2s (&neighbour->id),
4287 "HELLO", hello_size,
4289 sizeof (struct TransportPingMessage) + va->addrlen + slen);
4292 GNUNET_STATISTICS_update (stats,
4294 ("# PING messages sent for initial validation"), 1,
4296 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4297 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
4299 GNUNET_free (message_buf);
4304 * Check if the given address is already being validated; if not,
4305 * append the given address to the list of entries that are being be
4306 * validated and initiate validation.
4308 * @param cls closure ('struct CheckHelloValidatedContext *')
4309 * @param tname name of the transport
4310 * @param expiration expiration time
4311 * @param addr the address
4312 * @param addrlen length of the address
4313 * @return GNUNET_OK (always)
4316 run_validation (void *cls,
4318 struct GNUNET_TIME_Absolute expiration,
4319 const void *addr, uint16_t addrlen)
4321 struct CheckHelloValidatedContext *chvc = cls;
4322 struct GNUNET_PeerIdentity id;
4323 struct TransportPlugin *tp;
4324 struct ValidationEntry *va;
4325 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4326 struct CheckAddressExistsClosure caec;
4327 struct OwnAddressList *oal;
4329 GNUNET_assert (addr != NULL);
4331 GNUNET_STATISTICS_update (stats,
4333 ("# peer addresses scheduled for validation"), 1,
4335 tp = find_transport (tname);
4338 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4339 GNUNET_ERROR_TYPE_BULK,
4341 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4343 GNUNET_STATISTICS_update (stats,
4345 ("# peer addresses not validated (plugin not available)"),
4349 /* check if this is one of our own addresses */
4350 oal = tp->addresses;
4353 if ((oal->addrlen == addrlen) && (0 == memcmp (&oal[1], addr, addrlen)))
4355 /* not plausible, this address is equivalent to our own address! */
4356 GNUNET_STATISTICS_update (stats,
4358 ("# peer addresses not validated (loopback)"),
4364 GNUNET_HELLO_get_key (chvc->hello, &pk);
4365 GNUNET_CRYPTO_hash (&pk,
4367 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4370 if (is_blacklisted (&id, tp))
4373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4374 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4375 GNUNET_i2s (&id), tname);
4381 caec.addrlen = addrlen;
4382 caec.session = NULL;
4384 caec.exists = GNUNET_NO;
4385 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4386 &check_address_exists, &caec);
4387 if (caec.exists == GNUNET_YES)
4389 /* During validation attempts we will likely trigger the other
4390 * peer trying to validate our address which in turn will cause
4391 * it to send us its HELLO, so we expect to hit this case rather
4392 * frequently. Only print something if we are very verbose. */
4393 #if DEBUG_TRANSPORT > 1
4394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4395 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4396 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id));
4398 GNUNET_STATISTICS_update (stats,
4400 ("# peer addresses not validated (in progress)"),
4404 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4407 va->transport_name = GNUNET_strdup (tname);
4408 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4410 va->send_time = GNUNET_TIME_absolute_get ();
4411 va->addr = (const void *) &va[1];
4412 memcpy (&va[1], addr, addrlen);
4413 va->addrlen = addrlen;
4414 GNUNET_HELLO_get_key (chvc->hello, &va->publicKey);
4415 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4416 &timeout_hello_validation,
4418 GNUNET_CONTAINER_multihashmap_put (validation_map,
4421 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4422 setup_peer_check_blacklist (&id, GNUNET_NO, &transmit_hello_and_ping, va);
4428 * Check if addresses in validated hello "h" overlap with
4429 * those in "chvc->hello" and validate the rest.
4431 * @param cls closure
4432 * @param peer id of the peer, NULL for last call
4433 * @param h hello message for the peer (can be NULL)
4434 * @param err_msg NULL if successful, otherwise contains error message
4437 check_hello_validated (void *cls,
4438 const struct GNUNET_PeerIdentity *peer,
4439 const struct GNUNET_HELLO_Message *h,
4440 const char *err_msg)
4442 struct CheckHelloValidatedContext *chvc = cls;
4443 struct GNUNET_HELLO_Message *plain_hello;
4444 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4445 struct GNUNET_PeerIdentity target;
4446 struct NeighbourMapEntry *n;
4448 if (err_msg != NULL)
4451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4452 _("Error in communication with PEERINFO service: %s\n"),
4460 GNUNET_STATISTICS_update (stats,
4462 ("# outstanding peerinfo iterate requests"), -1,
4465 if (GNUNET_NO == chvc->hello_known)
4467 /* notify PEERINFO about the peer now, so that we at least
4468 * have the public key if some other component needs it */
4469 GNUNET_HELLO_get_key (chvc->hello, &pk);
4470 GNUNET_CRYPTO_hash (&pk,
4472 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4473 &target.hashPubKey);
4474 plain_hello = GNUNET_HELLO_create (&pk, NULL, NULL);
4475 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4476 GNUNET_free (plain_hello);
4477 #if DEBUG_TRANSPORT_HELLO
4478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4479 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4480 "HELLO", GNUNET_i2s (&target));
4482 GNUNET_STATISTICS_update (stats,
4484 ("# new HELLOs requiring full validation"), 1,
4486 GNUNET_HELLO_iterate_addresses (chvc->hello, GNUNET_NO, &run_validation,
4491 GNUNET_STATISTICS_update (stats,
4492 gettext_noop ("# duplicate HELLO (peer known)"),
4496 if (chvc->ve_count == 0)
4498 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
4505 #if DEBUG_TRANSPORT_HELLO
4506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4507 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4508 "HELLO", GNUNET_i2s (peer));
4510 chvc->hello_known = GNUNET_YES;
4511 n = find_neighbour (peer);
4514 #if DEBUG_TRANSPORT_HELLO
4515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4516 "Calling hello_iterate_addresses for %s!\n", GNUNET_i2s (peer));
4518 GNUNET_HELLO_iterate_addresses (h,
4519 GNUNET_NO, &add_to_foreign_address_list, n);
4520 try_transmission_to_peer (n);
4524 #if DEBUG_TRANSPORT_HELLO
4525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4526 "No existing neighbor record for %s!\n", GNUNET_i2s (peer));
4528 GNUNET_STATISTICS_update (stats,
4530 ("# no existing neighbour record (validating HELLO)"),
4533 GNUNET_STATISTICS_update (stats,
4534 gettext_noop ("# HELLO validations (update case)"),
4536 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4538 GNUNET_TIME_relative_to_absolute
4539 (HELLO_REVALIDATION_START_TIME),
4540 &run_validation, chvc);
4545 * Process HELLO-message.
4547 * @param plugin transport involved, may be NULL
4548 * @param message the actual message
4549 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4552 process_hello (struct TransportPlugin *plugin,
4553 const struct GNUNET_MessageHeader *message)
4556 struct GNUNET_PeerIdentity target;
4557 const struct GNUNET_HELLO_Message *hello;
4558 struct CheckHelloValidatedContext *chvc;
4559 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4560 struct NeighbourMapEntry *n;
4562 #if DEBUG_TRANSPORT_HELLO > 2
4566 hsize = ntohs (message->size);
4567 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4568 (hsize < sizeof (struct GNUNET_MessageHeader)))
4571 return GNUNET_SYSERR;
4573 GNUNET_STATISTICS_update (stats,
4574 gettext_noop ("# HELLOs received for validation"),
4577 hello = (const struct GNUNET_HELLO_Message *) message;
4578 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4580 #if DEBUG_TRANSPORT_HELLO
4581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4582 "Unable to get public key from `%s' for `%4s'!\n",
4583 "HELLO", GNUNET_i2s (&target));
4585 GNUNET_break_op (0);
4586 return GNUNET_SYSERR;
4588 GNUNET_CRYPTO_hash (&publicKey,
4589 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4590 &target.hashPubKey);
4592 #if DEBUG_TRANSPORT_HELLO
4593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4594 "Received `%s' message for `%4s'\n",
4595 "HELLO", GNUNET_i2s (&target));
4597 if (0 == memcmp (&my_identity, &target, sizeof (struct GNUNET_PeerIdentity)))
4599 GNUNET_STATISTICS_update (stats,
4601 ("# HELLOs ignored for validation (is my own HELLO)"),
4605 n = find_neighbour (&target);
4606 if ((NULL != n) && (!n->public_key_valid))
4608 GNUNET_HELLO_get_key (hello, &n->publicKey);
4609 n->public_key_valid = GNUNET_YES;
4612 /* check if load is too high before doing expensive stuff */
4613 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) >
4616 GNUNET_STATISTICS_update (stats,
4618 ("# HELLOs ignored due to high load"), 1,
4620 #if DEBUG_TRANSPORT_HELLO
4621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4622 "Ignoring `%s' for `%4s', load too high.\n",
4623 "HELLO", GNUNET_i2s (&target));
4630 while (NULL != chvc)
4632 if (GNUNET_HELLO_equals (hello,
4634 GNUNET_TIME_absolute_get ()).abs_value > 0)
4636 #if DEBUG_TRANSPORT_HELLO > 2
4637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4638 "Received duplicate `%s' message for `%4s'; ignored\n",
4639 "HELLO", GNUNET_i2s (&target));
4641 return GNUNET_OK; /* validation already pending */
4643 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4644 GNUNET_break (0 != memcmp (hello, chvc->hello,
4645 GNUNET_HELLO_size (hello)));
4650 struct NeighbourMapEntry *temp_neighbor = find_neighbour (&target);
4652 if ((NULL != temp_neighbor))
4654 fprintf (stderr, "Already know peer, ignoring hello\n");
4659 #if DEBUG_TRANSPORT_HELLO > 2
4663 my_id = GNUNET_strdup (GNUNET_i2s (plugin->env.my_identity));
4664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4665 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4668 GNUNET_i2s (&target),
4669 plugin->short_name, GNUNET_HELLO_size (hello));
4670 GNUNET_free (my_id);
4674 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4676 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4677 memcpy (&chvc[1], hello, hsize);
4678 GNUNET_CONTAINER_DLL_insert (chvc_head, chvc_tail, chvc);
4679 /* finally, check if HELLO was previously validated
4680 * (continuation will then schedule actual validation) */
4681 GNUNET_STATISTICS_update (stats,
4683 ("# peerinfo process hello iterate requests"), 1,
4685 GNUNET_STATISTICS_update (stats,
4687 ("# outstanding peerinfo iterate requests"), 1,
4690 GNUNET_PEERINFO_iterate (peerinfo, &target, HELLO_VERIFICATION_TIMEOUT,
4691 &check_hello_validated, chvc);
4697 * The peer specified by the given neighbour has timed-out or a plugin
4698 * has disconnected. We may either need to do nothing (other plugins
4699 * still up), or trigger a full disconnect and clean up. This
4700 * function updates our state and does the necessary notifications.
4701 * Also notifies our clients that the neighbour is now officially
4704 * @param n the neighbour list entry for the peer
4705 * @param check GNUNET_YES to check if ALL addresses for this peer
4706 * are gone, GNUNET_NO to force a disconnect of the peer
4707 * regardless of whether other addresses exist.
4710 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4712 struct ReadyList *rpos;
4713 struct MessageQueue *mq;
4714 struct ForeignAddressList *peer_addresses;
4715 struct ForeignAddressList *peer_pos;
4717 if (GNUNET_YES == n->in_disconnect)
4719 if (GNUNET_YES == check)
4722 while (NULL != rpos)
4724 peer_addresses = rpos->addresses;
4725 while (peer_addresses != NULL)
4727 /* Do not disconnect if: an address is connected or an inbound address exists */
4728 if ((GNUNET_YES == peer_addresses->connected) ||
4729 (peer_addresses->addrlen == 0))
4732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4733 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4734 GNUNET_i2s (&n->id),
4735 a2s (peer_addresses->ready_list->plugin->short_name,
4736 peer_addresses->addr, peer_addresses->addrlen));
4738 return; /* still connected */
4740 peer_addresses = peer_addresses->next;
4746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4747 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
4749 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4751 /* notify all clients about disconnect */
4752 if (GNUNET_YES == n->received_pong)
4754 n->received_pong = GNUNET_NO;
4755 notify_clients_disconnect (&n->id);
4758 ats_modify_problem_state (ats, ATS_MODIFIED);
4760 /* clean up all plugins, cancel connections and pending transmissions */
4761 while (NULL != (rpos = n->plugins))
4763 n->plugins = rpos->next;
4764 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4765 while (rpos->addresses != NULL)
4767 peer_pos = rpos->addresses;
4768 rpos->addresses = peer_pos->next;
4769 if (peer_pos->connected == GNUNET_YES)
4771 GNUNET_STATISTICS_update (stats,
4772 gettext_noop ("# connected addresses"),
4774 peer_pos->connected = GNUNET_NO;
4776 if (GNUNET_YES == peer_pos->validated)
4777 GNUNET_STATISTICS_update (stats,
4779 ("# peer addresses considered valid"), -1,
4781 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4783 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4784 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4786 GNUNET_free (peer_pos->ressources);
4787 peer_pos->ressources = NULL;
4788 GNUNET_free (peer_pos->quality);
4789 peer_pos->ressources = NULL;
4790 GNUNET_free (peer_pos);
4795 /* free all messages on the queue */
4796 while (NULL != (mq = n->messages_head))
4798 GNUNET_STATISTICS_update (stats,
4800 ("# bytes in message queue for other peers"),
4801 -(int64_t) mq->message_buf_size, GNUNET_NO);
4802 GNUNET_STATISTICS_update (stats,
4804 ("# bytes discarded due to disconnect"),
4805 mq->message_buf_size, GNUNET_NO);
4806 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
4807 GNUNET_assert (0 == memcmp (&mq->neighbour_id,
4808 &n->id, sizeof (struct GNUNET_PeerIdentity)));
4812 while (NULL != (mq = n->cont_head))
4815 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
4816 GNUNET_assert (0 == memcmp (&mq->neighbour_id,
4817 &n->id, sizeof (struct GNUNET_PeerIdentity)));
4821 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4823 GNUNET_SCHEDULER_cancel (n->timeout_task);
4824 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4826 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4828 GNUNET_SCHEDULER_cancel (n->retry_task);
4829 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4831 if (n->piter != NULL)
4833 GNUNET_PEERINFO_iterate_cancel (n->piter);
4834 GNUNET_STATISTICS_update (stats,
4836 ("# outstanding peerinfo iterate requests"), -1,
4841 GNUNET_assert (GNUNET_OK ==
4842 GNUNET_CONTAINER_multihashmap_remove (neighbours,
4843 &n->id.hashPubKey, n));
4844 /* finally, free n itself */
4845 GNUNET_STATISTICS_update (stats,
4846 gettext_noop ("# active neighbours"),
4848 GNUNET_free_non_null (n->pre_connect_message_buffer);
4854 * We have received a PING message from someone. Need to send a PONG message
4855 * in response to the peer by any means necessary.
4858 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4859 const struct GNUNET_PeerIdentity *peer,
4860 struct Session *session,
4861 const char *sender_address, uint16_t sender_address_len)
4863 struct TransportPlugin *plugin = cls;
4864 struct SessionHeader *session_header = (struct SessionHeader *) session;
4865 struct TransportPingMessage *ping;
4866 struct TransportPongMessage *pong;
4867 struct NeighbourMapEntry *n;
4868 struct ReadyList *rl;
4869 struct ForeignAddressList *fal;
4870 struct OwnAddressList *oal;
4876 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4878 GNUNET_break_op (0);
4879 return GNUNET_SYSERR;
4882 ping = (struct TransportPingMessage *) message;
4883 if (0 != memcmp (&ping->target,
4884 plugin->env.my_identity,
4885 sizeof (struct GNUNET_PeerIdentity)))
4888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4890 ("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4891 "PING", (sender_address != NULL) ? a2s (plugin->short_name,
4892 (const struct sockaddr
4894 sender_address_len) :
4895 "<inbound>", GNUNET_i2s (&ping->target));
4897 return GNUNET_SYSERR;
4900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4901 "Processing `%s' from `%s'\n",
4903 (sender_address != NULL)
4904 ? a2s (plugin->short_name,
4905 (const struct sockaddr *) sender_address,
4906 sender_address_len) : "<inbound>");
4908 GNUNET_STATISTICS_update (stats,
4909 gettext_noop ("# PING messages received"),
4911 addr = (const char *) &ping[1];
4912 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4913 slen = strlen (plugin->short_name) + 1;
4916 /* peer wants to confirm that we have an outbound connection to him */
4917 if (session == NULL)
4919 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4921 ("Refusing to create PONG since I do not have a session with `%s'.\n"),
4923 return GNUNET_SYSERR;
4925 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4926 * 1) it is NULL when we need to have a real value
4927 * 2) it is documented to be the address of the sender (source-IP), where
4928 * what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4932 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4933 a2s (plugin->short_name,
4934 sender_address, sender_address_len), GNUNET_i2s (peer));
4937 GNUNET_malloc (sizeof (struct TransportPongMessage) +
4938 sender_address_len + slen);
4940 htons (sizeof (struct TransportPongMessage) + sender_address_len +
4942 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4943 pong->purpose.size =
4944 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4946 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4947 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4948 pong->purpose.purpose =
4949 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4950 pong->challenge = ping->challenge;
4951 pong->addrlen = htonl (sender_address_len + slen);
4952 memcpy (&pong->pid, peer, sizeof (struct GNUNET_PeerIdentity));
4953 memcpy (&pong[1], plugin->short_name, slen);
4954 if ((sender_address != NULL) && (sender_address_len > 0))
4955 memcpy (&((char *) &pong[1])[slen], sender_address, sender_address_len);
4956 if (GNUNET_TIME_absolute_get_remaining
4957 (session_header->pong_sig_expires).rel_value <
4958 PONG_SIGNATURE_LIFETIME.rel_value / 4)
4960 /* create / update cached sig */
4962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4963 "Creating PONG signature to indicate active connection.\n");
4965 session_header->pong_sig_expires =
4966 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4968 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4969 GNUNET_assert (GNUNET_OK ==
4970 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4971 &session_header->pong_signature));
4976 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4978 memcpy (&pong->signature,
4979 &session_header->pong_signature,
4980 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4986 /* peer wants to confirm that this is one of our addresses */
4989 if (GNUNET_OK != plugin->api->check_address (plugin->api->cls, addr, alen))
4991 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4993 ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4994 a2s (plugin->short_name, addr, alen));
4997 oal = plugin->addresses;
5000 if ((oal->addrlen == alen) && (0 == memcmp (addr, &oal[1], alen)))
5004 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5006 htons (sizeof (struct TransportPongMessage) + alen + slen);
5007 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5008 pong->purpose.size =
5009 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5011 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5012 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5013 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5014 pong->challenge = ping->challenge;
5015 pong->addrlen = htonl (alen + slen);
5016 memcpy (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity));
5017 memcpy (&pong[1], plugin->short_name, slen);
5018 memcpy (&((char *) &pong[1])[slen], addr, alen);
5019 if ((oal != NULL) &&
5020 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value <
5021 PONG_SIGNATURE_LIFETIME.rel_value / 4))
5023 /* create / update cached sig */
5025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5026 "Creating PONG signature to indicate ownership.\n");
5028 oal->pong_sig_expires =
5029 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5030 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5031 GNUNET_assert (GNUNET_OK ==
5032 GNUNET_CRYPTO_rsa_sign (my_private_key,
5034 &oal->pong_signature));
5035 memcpy (&pong->signature,
5036 &oal->pong_signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
5038 else if (oal == NULL)
5040 /* not using cache (typically DV-only) */
5042 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
5043 (PONG_SIGNATURE_LIFETIME));
5044 GNUNET_assert (GNUNET_OK ==
5045 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
5050 /* can used cached version */
5051 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5052 memcpy (&pong->signature,
5053 &oal->pong_signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
5056 n = find_neighbour (peer);
5057 GNUNET_assert (n != NULL);
5058 did_pong = GNUNET_NO;
5059 /* first try reliable response transmission */
5063 fal = rl->addresses;
5066 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5068 (const char *) pong,
5069 ntohs (pong->header.size),
5070 TRANSPORT_PONG_PRIORITY,
5071 HELLO_VERIFICATION_TIMEOUT,
5074 fal->addrlen, GNUNET_SYSERR, NULL, NULL))
5076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5077 "Transmitted PONG to `%s' via reliable mechanism\n",
5080 GNUNET_STATISTICS_update (stats,
5082 ("# PONGs unicast via reliable transport"), 1,
5087 did_pong = GNUNET_YES;
5092 /* no reliable method found, do multicast */
5093 GNUNET_STATISTICS_update (stats,
5095 ("# PONGs multicast to all available addresses"), 1,
5100 fal = rl->addresses;
5103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5104 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5106 a2s (rl->plugin->short_name,
5107 fal->addr, fal->addrlen), rl->plugin->short_name);
5108 transmit_to_peer (NULL, fal,
5109 TRANSPORT_PONG_PRIORITY,
5110 HELLO_VERIFICATION_TIMEOUT,
5111 (const char *) pong,
5112 ntohs (pong->header.size), GNUNET_YES, n);
5113 did_pong = GNUNET_YES;
5119 if (GNUNET_YES != did_pong)
5120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5121 _("Could not send PONG to `%s': no address available\n"),
5128 * Function called by the plugin for each received message. Update
5129 * data volumes, possibly notify plugins about reducing the rate at
5130 * which they read from the socket and generally forward to our
5133 * @param cls the "struct TransportPlugin *" we gave to the plugin
5134 * @param peer (claimed) identity of the other peer
5135 * @param message the message, NULL if we only care about
5136 * learning about the delay until we should receive again
5137 * @param ats_data information for automatic transport selection
5138 * @param ats_count number of elements in ats not including 0-terminator
5139 * @param session identifier used for this session (can be NULL)
5140 * @param sender_address binary address of the sender (if observed)
5141 * @param sender_address_len number of bytes in sender_address
5142 * @return how long in ms the plugin should wait until receiving more data
5143 * (plugins that do not support this, can ignore the return value)
5145 static struct GNUNET_TIME_Relative
5146 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5147 const struct GNUNET_MessageHeader *message,
5148 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5150 struct Session *session,
5151 const char *sender_address, uint16_t sender_address_len)
5153 struct TransportPlugin *plugin = cls;
5154 struct ReadyList *service_context;
5155 struct ForeignAddressList *peer_address;
5157 struct NeighbourMapEntry *n;
5158 struct GNUNET_TIME_Relative ret;
5162 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
5164 /* refuse to receive from myself */
5166 return GNUNET_TIME_UNIT_FOREVER_REL;
5168 if (is_blacklisted (peer, plugin))
5169 return GNUNET_TIME_UNIT_FOREVER_REL;
5170 n = find_neighbour (peer);
5172 n = setup_new_neighbour (peer, GNUNET_YES);
5173 service_context = n->plugins;
5174 while ((service_context != NULL) && (plugin != service_context->plugin))
5175 service_context = service_context->next;
5176 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5177 peer_address = NULL;
5180 for (c = 0; c < ats_count; c++)
5181 if (ntohl (ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5182 distance = ntohl (ats_data[c].value);
5185 if (message != NULL)
5187 if ((session != NULL) || (sender_address != NULL))
5188 peer_address = add_peer_address (n,
5191 sender_address, sender_address_len);
5192 if (peer_address != NULL)
5194 update_addr_ats (peer_address, ats_data, ats_count);
5195 update_addr_value (peer_address, distance,
5196 GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5198 peer_address->distance = distance;
5199 if (GNUNET_YES == peer_address->validated)
5201 mark_address_connected (peer_address);
5202 schedule_next_ping (peer_address);
5207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5208 "New address is unvalidated, trying to validate it now\n");
5210 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5212 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5213 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5215 peer_address->revalidate_task =
5216 GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5219 peer_address->timeout
5221 GNUNET_TIME_relative_to_absolute
5222 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5224 /* update traffic received amount ... */
5225 msize = ntohs (message->size);
5227 GNUNET_STATISTICS_update (stats,
5229 ("# bytes received from other peers"), msize,
5231 n->distance = distance;
5233 GNUNET_TIME_relative_to_absolute
5234 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5235 GNUNET_SCHEDULER_cancel (n->timeout_task);
5237 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5238 &neighbour_timeout_task, n);
5239 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5241 /* dropping message due to frequent inbound volume violations! */
5242 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5243 GNUNET_ERROR_TYPE_BULK,
5245 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5246 n->in_tracker.available_bytes_per_s__,
5247 n->quota_violation_count);
5248 GNUNET_STATISTICS_update (stats,
5250 ("# bandwidth quota violations by other peers"),
5252 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5254 if ((ntohs (message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5255 (ntohs (message->size) ==
5256 (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5259 uint32_t value = ntohl (*((uint32_t *) & message[1]));
5261 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5262 /* Force ressource and quality update */
5263 if ((value == 4) && (ats != NULL))
5264 ats_modify_problem_state (ats, ATS_QUALITY_COST_UPDATED);
5265 /* Force cost update */
5266 if ((value == 3) && (ats != NULL))
5267 ats_modify_problem_state (ats, ATS_COST_UPDATED);
5268 /* Force quality update */
5269 if ((value == 2) && (ats != NULL))
5270 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
5271 /* Force full rebuild */
5272 if ((value == 1) && (ats != NULL))
5273 ats_modify_problem_state (ats, ATS_MODIFIED);
5278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5279 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5280 ntohs (message->type),
5281 ntohs (message->size), GNUNET_i2s (peer));
5283 switch (ntohs (message->type))
5285 case GNUNET_MESSAGE_TYPE_HELLO:
5286 GNUNET_STATISTICS_update (stats,
5288 ("# HELLO messages received from other peers"),
5290 process_hello (plugin, message);
5292 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5293 handle_ping (plugin, message, peer, session, sender_address,
5294 sender_address_len);
5295 if (GNUNET_YES != n->received_pong)
5296 transmit_plain_ping (n);
5298 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5299 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5301 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5304 handle_payload_message (message, n);
5308 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5309 if (ret.rel_value > 0)
5312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5313 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5314 (unsigned long long) n->
5315 in_tracker.consumption_since_last_update__,
5316 (unsigned int) n->in_tracker.available_bytes_per_s__,
5317 (unsigned long long) ret.rel_value);
5319 GNUNET_STATISTICS_update (stats,
5320 gettext_noop ("# ms throttling suggested"),
5321 (int64_t) ret.rel_value, GNUNET_NO);
5328 notify_client_about_neighbour (void *cls,
5329 const GNUNET_HashCode * key, void *value)
5331 struct TransportClient *c = cls;
5332 struct NeighbourMapEntry *n = value;
5333 struct ConnectInfoMessage *cim;
5337 if (GNUNET_YES != n->received_pong)
5342 sizeof (struct ConnectInfoMessage) +
5343 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5344 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5345 cim = GNUNET_malloc (size);
5346 cim->header.size = htons (size);
5347 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5348 cim->ats_count = htonl (ats_count);
5349 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5350 (&(cim->ats))[2].value = htonl (0);
5351 if (GNUNET_YES == n->received_pong)
5353 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5354 (&cim->ats)[0].value = htonl (n->distance);
5355 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5356 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5358 transmit_to_client (c, &cim->header, GNUNET_NO);
5366 * Handle START-message. This is the first message sent to us
5367 * by any client which causes us to add it to our list.
5369 * @param cls closure (always NULL)
5370 * @param client identification of the client
5371 * @param message the actual message
5374 handle_start (void *cls,
5375 struct GNUNET_SERVER_Client *client,
5376 const struct GNUNET_MessageHeader *message)
5378 const struct StartMessage *start;
5379 struct TransportClient *c;
5381 start = (const struct StartMessage *) message;
5383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5384 "Received `%s' request from client\n", "START");
5389 if (c->client == client)
5391 /* client already on our list! */
5393 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5398 if ((GNUNET_NO != ntohl (start->do_check)) &&
5399 (0 != memcmp (&start->self,
5400 &my_identity, sizeof (struct GNUNET_PeerIdentity))))
5402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5404 ("Rejecting control connection from peer `%s', which is not me!\n"),
5405 GNUNET_i2s (&start->self));
5406 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5409 c = GNUNET_malloc (sizeof (struct TransportClient));
5413 if (our_hello != NULL)
5416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5417 "Sending our own `%s' to new client\n", "HELLO");
5419 transmit_to_client (c,
5420 (const struct GNUNET_MessageHeader *) our_hello,
5422 /* tell new client about all existing connections */
5423 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5424 ¬ify_client_about_neighbour, c);
5428 #if DEBUG_TRANSPORT_HELLO
5429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5430 "No HELLO created yet, will transmit HELLO to client later!\n");
5434 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5439 * Handle HELLO-message.
5441 * @param cls closure (always NULL)
5442 * @param client identification of the client
5443 * @param message the actual message
5446 handle_hello (void *cls,
5447 struct GNUNET_SERVER_Client *client,
5448 const struct GNUNET_MessageHeader *message)
5452 GNUNET_STATISTICS_update (stats,
5453 gettext_noop ("# HELLOs received from clients"),
5455 ret = process_hello (NULL, message);
5456 GNUNET_SERVER_receive_done (client, ret);
5461 * Closure for 'transmit_client_message'; followed by
5462 * 'msize' bytes of the actual message.
5464 struct TransmitClientMessageContext
5467 * Client on whom's behalf we are sending.
5469 struct GNUNET_SERVER_Client *client;
5472 * Timeout for the transmission.
5474 struct GNUNET_TIME_Absolute timeout;
5482 * Size of the message in bytes.
5489 * Schedule transmission of a message we got from a client to a peer.
5491 * @param cls the 'struct TransmitClientMessageContext*'
5492 * @param n destination, or NULL on error (in that case, drop the message)
5495 transmit_client_message (void *cls, struct NeighbourMapEntry *n)
5497 struct TransmitClientMessageContext *tcmc = cls;
5498 struct TransportClient *tc;
5501 while ((tc != NULL) && (tc->client != tcmc->client))
5506 transmit_to_peer (tc, NULL, tcmc->priority,
5507 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5508 (char *) &tcmc[1], tcmc->msize, GNUNET_NO, n);
5510 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5511 GNUNET_SERVER_client_drop (tcmc->client);
5517 * Handle SEND-message.
5519 * @param cls closure (always NULL)
5520 * @param client identification of the client
5521 * @param message the actual message
5524 handle_send (void *cls,
5525 struct GNUNET_SERVER_Client *client,
5526 const struct GNUNET_MessageHeader *message)
5528 const struct OutboundMessage *obm;
5529 const struct GNUNET_MessageHeader *obmm;
5530 struct TransmitClientMessageContext *tcmc;
5534 size = ntohs (message->size);
5536 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5539 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5542 GNUNET_STATISTICS_update (stats,
5543 gettext_noop ("# payload received for other peers"),
5545 obm = (const struct OutboundMessage *) message;
5546 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5547 msize = size - sizeof (struct OutboundMessage);
5549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5550 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5551 "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
5553 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5554 tcmc->client = client;
5555 tcmc->priority = ntohl (obm->priority);
5557 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh
5559 tcmc->msize = msize;
5560 /* FIXME: this memcpy can be up to 7% of our total runtime */
5561 memcpy (&tcmc[1], obmm, msize);
5562 GNUNET_SERVER_client_keep (client);
5563 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5564 &transmit_client_message, tcmc);
5569 * Handle request connect message
5571 * @param cls closure (always NULL)
5572 * @param client identification of the client
5573 * @param message the actual message
5576 handle_request_connect (void *cls,
5577 struct GNUNET_SERVER_Client *client,
5578 const struct GNUNET_MessageHeader *message)
5580 const struct TransportRequestConnectMessage *trcm =
5581 (const struct TransportRequestConnectMessage *) message;
5583 GNUNET_STATISTICS_update (stats,
5585 ("# REQUEST CONNECT messages received"), 1,
5588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5589 "Received a request connect message for peer `%s'\n",
5590 GNUNET_i2s (&trcm->peer));
5592 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES, NULL, NULL);
5593 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5598 * Handle SET_QUOTA-message.
5600 * @param cls closure (always NULL)
5601 * @param client identification of the client
5602 * @param message the actual message
5605 handle_set_quota (void *cls,
5606 struct GNUNET_SERVER_Client *client,
5607 const struct GNUNET_MessageHeader *message)
5609 const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message;
5610 struct NeighbourMapEntry *n;
5612 GNUNET_STATISTICS_update (stats,
5613 gettext_noop ("# SET QUOTA messages received"),
5615 n = find_neighbour (&qsm->peer);
5618 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5619 GNUNET_STATISTICS_update (stats,
5621 ("# SET QUOTA messages ignored (no such peer)"),
5626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5627 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5629 (unsigned int) ntohl (qsm->quota.value__),
5630 (unsigned int) n->in_tracker.available_bytes_per_s__,
5631 GNUNET_i2s (&qsm->peer));
5633 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, qsm->quota);
5634 if (0 == ntohl (qsm->quota.value__))
5637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5638 "Disconnecting peer `%4s', %s\n", GNUNET_i2s (&n->id),
5641 GNUNET_STATISTICS_update (stats,
5642 gettext_noop ("# disconnects due to quota of 0"),
5644 disconnect_neighbour (n, GNUNET_NO);
5646 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5651 * Take the given address and append it to the set of results sent back to
5654 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5655 * @param address the resolved name, NULL to indicate the last response
5658 transmit_address_to_client (void *cls, const char *address)
5660 struct GNUNET_SERVER_TransmitContext *tc = cls;
5663 if (NULL != address)
5665 slen = strlen (address) + 1;
5666 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5667 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5671 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5672 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5673 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5679 * Handle AddressLookup-message.
5681 * @param cls closure (always NULL)
5682 * @param client identification of the client
5683 * @param message the actual message
5686 handle_address_lookup (void *cls,
5687 struct GNUNET_SERVER_Client *client,
5688 const struct GNUNET_MessageHeader *message)
5690 const struct AddressLookupMessage *alum;
5691 struct TransportPlugin *lsPlugin;
5692 const char *nameTransport;
5693 const char *address;
5695 struct GNUNET_SERVER_TransmitContext *tc;
5696 struct GNUNET_TIME_Relative rtimeout;
5699 size = ntohs (message->size);
5700 if (size < sizeof (struct AddressLookupMessage))
5702 GNUNET_break_op (0);
5703 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5706 alum = (const struct AddressLookupMessage *) message;
5707 uint32_t addressLen = ntohl (alum->addrlen);
5709 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5711 GNUNET_break_op (0);
5712 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5715 address = (const char *) &alum[1];
5716 nameTransport = (const char *) &address[addressLen];
5718 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5720 GNUNET_break_op (0);
5721 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5724 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5725 numeric = ntohl (alum->numeric_only);
5726 lsPlugin = find_transport (nameTransport);
5727 if (NULL == lsPlugin)
5729 tc = GNUNET_SERVER_transmit_context_create (client);
5730 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5731 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5732 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5735 GNUNET_SERVER_disable_receive_done_warning (client);
5736 tc = GNUNET_SERVER_transmit_context_create (client);
5737 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5739 address, addressLen,
5742 &transmit_address_to_client, tc);
5746 * Handle PeerAddressLookupMessage.
5748 * @param cls closure (always NULL)
5749 * @param client identification of the client
5750 * @param message the actual message
5753 handle_peer_address_lookup (void *cls,
5754 struct GNUNET_SERVER_Client *client,
5755 const struct GNUNET_MessageHeader *message)
5757 const struct PeerAddressLookupMessage *peer_address_lookup;
5758 struct NeighbourMapEntry *neighbor_iterator;
5759 struct ReadyList *ready_iterator;
5760 struct ForeignAddressList *foreign_address_iterator;
5761 struct TransportPlugin *transport_plugin;
5764 struct GNUNET_SERVER_TransmitContext *tc;
5765 struct GNUNET_TIME_Relative rtimeout;
5768 size = ntohs (message->size);
5769 if (size < sizeof (struct PeerAddressLookupMessage))
5771 GNUNET_break_op (0);
5772 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5775 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5777 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5779 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5781 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5782 if (neighbor_iterator == NULL)
5785 tc = GNUNET_SERVER_transmit_context_create (client);
5786 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5787 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5788 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5792 ready_iterator = neighbor_iterator->plugins;
5793 GNUNET_SERVER_disable_receive_done_warning (client);
5794 tc = GNUNET_SERVER_transmit_context_create (client);
5795 while (ready_iterator != NULL)
5797 foreign_address_iterator = ready_iterator->addresses;
5798 while (foreign_address_iterator != NULL)
5800 transport_plugin = foreign_address_iterator->ready_list->plugin;
5801 if (foreign_address_iterator->addr != NULL)
5803 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
5804 a2s (transport_plugin->short_name,
5805 foreign_address_iterator->addr,
5806 foreign_address_iterator->addrlen),
5807 (foreign_address_iterator->connected
5808 == GNUNET_YES) ? "CONNECTED"
5810 (foreign_address_iterator->validated
5811 == GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5812 transmit_address_to_client (tc, addr_buf);
5813 GNUNET_free (addr_buf);
5815 else if (foreign_address_iterator->addrlen == 0)
5817 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5818 (foreign_address_iterator->connected
5819 == GNUNET_YES) ? "CONNECTED"
5821 (foreign_address_iterator->validated
5822 == GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5823 transmit_address_to_client (tc, addr_buf);
5824 GNUNET_free (addr_buf);
5827 foreign_address_iterator = foreign_address_iterator->next;
5829 ready_iterator = ready_iterator->next;
5831 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5832 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5833 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5839 output_addresses (void *cls, const GNUNET_HashCode * key, void *value)
5841 struct GNUNET_SERVER_TransmitContext *tc = cls;
5842 struct NeighbourMapEntry *neighbor_iterator = value;
5843 struct ForeignAddressList *foreign_address_iterator;
5844 struct TransportPlugin *transport_plugin;
5845 struct ReadyList *ready_iterator;
5848 ready_iterator = neighbor_iterator->plugins;
5849 while (ready_iterator != NULL)
5851 foreign_address_iterator = ready_iterator->addresses;
5852 while (foreign_address_iterator != NULL)
5854 transport_plugin = foreign_address_iterator->ready_list->plugin;
5855 if (foreign_address_iterator->addr != NULL)
5857 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5858 GNUNET_i2s (&neighbor_iterator->id),
5859 a2s (transport_plugin->short_name,
5860 foreign_address_iterator->addr,
5861 foreign_address_iterator->addrlen),
5862 (foreign_address_iterator->connected
5863 == GNUNET_YES) ? "CONNECTED"
5865 (foreign_address_iterator->validated
5866 == GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5867 transmit_address_to_client (tc, addr_buf);
5868 GNUNET_free (addr_buf);
5870 else if (foreign_address_iterator->addrlen == 0)
5872 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5873 GNUNET_i2s (&neighbor_iterator->id),
5875 (foreign_address_iterator->connected
5876 == GNUNET_YES) ? "CONNECTED"
5878 (foreign_address_iterator->validated
5879 == GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5880 transmit_address_to_client (tc, addr_buf);
5881 GNUNET_free (addr_buf);
5884 foreign_address_iterator = foreign_address_iterator->next;
5886 ready_iterator = ready_iterator->next;
5893 * Handle AddressIterateMessage
5895 * @param cls closure (always NULL)
5896 * @param client identification of the client
5897 * @param message the actual message
5900 handle_address_iterate (void *cls,
5901 struct GNUNET_SERVER_Client *client,
5902 const struct GNUNET_MessageHeader *message)
5904 struct GNUNET_SERVER_TransmitContext *tc;
5907 size = ntohs (message->size);
5908 if (size < sizeof (struct AddressIterateMessage))
5910 GNUNET_break_op (0);
5911 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5914 GNUNET_SERVER_disable_receive_done_warning (client);
5915 tc = GNUNET_SERVER_transmit_context_create (client);
5916 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &output_addresses, tc);
5917 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5918 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5919 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5923 static const struct GNUNET_MessageHeader *
5926 return (const struct GNUNET_MessageHeader *) our_hello;
5931 * Setup the environment for this plugin.
5934 create_environment (struct TransportPlugin *plug)
5936 plug->env.cfg = cfg;
5937 plug->env.my_identity = &my_identity;
5938 plug->env.get_our_hello = &do_get_our_hello;
5939 plug->env.cls = plug;
5940 plug->env.receive = &plugin_env_receive;
5941 plug->env.notify_address = &plugin_env_notify_address;
5942 plug->env.session_end = &plugin_env_session_end;
5943 plug->env.max_connections = max_connect_per_transport;
5944 plug->env.stats = stats;
5949 * Start the specified transport (load the plugin).
5952 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
5954 struct TransportPlugin *plug;
5957 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5958 _("Loading `%s' transport plugin\n"), name);
5959 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5960 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5961 create_environment (plug);
5962 plug->short_name = GNUNET_strdup (name);
5963 plug->lib_name = libname;
5964 plug->next = plugins;
5966 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5967 if (plug->api == NULL)
5969 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5970 _("Failed to load transport plugin for `%s'\n"), name);
5971 GNUNET_free (plug->short_name);
5972 plugins = plug->next;
5973 GNUNET_free (libname);
5980 null_mq_client_pointers (void *cls, const GNUNET_HashCode * key, void *value)
5982 struct TransportClient *pos = cls;
5983 struct NeighbourMapEntry *n = value;
5984 struct MessageQueue *mq;
5986 for (mq = n->messages_head; mq != NULL; mq = mq->next)
5988 if (mq->client == pos)
5989 mq->client = NULL; /* do not use anymore! */
5996 * Called whenever a client is disconnected. Frees our
5997 * resources associated with that client.
5999 * @param cls closure
6000 * @param client identification of the client
6003 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
6005 struct TransportClient *pos;
6006 struct TransportClient *prev;
6007 struct ClientMessageQueueEntry *mqe;
6008 struct Blacklisters *bl;
6009 struct BlacklistCheck *bc;
6014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6015 "Client disconnected, cleaning up.\n");
6017 /* clean up blacklister */
6021 if (bl->client == client)
6026 if (bc->bl_pos == bl)
6028 bc->bl_pos = bl->next;
6031 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6034 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6035 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
6040 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
6041 GNUNET_SERVER_client_drop (bl->client);
6047 /* clean up 'normal' clients */
6050 while ((pos != NULL) && (pos->client != client))
6057 while (NULL != (mqe = pos->message_queue_head))
6059 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6060 pos->message_queue_tail, mqe);
6061 pos->message_count--;
6064 if (NULL != neighbours)
6065 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6066 &null_mq_client_pointers, pos);
6068 clients = pos->next;
6070 prev->next = pos->next;
6071 if (GNUNET_YES == pos->tcs_pending)
6076 if (pos->th != NULL)
6078 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6081 GNUNET_break (0 == pos->message_count);
6087 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
6089 struct NeighbourMapEntry *n = value;
6092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6093 "Disconnecting peer `%4s', %s\n",
6094 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
6096 disconnect_neighbour (n, GNUNET_NO);
6102 * Function called when the service shuts down. Unloads our plugins
6103 * and cancels pending validations.
6105 * @param cls closure, unused
6106 * @param tc task context (unused)
6109 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6111 struct TransportPlugin *plug;
6112 struct OwnAddressList *al;
6113 struct CheckHelloValidatedContext *chvc;
6115 shutdown_in_progress = GNUNET_YES;
6116 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6117 &disconnect_all_neighbours, NULL);
6119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6120 "Transport service is unloading plugins...\n");
6122 while (NULL != (plug = plugins))
6124 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6126 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6127 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6129 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6130 GNUNET_free (plug->lib_name);
6131 GNUNET_free (plug->short_name);
6132 while (NULL != (al = plug->addresses))
6134 plug->addresses = al->next;
6137 plugins = plug->next;
6140 if (my_private_key != NULL)
6141 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6142 GNUNET_free_non_null (our_hello);
6144 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6145 &abort_validation, NULL);
6146 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6147 validation_map = NULL;
6150 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6152 GNUNET_SCHEDULER_cancel (ats_task);
6153 ats_task = GNUNET_SCHEDULER_NO_TASK;
6160 /* free 'chvc' data structure */
6161 while (NULL != (chvc = chvc_head))
6163 chvc_head = chvc->next;
6164 if (chvc->piter != NULL)
6166 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6167 GNUNET_STATISTICS_update (stats,
6169 ("# outstanding peerinfo iterate requests"), -1,
6175 GNUNET_assert (chvc->ve_count == 0);
6182 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6185 if (peerinfo != NULL)
6187 GNUNET_PEERINFO_disconnect (peerinfo);
6190 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6192 GNUNET_SCHEDULER_cancel (hello_task);
6193 hello_task = GNUNET_SCHEDULER_NO_TASK;
6195 /* Can we assume those are gone by now, or do we need to clean up
6197 GNUNET_break (bl_head == NULL);
6198 GNUNET_break (bc_head == NULL);
6199 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS Result callback\n");
6212 struct AtsBuildContext
6214 struct ATS_mechanism *mechanisms;
6215 struct ATS_peer *peers;
6222 find_and_count_addresses (void *cls, const GNUNET_HashCode * key, void *value)
6224 struct AtsBuildContext *abc = cls;
6225 struct NeighbourMapEntry *next = value;
6226 int found_addresses = GNUNET_NO;
6228 struct ReadyList *r_next = next->plugins;
6230 while (r_next != NULL)
6232 struct ForeignAddressList *a_next = r_next->addresses;
6234 while (a_next != NULL)
6237 found_addresses = GNUNET_YES;
6238 a_next = a_next->next;
6240 r_next = r_next->next;
6242 if (found_addresses)
6249 setup_ats_problem (void *cls, const GNUNET_HashCode * key, void *value)
6251 struct AtsBuildContext *abc = cls;
6252 struct NeighbourMapEntry *next = value;
6254 int found_addresses = GNUNET_NO;
6255 struct ReadyList *r_next = next->plugins;
6257 while (r_next != NULL)
6259 struct ForeignAddressList *a_next = r_next->addresses;
6261 while (a_next != NULL)
6263 if (found_addresses == GNUNET_NO)
6265 abc->peers[abc->c_peers].peer = next->id;
6266 abc->peers[abc->c_peers].m_head = NULL;
6267 abc->peers[abc->c_peers].m_tail = NULL;
6268 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6270 abc->mechanisms[abc->c_mechs].addr = a_next;
6271 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6272 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6273 abc->mechanisms[abc->c_mechs].next = NULL;
6274 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6275 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6276 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6277 GNUNET_CONTAINER_DLL_insert_tail (abc->peers[abc->c_peers].m_head,
6278 abc->peers[abc->c_peers].m_tail,
6279 &abc->mechanisms[abc->c_mechs]);
6280 found_addresses = GNUNET_YES;
6282 a_next = a_next->next;
6284 r_next = r_next->next;
6286 if (found_addresses == GNUNET_YES)
6293 create_ats_information (struct ATS_peer **p,
6294 int *c_p, struct ATS_mechanism **m, int *c_m)
6296 struct AtsBuildContext abc;
6299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6300 "ATS requires clean address information\n");
6304 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
6305 &find_and_count_addresses, &abc);
6307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6308 "Found %u peers with % u transport mechanisms\n", c_peers,
6312 if ((abc.c_peers == 0) && (abc.c_mechs == 0))
6322 GNUNET_malloc ((1 + abc.c_mechs) * sizeof (struct ATS_mechanism));
6323 abc.peers = GNUNET_malloc ((1 + abc.c_peers) * sizeof (struct ATS_peer));
6326 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &setup_ats_problem, &abc);
6329 (*c_m) = abc.c_mechs;
6330 (*c_p) = abc.c_peers;
6332 (*m) = abc.mechanisms;
6337 schedule_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6339 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6344 ats_task = GNUNET_SCHEDULER_NO_TASK;
6345 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6348 if (shutdown_in_progress == GNUNET_YES)
6351 struct GNUNET_TIME_Relative delta =
6352 GNUNET_TIME_absolute_get_difference (last_ats_execution,
6353 GNUNET_TIME_absolute_get ());
6355 if (delta.rel_value < ats_minimum_interval.rel_value)
6358 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6359 "Minimum time between cycles not reached\n");
6365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6368 ats_calculate_bandwidth_distribution (ats);
6370 last_ats_execution = GNUNET_TIME_absolute_get ();
6372 ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6373 &schedule_ats, ats);
6378 struct ForeignAddressList *
6379 get_preferred_ats_address (struct NeighbourMapEntry *n)
6381 // TODO get ATS prefered address
6382 return find_ready_address (n);
6386 * Initiate transport service.
6388 * @param cls closure
6389 * @param server the initialized server
6390 * @param c configuration to use
6394 struct GNUNET_SERVER_Handle *server,
6395 const struct GNUNET_CONFIGURATION_Handle *c)
6397 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6398 {&handle_start, NULL,
6399 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6400 {&handle_hello, NULL,
6401 GNUNET_MESSAGE_TYPE_HELLO, 0},
6402 {&handle_send, NULL,
6403 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6404 {&handle_request_connect, NULL,
6405 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
6406 sizeof (struct TransportRequestConnectMessage)},
6407 {&handle_set_quota, NULL,
6408 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6409 {&handle_address_lookup, NULL,
6410 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6412 {&handle_peer_address_lookup, NULL,
6413 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6415 {&handle_address_iterate, NULL,
6416 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6418 {&handle_blacklist_init, NULL,
6419 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
6420 sizeof (struct GNUNET_MessageHeader)},
6421 {&handle_blacklist_reply, NULL,
6422 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
6423 sizeof (struct BlacklistMessage)},
6429 unsigned long long tneigh;
6432 shutdown_in_progress = GNUNET_NO;
6434 stats = GNUNET_STATISTICS_create ("transport", cfg);
6435 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6436 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6437 /* parse configuration */
6439 GNUNET_CONFIGURATION_get_value_number (c,
6444 GNUNET_CONFIGURATION_get_value_filename (c,
6446 "HOSTKEY", &keyfile)))
6448 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6450 ("Transport service is lacking key configuration settings. Exiting.\n"));
6451 GNUNET_SCHEDULER_shutdown ();
6454 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6457 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6458 validation_map = NULL;
6459 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6464 max_connect_per_transport = (uint32_t) tneigh;
6465 peerinfo = GNUNET_PEERINFO_connect (cfg);
6466 if (peerinfo == NULL)
6468 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6469 _("Could not access PEERINFO service. Exiting.\n"));
6470 GNUNET_SCHEDULER_shutdown ();
6473 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6476 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6477 validation_map = NULL;
6478 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6480 GNUNET_free (keyfile);
6483 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6484 GNUNET_free (keyfile);
6485 if (my_private_key == NULL)
6487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6488 _("Transport service could not access hostkey. Exiting.\n"));
6489 GNUNET_SCHEDULER_shutdown ();
6492 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6495 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6496 validation_map = NULL;
6497 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6501 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6502 GNUNET_CRYPTO_hash (&my_public_key,
6503 sizeof (my_public_key), &my_identity.hashPubKey);
6504 /* setup notification */
6505 GNUNET_SERVER_disconnect_notify (server,
6506 &client_disconnect_notification, NULL);
6507 /* load plugins... */
6510 GNUNET_CONFIGURATION_get_value_string (c, "TRANSPORT", "PLUGINS", &plugs))
6512 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6513 _("Starting transport plugins `%s'\n"), plugs);
6514 pos = strtok (plugs, " ");
6517 start_transport (server, pos);
6519 pos = strtok (NULL, " ");
6521 GNUNET_free (plugs);
6523 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6524 &shutdown_task, NULL);
6528 /* Initializing ATS */
6531 unsigned long long value;
6537 int v_b_min = 64000;
6541 ats_minimum_interval = ATS_MIN_INTERVAL;
6542 ats_regular_interval = ATS_EXEC_INTERVAL;
6544 /* loading cost ressources */
6545 for (co = 0; co < available_ressources; co++)
6547 GNUNET_asprintf (§ion, "%s_UP", ressources[co].cfg_param);
6548 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6550 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg,
6555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6556 "Found ressource cost: [%s] = %llu\n", section, value);
6558 ressources[co].c_max = value;
6561 GNUNET_free (section);
6562 GNUNET_asprintf (§ion, "%s_DOWN", ressources[co].cfg_param);
6563 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6565 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg,
6570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6571 "Found ressource cost: [%s] = %llu\n", section, value);
6573 ressources[co].c_min = value;
6576 GNUNET_free (section);
6579 ats = ats_init (D, U, R, v_b_min, v_n_min,
6580 ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6581 &create_ats_information, ats_result_cb);
6582 ats_set_logging_options (ats, stats, cfg);
6583 GNUNET_break (GNUNET_OK ==
6584 GNUNET_CONFIGURATION_get_value_time (cfg,
6586 "ATS_EXEC_INTERVAL",
6587 &ats_regular_interval));
6588 GNUNET_break (GNUNET_OK ==
6589 GNUNET_CONFIGURATION_get_value_time (cfg,
6592 &ats_minimum_interval));
6594 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6599 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6601 /* If we have a blacklist file, read from it */
6602 read_blacklist_file (cfg);
6603 /* process client requests */
6604 GNUNET_SERVER_add_handlers (server, handlers);
6609 * The main function for the transport service.
6611 * @param argc number of arguments from the command line
6612 * @param argv command line arguments
6613 * @return 0 ok, 1 on error
6616 main (int argc, char *const *argv)
6618 a2s (NULL, NULL, 0); /* make compiler happy */
6619 return (GNUNET_OK ==
6620 GNUNET_SERVICE_run (argc,
6623 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
6626 /* end of gnunet-service-transport.c */