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
957 disconnect_neighbour (struct NeighbourMapEntry *n, int check);
960 * Check the ready list for the given neighbour and if a plugin is
961 * ready for transmission (and if we have a message), do so!
963 * @param nexi target peer for which to transmit
966 try_transmission_to_peer (struct NeighbourMapEntry *n);
968 struct ForeignAddressList *
969 get_preferred_ats_address (struct NeighbourMapEntry *n);
972 * Find an entry in the neighbour list for a particular peer.
974 * @return NULL if not found.
976 static struct NeighbourMapEntry *
977 find_neighbour (const struct GNUNET_PeerIdentity *key)
979 return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
983 update_addr_value (struct ForeignAddressList *fal, uint32_t value,
989 for (c = 0; c < available_quality_metrics; c++)
991 if (ats_index == qm[c].atis_index)
993 fal->quality[c].values[0] = fal->quality[c].values[1];
994 fal->quality[c].values[1] = fal->quality[c].values[2];
995 fal->quality[c].values[2] = value;
998 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1002 if (set == GNUNET_NO)
1004 for (c = 0; c < available_ressources; c++)
1006 if (ats_index == ressources[c].atis_index)
1008 fal->ressources[c].c = value;
1011 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1020 update_addr_ats (struct ForeignAddressList *fal,
1021 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1027 for (c1 = 0; c1 < ats_count; c1++)
1030 update_addr_value (fal, ntohl (ats_data[c1].value),
1031 ntohl (ats_data[c1].type));
1037 * Find an entry in the transport list for a particular transport.
1039 * @return NULL if not found.
1041 static struct TransportPlugin *
1042 find_transport (const char *short_name)
1044 struct TransportPlugin *head = plugins;
1046 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1052 * Is a particular peer blacklisted for a particular transport?
1054 * @param peer the peer to check for
1055 * @param plugin the plugin used to connect to the peer
1057 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1060 is_blacklisted (const struct GNUNET_PeerIdentity *peer,
1061 struct TransportPlugin *plugin)
1064 if (plugin->blacklist != NULL)
1066 if (GNUNET_CONTAINER_multihashmap_contains
1067 (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s:%s' is blacklisted!\n",
1071 plugin->short_name, GNUNET_i2s (peer));
1074 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1,
1085 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1087 struct TransportPlugin *plugin;
1089 plugin = find_transport (transport_name);
1090 if (plugin == NULL) /* Nothing to do */
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "Adding peer `%s' with plugin `%s' to blacklist\n",
1095 GNUNET_i2s (peer), transport_name);
1097 if (plugin->blacklist == NULL)
1099 GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE);
1100 GNUNET_assert (plugin->blacklist != NULL);
1101 GNUNET_CONTAINER_multihashmap_put (plugin->blacklist, &peer->hashPubKey, NULL,
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, "TRANSPORT",
1128 "BLACKLIST_FILE", &fn))
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Option `%s' in section `%s' not specified!\n",
1133 "BLACKLIST_FILE", "TRANSPORT");
1137 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1138 GNUNET_DISK_fn_write (fn, NULL, 0,
1139 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, _("Blacklist file `%s' is empty.\n"),
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));
1342 GNUNET_SERVER_notify_transmit_ready (client->client, msize,
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"), 1,
1424 GNUNET_CRYPTO_hash (&va->publicKey,
1425 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1427 GNUNET_break (GNUNET_OK ==
1428 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1429 &pid.hashPubKey, va));
1430 abort_validation (NULL, NULL, va);
1436 * Send the specified message to the specified client. Since multiple
1437 * messages may be pending for the same client at a time, this code
1438 * makes sure that no message is lost.
1440 * @param client client to transmit the message to
1441 * @param msg the message to send
1442 * @param may_drop can this message be dropped if the
1443 * message queue for this client is getting far too large?
1446 transmit_to_client (struct TransportClient *client,
1447 const struct GNUNET_MessageHeader *msg, int may_drop)
1449 struct ClientMessageQueueEntry *q;
1452 /* Client==NULL when GNUNET_SERVER_Client disconnected and was
1453 * freed in client_disconnect_notification
1455 if (client->client == NULL)
1461 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1463 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1465 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1466 ntohs (msg->type), ntohs (msg->size), client->message_count,
1468 GNUNET_STATISTICS_update (stats,
1470 ("# messages dropped due to slow client"), 1,
1474 msize = ntohs (msg->size);
1475 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1476 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1477 memcpy (&q[1], msg, msize);
1478 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1479 client->message_queue_tail, q);
1480 client->message_count++;
1481 if (client->th == NULL)
1484 GNUNET_SERVER_notify_transmit_ready (client->client, msize,
1485 GNUNET_TIME_UNIT_FOREVER_REL,
1486 &transmit_to_client_callback,
1488 GNUNET_assert (client->th != NULL);
1494 * Transmit a 'SEND_OK' notification to the given client for the
1497 * @param client who to notify
1498 * @param n neighbour to notify about, can be NULL (on failure)
1499 * @param target target of the transmission
1500 * @param result status code for the transmission request
1503 transmit_send_ok (struct TransportClient *client, struct NeighbourMapEntry *n,
1504 const struct GNUNET_PeerIdentity *target, int result)
1506 struct SendOkMessage send_ok_msg;
1508 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1509 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1510 send_ok_msg.success = htonl (result);
1512 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1514 send_ok_msg.latency =
1515 GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1516 send_ok_msg.peer = *target;
1517 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1522 * Mark the given FAL entry as 'connected' (and hence preferred for
1523 * sending); also mark all others for the same peer as 'not connected'
1524 * (since only one can be preferred).
1526 * @param fal address to set to 'connected'
1529 mark_address_connected (struct ForeignAddressList *fal);
1534 * We should re-try transmitting to the given peer,
1535 * hopefully we've learned something in the meantime.
1538 retry_transmission_task (void *cls,
1539 const struct GNUNET_SCHEDULER_TaskContext *tc)
1541 struct NeighbourMapEntry *n = cls;
1543 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1544 try_transmission_to_peer (n);
1549 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1550 * upon "completion" of a send request. This tells the API
1551 * that it is now legal to send another message to the given
1554 * @param cls closure, identifies the entry on the
1555 * message queue that was transmitted and the
1556 * client responsible for queuing the message
1557 * @param target the peer receiving the message
1558 * @param result GNUNET_OK on success, if the transmission
1559 * failed, we should not tell the client to transmit
1563 transmit_send_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
1566 struct MessageQueue *mq = cls;
1567 struct NeighbourMapEntry *n;
1569 GNUNET_STATISTICS_update (stats,
1570 gettext_noop ("# bytes pending with plugins"),
1571 -(int64_t) mq->message_buf_size, GNUNET_NO);
1572 if (result == GNUNET_OK)
1574 GNUNET_STATISTICS_update (stats,
1576 ("# bytes successfully transmitted by plugins"),
1577 mq->message_buf_size, GNUNET_NO);
1581 GNUNET_STATISTICS_update (stats,
1583 ("# bytes with transmission failure by plugins"),
1584 mq->message_buf_size, GNUNET_NO);
1586 if (mq->specific_address != NULL)
1588 if (result == GNUNET_OK)
1590 mq->specific_address->timeout =
1591 GNUNET_TIME_relative_to_absolute
1592 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1593 if (mq->specific_address->validated == GNUNET_YES)
1594 mark_address_connected (mq->specific_address);
1598 if (mq->specific_address->connected == GNUNET_YES)
1601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1602 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1603 a2s (mq->specific_address->ready_list->plugin->short_name,
1604 mq->specific_address->addr,
1605 mq->specific_address->addrlen));
1607 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1609 mq->specific_address->connected = GNUNET_NO;
1612 if (!mq->internal_msg)
1613 mq->specific_address->in_transmit = GNUNET_NO;
1615 n = find_neighbour (&mq->neighbour_id);
1618 if (mq->client != NULL)
1619 transmit_send_ok (mq->client, n, target, result);
1620 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
1621 if (result == GNUNET_OK)
1622 try_transmission_to_peer (n);
1623 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1624 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, n);
1627 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "transmit_send_continuation",
1628 "Neighbour `%s' no longer exists\n",
1629 GNUNET_i2s (&mq->neighbour_id));
1635 * Check the ready list for the given neighbour and if a plugin is
1636 * ready for transmission (and if we have a message), do so!
1638 * @param neighbour target peer for which to transmit
1641 try_transmission_to_peer (struct NeighbourMapEntry *n)
1643 struct ReadyList *rl;
1644 struct MessageQueue *mq;
1645 struct GNUNET_TIME_Relative timeout;
1649 if (n->messages_head == NULL)
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Transmission queue for `%4s' is empty\n", GNUNET_i2s (&n->id));
1655 return; /* nothing to do */
1658 mq = n->messages_head;
1659 force_address = GNUNET_YES;
1660 if (mq->specific_address == NULL)
1663 mq->specific_address = get_preferred_ats_address (n);
1664 GNUNET_STATISTICS_update (stats,
1666 ("# transport selected peer address freely"), 1,
1668 force_address = GNUNET_NO;
1670 if (mq->specific_address == NULL)
1672 GNUNET_STATISTICS_update (stats,
1674 ("# transport failed to selected peer address"),
1676 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1677 if (timeout.rel_value == 0)
1680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1681 "No destination address available to transmit message of size %u to peer `%4s'\n",
1682 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id));
1684 GNUNET_STATISTICS_update (stats,
1686 ("# bytes in message queue for other peers"),
1687 -(int64_t) mq->message_buf_size, GNUNET_NO);
1688 GNUNET_STATISTICS_update (stats,
1690 ("# bytes discarded (no destination address available)"),
1691 mq->message_buf_size, GNUNET_NO);
1692 if (mq->client != NULL)
1693 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1694 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1696 return; /* nobody ready */
1698 GNUNET_STATISTICS_update (stats,
1700 ("# message delivery deferred (no address)"), 1,
1702 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1703 GNUNET_SCHEDULER_cancel (n->retry_task);
1705 GNUNET_SCHEDULER_add_delayed (timeout, &retry_transmission_task, n);
1707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1708 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1709 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id),
1712 /* FIXME: might want to trigger peerinfo lookup here
1713 * (unless that's already pending...) */
1716 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1717 if (mq->specific_address->connected == GNUNET_NO)
1718 mq->specific_address->connect_attempts++;
1719 rl = mq->specific_address->ready_list;
1720 mq->plugin = rl->plugin;
1721 if (!mq->internal_msg)
1722 mq->specific_address->in_transmit = GNUNET_YES;
1724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1725 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1726 mq->message_buf_size, GNUNET_i2s (&n->id),
1727 (mq->specific_address->addr !=
1728 NULL) ? a2s (mq->plugin->short_name, mq->specific_address->addr,
1729 mq->specific_address->addrlen) : "<inbound>",
1730 rl->plugin->short_name);
1732 GNUNET_STATISTICS_update (stats,
1734 ("# bytes in message queue for other peers"),
1735 -(int64_t) mq->message_buf_size, GNUNET_NO);
1736 GNUNET_STATISTICS_update (stats,
1737 gettext_noop ("# bytes pending with plugins"),
1738 mq->message_buf_size, GNUNET_NO);
1740 GNUNET_CONTAINER_DLL_insert (n->cont_head, n->cont_tail, mq);
1743 rl->plugin->api->send (rl->plugin->api->cls, &mq->neighbour_id,
1744 mq->message_buf, 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, force_address,
1750 &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, struct GNUNET_TIME_Relative timeout,
1777 const char *message_buf, size_t message_buf_size,
1778 int is_internal, struct NeighbourMapEntry *neighbour)
1780 struct MessageQueue *mq;
1785 /* check for duplicate submission */
1786 mq = neighbour->messages_head;
1789 if (mq->client == client)
1791 /* client transmitted to same peer twice
1792 * before getting SEND_OK! */
1800 GNUNET_STATISTICS_update (stats,
1802 ("# bytes in message queue for other peers"),
1803 message_buf_size, GNUNET_NO);
1804 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1805 mq->specific_address = peer_address;
1806 mq->client = client;
1807 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1808 memcpy (&mq[1], message_buf, message_buf_size);
1809 mq->message_buf = (const char *) &mq[1];
1810 mq->message_buf_size = message_buf_size;
1811 memcpy (&mq->neighbour_id, &neighbour->id,
1812 sizeof (struct GNUNET_PeerIdentity));
1813 mq->internal_msg = is_internal;
1814 mq->priority = priority;
1815 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1817 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1818 neighbour->messages_tail, mq);
1820 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1821 neighbour->messages_tail,
1822 neighbour->messages_tail, mq);
1823 try_transmission_to_peer (neighbour);
1828 * Send a plain PING (without address or our HELLO) to the given
1829 * foreign address to try to establish a connection (and validate
1830 * that the other peer is really who he claimed he is).
1832 * @param n neighbour to PING
1835 transmit_plain_ping (struct NeighbourMapEntry *n)
1837 struct ValidationEntry *ve;
1838 struct TransportPingMessage ping;
1839 struct ReadyList *rl;
1840 struct TransportPlugin *plugin;
1841 struct ForeignAddressList *fal;
1843 if (!n->public_key_valid)
1845 /* This should not happen since the other peer
1846 * should send us a HELLO prior to sending his
1848 GNUNET_break_op (0);
1849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1850 "Could not transmit plain PING to `%s': public key not known\n",
1851 GNUNET_i2s (&n->id));
1854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1855 "Looking for addresses to transmit plain PING to `%s'\n",
1856 GNUNET_i2s (&n->id));
1857 for (rl = n->plugins; rl != NULL; rl = rl->next)
1859 plugin = rl->plugin;
1860 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1862 if (!fal->connected)
1864 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1865 ve->transport_name = GNUNET_strdup (plugin->short_name);
1867 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
1868 ve->send_time = GNUNET_TIME_absolute_get ();
1869 ve->session = fal->session;
1870 memcpy (&ve->publicKey, &n->publicKey,
1871 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1873 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1874 &timeout_hello_validation, ve);
1875 GNUNET_CONTAINER_multihashmap_put (validation_map, &n->id.hashPubKey, ve,
1876 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1877 ping.header.size = htons (sizeof (struct TransportPingMessage));
1878 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1879 ping.challenge = htonl (ve->challenge);
1880 memcpy (&ping.target, &n->id, sizeof (struct GNUNET_PeerIdentity));
1881 GNUNET_STATISTICS_update (stats,
1883 ("# PING without HELLO messages sent"), 1,
1885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s'\n",
1886 GNUNET_i2s (&n->id));
1887 transmit_to_peer (NULL, fal, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1888 HELLO_VERIFICATION_TIMEOUT, (const char *) &ping,
1889 sizeof (ping), GNUNET_YES, n);
1896 * Mark the given FAL entry as 'connected' (and hence preferred for
1897 * sending); also mark all others for the same peer as 'not connected'
1898 * (since only one can be preferred).
1900 * @param fal address to set to 'connected'
1903 mark_address_connected (struct ForeignAddressList *fal)
1905 struct ForeignAddressList *pos;
1906 struct ForeignAddressList *inbound;
1907 struct ForeignAddressList *outbound;
1909 GNUNET_assert (GNUNET_YES == fal->validated);
1910 if (fal->connected == GNUNET_YES)
1911 return; /* nothing to do */
1915 pos = fal->ready_list->addresses;
1918 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1919 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) &&
1920 (0 == fal->addrlen))
1922 if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1927 pos = fal->ready_list->addresses;
1930 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1931 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) &&
1934 if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1940 if (inbound != NULL)
1941 fprintf (stderr, "Peer: %s, have inbound connection.\n",
1942 GNUNET_i2s (&my_identity));
1943 if (outbound != NULL)
1944 fprintf (stderr, "Peer: %s, have outbound connection.\n",
1945 GNUNET_i2s (&my_identity));
1948 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1949 if ((inbound != NULL) && (0 != fal->addrlen) &&
1951 GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.
1952 hashPubKey, &my_identity.hashPubKey,
1956 fprintf (stderr, "Peer: %s, had inbound connection, ignoring outbound!\n",
1957 GNUNET_i2s (&my_identity));
1961 else if ((outbound != NULL) && (0 == fal->addrlen) &&
1963 GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->
1964 id.hashPubKey, &my_identity.hashPubKey,
1968 fprintf (stderr, "Peer: %s, have outbound connection, ignoring inbound!\n",
1969 GNUNET_i2s (&my_identity));
1974 pos = fal->ready_list->addresses;
1977 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1981 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1982 a2s (pos->ready_list->plugin->short_name, pos->addr,
1986 fprintf (stderr, "Peer: %s, setting %s connection to disconnected.\n",
1987 GNUNET_i2s (&my_identity),
1988 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
1990 pos->connected = GNUNET_NO;
1991 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1996 GNUNET_assert (GNUNET_NO == fal->connected);
1997 fal->connected = GNUNET_YES;
1998 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), 1,
2004 * Find an address in any of the available transports for
2005 * the given neighbour that would be good for message
2006 * transmission. This is essentially the transport selection
2009 * @param neighbour for whom to select an address
2010 * @return selected address, NULL if we have none
2012 struct ForeignAddressList *
2013 find_ready_address (struct NeighbourMapEntry *neighbour)
2015 struct ReadyList *head = neighbour->plugins;
2016 struct ForeignAddressList *addresses;
2017 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2018 struct ForeignAddressList *best_address;
2020 /* Hack to prefer unix domain sockets */
2021 struct ForeignAddressList *unix_address = NULL;
2023 best_address = NULL;
2024 while (head != NULL)
2026 addresses = head->addresses;
2027 while (addresses != NULL)
2029 if ((addresses->timeout.abs_value < now.abs_value) &&
2030 (addresses->connected == GNUNET_YES))
2033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2034 "Marking long-time inactive connection to `%4s' as down.\n",
2035 GNUNET_i2s (&neighbour->id));
2037 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2039 addresses->connected = GNUNET_NO;
2041 addresses = addresses->next;
2044 addresses = head->addresses;
2045 while (addresses != NULL)
2048 if (addresses->addr != NULL)
2049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2050 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2051 a2s (head->plugin->short_name, addresses->addr,
2052 addresses->addrlen), GNUNET_i2s (&neighbour->id),
2053 addresses->connected, addresses->in_transmit,
2054 addresses->validated, addresses->connect_attempts,
2055 (unsigned long long) addresses->timeout.abs_value,
2056 (unsigned int) addresses->distance);
2058 if (0 == strcmp (head->plugin->short_name, "unix"))
2060 if ((unix_address == NULL) ||
2061 ((unix_address != NULL) &&
2062 (addresses->latency.rel_value < unix_address->latency.rel_value)))
2063 unix_address = addresses;
2065 if (((best_address == NULL) || (addresses->connected == GNUNET_YES) ||
2066 (best_address->connected == GNUNET_NO)) &&
2067 (addresses->in_transmit == GNUNET_NO) && ((best_address == NULL) ||
2071 latency.rel_value)))
2072 best_address = addresses;
2073 /* FIXME: also give lower-latency addresses that are not
2074 * connected a chance some times... */
2075 addresses = addresses->next;
2077 if (unix_address != NULL)
2081 if (unix_address != NULL)
2083 best_address = unix_address;
2085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2086 "Found UNIX address, forced this address\n");
2089 if (best_address != NULL)
2092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2093 "Best address found (`%s') has latency of %llu ms.\n",
2094 (best_address->addrlen >
2095 0) ? a2s (best_address->ready_list->plugin->short_name,
2097 best_address->addrlen) : "<inbound>",
2098 best_address->latency.rel_value);
2103 GNUNET_STATISTICS_update (stats,
2105 ("# transmission attempts failed (no address)"),
2109 return best_address;
2116 struct GeneratorContext
2118 struct TransportPlugin *plug_pos;
2119 struct OwnAddressList *addr_pos;
2120 struct GNUNET_TIME_Absolute expiration;
2128 address_generator (void *cls, size_t max, void *buf)
2130 struct GeneratorContext *gc = cls;
2133 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2135 gc->plug_pos = gc->plug_pos->next;
2136 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2138 if (NULL == gc->plug_pos)
2144 GNUNET_HELLO_add_address (gc->plug_pos->short_name, gc->expiration,
2145 &gc->addr_pos[1], gc->addr_pos->addrlen, buf,
2147 gc->addr_pos = gc->addr_pos->next;
2154 transmit_our_hello_if_pong (void *cls, const GNUNET_HashCode * key, void *value)
2156 struct NeighbourMapEntry *npos = value;
2158 if (GNUNET_YES != npos->received_pong)
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2162 "Transmitting updated `%s' to neighbour `%4s'\n", "HELLO",
2163 GNUNET_i2s (&npos->id));
2165 GNUNET_STATISTICS_update (stats,
2167 ("# transmitted my HELLO to other peers"), 1,
2169 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
2170 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
2177 * Construct our HELLO message from all of the addresses of
2178 * all of the transports.
2181 * @param tc scheduler context
2184 refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2186 struct GNUNET_HELLO_Message *hello;
2187 struct TransportClient *cpos;
2188 struct GeneratorContext gc;
2190 hello_task = GNUNET_SCHEDULER_NO_TASK;
2191 gc.plug_pos = plugins;
2192 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2193 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2194 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2197 "Refreshed my `%s', new size is %d\n", "HELLO",
2198 GNUNET_HELLO_size (hello));
2200 GNUNET_STATISTICS_update (stats, gettext_noop ("# refreshed my HELLO"), 1,
2203 while (cpos != NULL)
2205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting my HELLO to client!\n");
2206 transmit_to_client (cpos, (const struct GNUNET_MessageHeader *) hello,
2211 GNUNET_free_non_null (our_hello);
2213 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2214 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2215 &transmit_our_hello_if_pong, NULL);
2220 * Schedule task to refresh hello (unless such a
2221 * task exists already).
2226 #if DEBUG_TRANSPORT_HELLO
2227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refresh_hello() called!\n");
2229 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2231 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
2236 * Iterator over hash map entries that NULLs the session of validation
2237 * entries that match the given session.
2239 * @param cls closure (the 'struct Session*' to match against)
2240 * @param key current key code (peer ID, not used)
2241 * @param value value in the hash map ('struct ValidationEntry*')
2242 * @return GNUNET_YES (we should continue to iterate)
2245 remove_session_validations (void *cls, const GNUNET_HashCode * key, void *value)
2247 struct Session *session = cls;
2248 struct ValidationEntry *ve = value;
2250 if (session == ve->session)
2257 * We've been disconnected from the other peer (for some
2258 * connection-oriented transport). Either quickly
2259 * re-establish the connection or signal the disconnect
2262 * Only signal CORE level disconnect if ALL addresses
2263 * for the peer are exhausted.
2265 * @param p overall plugin context
2266 * @param nl neighbour that was disconnected
2269 try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl)
2271 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2272 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "try_fast_reconnect not implemented!\n");
2273 /* Note: the idea here is to hide problems with transports (or
2274 * switching between plugins) from the core to eliminate the need to
2275 * re-negotiate session keys and the like; OTOH, we should tell core
2276 * quickly (much faster than timeout) `if a connection was lost and
2277 * could not be re-established (i.e. other peer went down or is
2278 * unable / refuses to communicate);
2280 * So we should consider:
2281 * 1) ideally: our own willingness / need to connect
2282 * 2) prior failures to connect to this peer (by plugin)
2283 * 3) ideally: reasons why other peer terminated (as far as knowable)
2285 * Most importantly, it must be POSSIBLE for another peer to terminate
2286 * a connection for a while (without us instantly re-establishing it).
2287 * Similarly, if another peer is gone we should quickly notify CORE.
2288 * OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2289 * on the other end), we should reconnect in such a way that BOTH CORE
2290 * services never even notice.
2291 * Furthermore, the same mechanism (or small variation) could be used
2292 * to switch to a better-performing plugin (ATS).
2294 * Finally, this needs to be tested throughly... */
2297 * GNUNET_NO in the call below makes transport disconnect the peer,
2298 * even if only a single address (out of say, six) went away. This
2299 * function must be careful to ONLY disconnect if the peer is gone,
2300 * not just a specific address.
2302 * More specifically, half the places it was used had it WRONG.
2305 /* No reconnect, signal disconnect instead! */
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2309 GNUNET_i2s (&nl->id), "try_fast_reconnect");
2311 GNUNET_STATISTICS_update (stats,
2313 ("# disconnects due to try_fast_reconnect"), 1,
2316 disconnect_neighbour (nl, GNUNET_YES);
2322 * Function that will be called whenever the plugin internally
2323 * cleans up a session pointer and hence the service needs to
2324 * discard all of those sessions as well. Plugins that do not
2325 * use sessions can simply omit calling this function and always
2326 * use NULL wherever a session pointer is needed.
2328 * @param cls closure
2329 * @param peer which peer was the session for
2330 * @param session which session is being destoyed
2333 plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
2334 struct Session *session)
2336 struct TransportPlugin *p = cls;
2337 struct NeighbourMapEntry *nl;
2338 struct ReadyList *rl;
2339 struct ForeignAddressList *pos;
2340 struct ForeignAddressList *prev;
2343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session ended with peer `%4s', %s\n",
2344 GNUNET_i2s (peer), "plugin_env_session_end");
2346 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2347 &remove_session_validations, session);
2348 nl = find_neighbour (peer);
2352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353 "No neighbour record found for peer `%4s'\n",
2356 return; /* was never marked as connected */
2361 if (rl->plugin == p)
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Plugin was associated with peer `%4s'\n", GNUNET_i2s (peer));
2371 GNUNET_STATISTICS_update (stats,
2372 gettext_noop ("# disconnects due to session end"),
2374 disconnect_neighbour (nl, GNUNET_YES);
2378 pos = rl->addresses;
2379 while ((pos != NULL) && (pos->session != session))
2387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388 "Session was never marked as ready for peer `%4s'\n",
2392 int validations_pending =
2393 GNUNET_CONTAINER_multihashmap_contains (validation_map,
2396 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2397 if (validations_pending == GNUNET_YES)
2400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401 "Not disconnecting from peer `%4s due to pending address validations\n",
2407 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2408 GNUNET_STATISTICS_update (stats,
2410 ("# disconnects due to unready session"), 1,
2413 disconnect_neighbour (nl, GNUNET_YES);
2414 return; /* was never marked as connected */
2416 pos->session = NULL;
2417 if (GNUNET_YES == pos->connected)
2419 pos->connected = GNUNET_NO;
2420 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2423 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2425 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2426 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2429 if (pos->addrlen != 0)
2431 if (nl->received_pong != GNUNET_NO)
2433 GNUNET_STATISTICS_update (stats,
2435 ("# try_fast_reconnect thanks to plugin_env_session_end"),
2437 if (GNUNET_YES == pos->connected)
2438 try_fast_reconnect (p, nl);
2442 GNUNET_STATISTICS_update (stats,
2444 ("# disconnects due to missing pong"), 1,
2446 /* FIXME this is never true?! See: line 2416 */
2447 if (GNUNET_YES == pos->connected)
2448 disconnect_neighbour (nl, GNUNET_YES);
2453 /* was inbound connection, free 'pos' */
2455 rl->addresses = pos->next;
2457 prev->next = pos->next;
2458 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2460 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2461 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2463 GNUNET_free_non_null (pos->ressources);
2464 GNUNET_free_non_null (pos->quality);
2466 ats_modify_problem_state (ats, ATS_MODIFIED);
2468 if (GNUNET_YES != pos->connected)
2470 /* nothing else to do, connection was never up... */
2474 pos->connected = GNUNET_NO;
2475 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2479 if (nl->received_pong == GNUNET_NO)
2481 GNUNET_STATISTICS_update (stats,
2482 gettext_noop ("# disconnects due to NO pong"), 1,
2484 disconnect_neighbour (nl, GNUNET_YES);
2485 return; /* nothing to do, never connected... */
2487 /* check if we have any validated addresses left */
2488 pos = rl->addresses;
2491 if (GNUNET_YES == pos->validated)
2493 GNUNET_STATISTICS_update (stats,
2495 ("# try_fast_reconnect thanks to validated_address"),
2497 try_fast_reconnect (p, nl);
2502 /* no valid addresses left, signal disconnect! */
2505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2506 GNUNET_i2s (peer), "plugin_env_session_end");
2508 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2509 * it means there aren't any left for this PLUGIN/PEER combination! So
2510 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2511 * when it isn't necessary. Using GNUNET_YES at least checks to see
2512 * if there are any addresses that work first, so as not to overdo it.
2515 GNUNET_STATISTICS_update (stats,
2517 ("# disconnects due to plugin_env_session_end"), 1,
2519 disconnect_neighbour (nl, GNUNET_YES);
2524 * Function that must be called by each plugin to notify the
2525 * transport service about the addresses under which the transport
2526 * provided by the plugin can be reached.
2528 * @param cls closure
2529 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2530 * @param addr one of the addresses of the host, NULL for the last address
2531 * the specific address format depends on the transport
2532 * @param addrlen length of the address
2535 plugin_env_notify_address (void *cls, int add_remove, const void *addr,
2538 struct TransportPlugin *p = cls;
2539 struct OwnAddressList *al;
2540 struct OwnAddressList *prev;
2542 GNUNET_assert (p->api != NULL);
2544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2546 GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" :
2547 "Removing `%s':%s from the set of our addresses\n",
2548 a2s (p->short_name, addr, addrlen), p->short_name);
2550 GNUNET_assert (addr != NULL);
2551 if (GNUNET_NO == add_remove)
2557 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2560 p->addresses = al->next;
2562 prev->next = al->next;
2573 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2574 al->next = p->addresses;
2576 al->addrlen = addrlen;
2577 memcpy (&al[1], addr, addrlen);
2583 * Notify all of our clients about a peer connecting.
2586 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2587 struct GNUNET_TIME_Relative latency, uint32_t distance)
2589 struct ConnectInfoMessage *cim;
2590 struct TransportClient *cpos;
2594 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2601 "Notifying clients about connection with `%s'\n",
2604 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), 1,
2609 sizeof (struct ConnectInfoMessage) +
2610 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2611 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2612 cim = GNUNET_malloc (size);
2613 cim->header.size = htons (size);
2614 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2615 cim->ats_count = htonl (2);
2616 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2617 (&cim->ats)[0].value = htonl (distance);
2618 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2619 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2620 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2621 (&cim->ats)[2].value = htonl (0);
2622 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2624 /* notify ats about connecting peer */
2625 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2628 ats_modify_problem_state (ats, ATS_MODIFIED);
2629 ats_calculate_bandwidth_distribution (ats);
2633 while (cpos != NULL)
2635 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2643 * Notify all of our clients about a peer disconnecting.
2646 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2648 struct DisconnectInfoMessage dim;
2649 struct TransportClient *cpos;
2651 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2658 "Notifying clients about lost connection to `%s'\n",
2661 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), -1,
2663 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2664 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2665 dim.reserved = htonl (0);
2666 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2668 /* notify ats about connecting peer */
2669 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2672 ats_modify_problem_state (ats, ATS_MODIFIED);
2673 ats_calculate_bandwidth_distribution (ats);
2678 while (cpos != NULL)
2680 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2687 * Find a ForeignAddressList entry for the given neighbour
2688 * that matches the given address and transport.
2690 * @param neighbour which peer we care about
2691 * @param tname name of the transport plugin
2692 * @param session session to look for, NULL for 'any'; otherwise
2693 * can be used for the service to "learn" this session ID
2695 * @param addr binary address
2696 * @param addrlen length of addr
2697 * @return NULL if no such entry exists
2699 static struct ForeignAddressList *
2700 find_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2701 struct Session *session, const char *addr, uint16_t addrlen)
2703 struct ReadyList *head;
2704 struct ForeignAddressList *pos;
2706 head = neighbour->plugins;
2707 while (head != NULL)
2709 if (0 == strcmp (tname, head->plugin->short_name))
2715 pos = head->addresses;
2716 while ((pos != NULL) &&
2717 ((pos->addrlen != addrlen) ||
2718 (memcmp (pos->addr, addr, addrlen) != 0)))
2720 if ((session != NULL) && (pos->session == session))
2724 if ((session != NULL) && (pos != NULL))
2725 pos->session = session; /* learn it! */
2731 * Get the peer address struct for the given neighbour and
2732 * address. If it doesn't yet exist, create it.
2734 * @param neighbour which peer we care about
2735 * @param tname name of the transport plugin
2736 * @param session session of the plugin, or NULL for none
2737 * @param addr binary address
2738 * @param addrlen length of addr
2739 * @return NULL if we do not have a transport plugin for 'tname'
2741 static struct ForeignAddressList *
2742 add_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2743 struct Session *session, const char *addr, uint16_t addrlen)
2745 struct ReadyList *head;
2746 struct ForeignAddressList *ret;
2749 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2752 head = neighbour->plugins;
2754 while (head != NULL)
2756 if (0 == strcmp (tname, head->plugin->short_name))
2762 ret = GNUNET_malloc (sizeof (struct ForeignAddressList) + addrlen);
2763 ret->session = session;
2764 if ((addrlen > 0) && (addr != NULL))
2766 ret->addr = (const char *) &ret[1];
2767 memcpy (&ret[1], addr, addrlen);
2775 GNUNET_malloc (available_ressources *
2776 sizeof (struct ATS_ressource_entry));
2777 for (c = 0; c < available_ressources; c++)
2779 struct ATS_ressource_entry *r = ret->ressources;
2782 r[c].atis_index = ressources[c].atis_index;
2783 if (0 == strcmp (neighbour->plugins->plugin->short_name, "unix"))
2785 r[c].c = ressources[c].c_unix;
2787 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "udp"))
2789 r[c].c = ressources[c].c_udp;
2791 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "tcp"))
2793 r[c].c = ressources[c].c_tcp;
2795 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "http"))
2797 r[c].c = ressources[c].c_http;
2799 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "https"))
2801 r[c].c = ressources[c].c_https;
2803 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "wlan"))
2805 r[c].c = ressources[c].c_wlan;
2809 r[c].c = ressources[c].c_default;
2810 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2811 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2812 GNUNET_i2s (&neighbour->id),
2813 neighbour->plugins->plugin->short_name);
2818 GNUNET_malloc (available_quality_metrics *
2819 sizeof (struct ATS_quality_entry));
2820 ret->addrlen = addrlen;
2822 GNUNET_TIME_relative_to_absolute
2823 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2824 ret->latency = GNUNET_TIME_relative_get_forever ();
2827 GNUNET_TIME_relative_to_absolute
2828 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2829 ret->ready_list = head;
2830 ret->next = head->addresses;
2831 head->addresses = ret;
2837 * Closure for 'add_validated_address'.
2839 struct AddValidatedAddressContext
2842 * Entry that has been validated.
2844 const struct ValidationEntry *ve;
2847 * Flag set after we have added the address so
2848 * that we terminate the iteration next time.
2855 * Callback function used to fill a buffer of max bytes with a list of
2856 * addresses in the format used by HELLOs. Should use
2857 * "GNUNET_HELLO_add_address" as a helper function.
2859 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2860 * @param max maximum number of bytes that can be written to buf
2861 * @param buf where to write the address information
2862 * @return number of bytes written, 0 to signal the
2863 * end of the iteration.
2866 add_validated_address (void *cls, size_t max, void *buf)
2868 struct AddValidatedAddressContext *avac = cls;
2869 const struct ValidationEntry *ve = avac->ve;
2871 if (GNUNET_YES == avac->done)
2873 avac->done = GNUNET_YES;
2874 return GNUNET_HELLO_add_address (ve->transport_name,
2875 GNUNET_TIME_relative_to_absolute
2876 (HELLO_ADDRESS_EXPIRATION), ve->addr,
2877 ve->addrlen, buf, max);
2883 * Closure for 'check_address_exists'.
2885 struct CheckAddressExistsClosure
2888 * Address to check for.
2893 * Name of the transport.
2900 struct Session *session;
2903 * Set to GNUNET_YES if the address exists.
2916 * Iterator over hash map entries. Checks if the given
2917 * validation entry is for the same address as what is given
2920 * @param cls the 'struct CheckAddressExistsClosure*'
2921 * @param key current key code (ignored)
2922 * @param value value in the hash map ('struct ValidationEntry')
2923 * @return GNUNET_YES if we should continue to
2924 * iterate (mismatch), GNUNET_NO if not (entry matched)
2927 check_address_exists (void *cls, const GNUNET_HashCode * key, void *value)
2929 struct CheckAddressExistsClosure *caec = cls;
2930 struct ValidationEntry *ve = value;
2932 if ((0 == strcmp (caec->tname, ve->transport_name)) &&
2933 (caec->addrlen == ve->addrlen) &&
2934 (0 == memcmp (caec->addr, ve->addr, caec->addrlen)))
2936 caec->exists = GNUNET_YES;
2939 if ((ve->session != NULL) && (caec->session == ve->session))
2941 caec->exists = GNUNET_YES;
2949 neighbour_timeout_task (void *cls,
2950 const struct GNUNET_SCHEDULER_TaskContext *tc)
2952 struct NeighbourMapEntry *n = cls;
2955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2956 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2958 GNUNET_STATISTICS_update (stats,
2959 gettext_noop ("# disconnects due to timeout"), 1,
2961 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2962 disconnect_neighbour (n, GNUNET_NO);
2967 * Schedule the job that will cause us to send a PING to the
2968 * foreign address to evaluate its validity and latency.
2970 * @param fal address to PING
2973 schedule_next_ping (struct ForeignAddressList *fal);
2977 * Add the given address to the list of foreign addresses
2978 * available for the given peer (check for duplicates).
2980 * @param cls the respective 'struct NeighbourMapEntry' to update
2981 * @param tname name of the transport
2982 * @param expiration expiration time
2983 * @param addr the address
2984 * @param addrlen length of the address
2985 * @return GNUNET_OK (always)
2988 add_to_foreign_address_list (void *cls, const char *tname,
2989 struct GNUNET_TIME_Absolute expiration,
2990 const void *addr, uint16_t addrlen)
2992 struct NeighbourMapEntry *n = cls;
2993 struct ForeignAddressList *fal;
2996 GNUNET_STATISTICS_update (stats,
2998 ("# valid peer addresses returned by PEERINFO"), 1,
3001 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3004 #if DEBUG_TRANSPORT_HELLO
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3007 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&n->id),
3008 expiration.abs_value);
3010 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3013 GNUNET_STATISTICS_update (stats,
3015 ("# previously validated addresses lacking transport"),
3020 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3021 schedule_next_ping (fal);
3027 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3033 "Failed to add new address for `%4s'\n", GNUNET_i2s (&n->id));
3037 if (fal->validated == GNUNET_NO)
3039 fal->validated = GNUNET_YES;
3040 GNUNET_STATISTICS_update (stats,
3042 ("# peer addresses considered valid"), 1,
3045 if (try == GNUNET_YES)
3048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049 "Have new addresses, will try to trigger transmissions.\n");
3051 try_transmission_to_peer (n);
3058 * Add addresses in validated HELLO "h" to the set of addresses
3059 * we have for this peer.
3061 * @param cls closure ('struct NeighbourMapEntry*')
3062 * @param peer id of the peer, NULL for last call
3063 * @param h hello message for the peer (can be NULL)
3064 * @param err_msg NULL if successful, otherwise contains error message
3067 add_hello_for_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
3068 const struct GNUNET_HELLO_Message *h, const char *err_msg)
3070 struct NeighbourMapEntry *n = cls;
3072 if (err_msg != NULL)
3075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3076 _("Error in communication with PEERINFO service: %s\n"),
3083 GNUNET_STATISTICS_update (stats,
3085 ("# outstanding peerinfo iterate requests"), -1,
3091 return; /* no HELLO available */
3093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3095 "HELLO", GNUNET_i2s (peer));
3097 if (GNUNET_YES != n->public_key_valid)
3099 GNUNET_HELLO_get_key (h, &n->publicKey);
3100 n->public_key_valid = GNUNET_YES;
3102 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
3108 * Create a fresh entry in our neighbour list for the given peer.
3109 * Will try to transmit our current HELLO to the new neighbour.
3110 * Do not call this function directly, use 'setup_peer_check_blacklist.
3112 * @param peer the peer for which we create the entry
3113 * @param do_hello should we schedule transmitting a HELLO
3114 * @return the new neighbour list entry
3116 static struct NeighbourMapEntry *
3117 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer, int do_hello)
3119 struct NeighbourMapEntry *n;
3120 struct TransportPlugin *tp;
3121 struct ReadyList *rl;
3124 memcmp (peer, &my_identity,
3125 sizeof (struct GNUNET_PeerIdentity)));
3127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up state for neighbour `%4s'\n",
3130 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), 1,
3132 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3135 GNUNET_TIME_relative_to_absolute
3136 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3137 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3138 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3139 MAX_BANDWIDTH_CARRY_S);
3143 if ((tp->api->send != NULL) && (!is_blacklisted (peer, tp)))
3145 rl = GNUNET_malloc (sizeof (struct ReadyList));
3147 rl->next = n->plugins;
3150 rl->addresses = NULL;
3154 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3157 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3158 &neighbour_timeout_task, n);
3159 GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n,
3160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3163 GNUNET_STATISTICS_update (stats,
3165 ("# peerinfo new neighbor iterate requests"), 1,
3167 GNUNET_STATISTICS_update (stats,
3169 ("# outstanding peerinfo iterate requests"), 1,
3172 GNUNET_PEERINFO_iterate (peerinfo, peer, GNUNET_TIME_UNIT_FOREVER_REL,
3173 &add_hello_for_peer, n);
3175 GNUNET_STATISTICS_update (stats,
3176 gettext_noop ("# HELLO's sent to new neighbors"),
3178 if (NULL != our_hello)
3179 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
3180 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
3188 * Function called after we have checked if communicating
3189 * with a given peer is acceptable.
3191 * @param cls closure
3192 * @param n NULL if communication is not acceptable
3194 typedef void (*SetupContinuation) (void *cls, struct NeighbourMapEntry * n);
3198 * Information kept for each client registered to perform
3204 * This is a linked list.
3206 struct Blacklisters *next;
3209 * This is a linked list.
3211 struct Blacklisters *prev;
3214 * Client responsible for this entry.
3216 struct GNUNET_SERVER_Client *client;
3219 * Blacklist check that we're currently performing.
3221 struct BlacklistCheck *bc;
3227 * Head of DLL of blacklisting clients.
3229 static struct Blacklisters *bl_head;
3232 * Tail of DLL of blacklisting clients.
3234 static struct Blacklisters *bl_tail;
3238 * Context we use when performing a blacklist check.
3240 struct BlacklistCheck
3244 * This is a linked list.
3246 struct BlacklistCheck *next;
3249 * This is a linked list.
3251 struct BlacklistCheck *prev;
3254 * Peer being checked.
3256 struct GNUNET_PeerIdentity peer;
3259 * Option for setup neighbour afterwards.
3264 * Continuation to call with the result.
3266 SetupContinuation cont;
3274 * Current transmission request handle for this client, or NULL if no
3275 * request is pending.
3277 struct GNUNET_CONNECTION_TransmitHandle *th;
3280 * Our current position in the blacklisters list.
3282 struct Blacklisters *bl_pos;
3285 * Current task performing the check.
3287 GNUNET_SCHEDULER_TaskIdentifier task;
3292 * Head of DLL of active blacklisting queries.
3294 static struct BlacklistCheck *bc_head;
3297 * Tail of DLL of active blacklisting queries.
3299 static struct BlacklistCheck *bc_tail;
3303 * Perform next action in the blacklist check.
3305 * @param cls the 'struct BlacklistCheck*'
3309 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3312 * Transmit blacklist query to the client.
3314 * @param cls the 'struct BlacklistCheck'
3315 * @param size number of bytes allowed
3316 * @param buf where to copy the message
3317 * @return number of bytes copied to buf
3320 transmit_blacklist_message (void *cls, size_t size, void *buf)
3322 struct BlacklistCheck *bc = cls;
3323 struct Blacklisters *bl;
3324 struct BlacklistMessage bm;
3329 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3330 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3331 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3332 "Failed to send blacklist test for peer `%s' to client\n",
3333 GNUNET_i2s (&bc->peer));
3337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3338 "Sending blacklist test for peer `%s' to client\n",
3339 GNUNET_i2s (&bc->peer));
3342 bm.header.size = htons (sizeof (struct BlacklistMessage));
3343 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3344 bm.is_allowed = htonl (0);
3346 memcpy (buf, &bm, sizeof (bm));
3347 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3353 * Perform next action in the blacklist check.
3355 * @param cls the 'struct BlacklistCheck*'
3359 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3361 struct BlacklistCheck *bc = cls;
3362 struct Blacklisters *bl;
3364 bc->task = GNUNET_SCHEDULER_NO_TASK;
3369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3370 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3371 GNUNET_i2s (&bc->peer));
3373 bc->cont (bc->cont_cls, setup_new_neighbour (&bc->peer, bc->do_hello));
3381 GNUNET_SERVER_notify_transmit_ready (bl->client,
3382 sizeof (struct BlacklistMessage),
3383 GNUNET_TIME_UNIT_FOREVER_REL,
3384 &transmit_blacklist_message, bc);
3390 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3391 * does not yet exist, check the blacklist. If the blacklist says creating
3392 * one is acceptable, create one and call the continuation; otherwise
3393 * call the continuation with NULL.
3395 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3396 * @param do_hello should we also schedule sending our HELLO to the peer
3397 * if this is a new record
3398 * @param cont function to call with the 'struct NeigbhbourList*'
3399 * @param cont_cls closure for cont
3402 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3403 int do_hello, SetupContinuation cont,
3406 struct NeighbourMapEntry *n;
3407 struct BlacklistCheck *bc;
3409 n = find_neighbour (peer);
3413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3414 "Neighbour record exists for peer `%s'\n", GNUNET_i2s (peer));
3420 if (bl_head == NULL)
3423 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3425 setup_new_neighbour (peer, do_hello);
3428 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3429 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3431 bc->do_hello = do_hello;
3433 bc->cont_cls = cont_cls;
3434 bc->bl_pos = bl_head;
3435 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3440 * Function called with the result of querying a new blacklister about
3441 * it being allowed (or not) to continue to talk to an existing neighbour.
3443 * @param cls the original 'struct NeighbourMapEntry'
3444 * @param n NULL if we need to disconnect
3447 confirm_or_drop_neighbour (void *cls, struct NeighbourMapEntry *n)
3449 struct NeighbourMapEntry *orig = cls;
3454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
3455 GNUNET_i2s (&orig->id), "confirm_or_drop_neighboUr");
3457 GNUNET_STATISTICS_update (stats,
3458 gettext_noop ("# disconnects due to blacklist"),
3460 disconnect_neighbour (orig, GNUNET_NO);
3465 struct TestConnectionContext
3469 struct Blacklisters *bl;
3474 test_connection_ok (void *cls, const GNUNET_HashCode * key, void *value)
3476 struct TestConnectionContext *tcc = cls;
3477 struct NeighbourMapEntry *n = value;
3478 struct BlacklistCheck *bc;
3481 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3482 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3484 bc->do_hello = GNUNET_NO;
3485 bc->cont = &confirm_or_drop_neighbour;
3487 bc->bl_pos = tcc->bl;
3488 if (GNUNET_YES == tcc->first)
3490 /* all would wait for the same client, no need to
3491 * create more than just the first task right now */
3492 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3493 tcc->first = GNUNET_NO;
3500 * Handle a request to start a blacklist.
3502 * @param cls closure (always NULL)
3503 * @param client identification of the client
3504 * @param message the actual message
3507 handle_blacklist_init (void *cls, struct GNUNET_SERVER_Client *client,
3508 const struct GNUNET_MessageHeader *message)
3510 struct Blacklisters *bl;
3511 struct TestConnectionContext tcc;
3516 if (bl->client == client)
3519 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3524 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3525 bl->client = client;
3526 GNUNET_SERVER_client_keep (client);
3527 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3528 /* confirm that all existing connections are OK! */
3530 tcc.first = GNUNET_YES;
3531 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &test_connection_ok, &tcc);
3536 * Handle a request to blacklist a peer.
3538 * @param cls closure (always NULL)
3539 * @param client identification of the client
3540 * @param message the actual message
3543 handle_blacklist_reply (void *cls, struct GNUNET_SERVER_Client *client,
3544 const struct GNUNET_MessageHeader *message)
3546 const struct BlacklistMessage *msg =
3547 (const struct BlacklistMessage *) message;
3548 struct Blacklisters *bl;
3549 struct BlacklistCheck *bc;
3552 while ((bl != NULL) && (bl->client != client))
3557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
3559 /* FIXME: other error handling here!? */
3560 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3565 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3569 "Blacklist check failed, peer not allowed\n");
3571 bc->cont (bc->cont_cls, NULL);
3572 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3579 "Blacklist check succeeded, continuing with checks\n");
3581 bc->bl_pos = bc->bl_pos->next;
3582 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3584 /* check if any other bc's are waiting for this blacklister */
3588 if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
3589 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3596 * Send periodic PING messages to a given foreign address.
3598 * @param cls our 'struct PeriodicValidationContext*'
3599 * @param tc task context
3602 send_periodic_ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3604 struct ForeignAddressList *peer_address = cls;
3605 struct TransportPlugin *tp;
3606 struct ValidationEntry *va;
3607 struct NeighbourMapEntry *neighbour;
3608 struct TransportPingMessage ping;
3609 struct CheckAddressExistsClosure caec;
3611 uint16_t hello_size;
3615 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3616 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3618 GNUNET_assert (peer_address != NULL);
3619 tp = peer_address->ready_list->plugin;
3620 neighbour = peer_address->ready_list->neighbour;
3621 if (GNUNET_YES != neighbour->public_key_valid)
3623 /* no public key yet, try again later */
3624 schedule_next_ping (peer_address);
3627 caec.addr = peer_address->addr;
3628 caec.addrlen = peer_address->addrlen;
3629 caec.tname = tp->short_name;
3630 caec.session = peer_address->session;
3631 caec.exists = GNUNET_NO;
3633 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
3635 if (caec.exists == GNUNET_YES)
3637 /* During validation attempts we will likely trigger the other
3638 * peer trying to validate our address which in turn will cause
3639 * it to send us its HELLO, so we expect to hit this case rather
3640 * frequently. Only print something if we are very verbose. */
3641 #if DEBUG_TRANSPORT > 1
3642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3643 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3644 (peer_address->addr != NULL) ? a2s (tp->short_name,
3646 peer_address->addrlen) :
3647 "<inbound>", tp->short_name, GNUNET_i2s (&neighbour->id));
3649 schedule_next_ping (peer_address);
3652 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3653 va->transport_name = GNUNET_strdup (tp->short_name);
3655 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
3656 va->send_time = GNUNET_TIME_absolute_get ();
3657 va->session = peer_address->session;
3658 if (peer_address->addr != NULL)
3660 va->addr = (const void *) &va[1];
3661 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3662 va->addrlen = peer_address->addrlen;
3664 memcpy (&va->publicKey, &neighbour->publicKey,
3665 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3668 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3669 &timeout_hello_validation, va);
3670 GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->id.hashPubKey,
3672 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3674 if (peer_address->validated != GNUNET_YES)
3675 hello_size = GNUNET_HELLO_size (our_hello);
3679 tsize = sizeof (struct TransportPingMessage) + hello_size;
3681 if (peer_address->addr != NULL)
3683 slen = strlen (tp->short_name) + 1;
3684 tsize += slen + peer_address->addrlen;
3688 slen = 0; /* make gcc happy */
3690 message_buf = GNUNET_malloc (tsize);
3691 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3692 ping.challenge = htonl (va->challenge);
3693 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
3694 if (peer_address->validated != GNUNET_YES)
3696 memcpy (message_buf, our_hello, hello_size);
3699 if (peer_address->addr != NULL)
3702 htons (sizeof (struct TransportPingMessage) + peer_address->addrlen +
3704 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3705 tp->short_name, slen);
3706 memcpy (&message_buf
3707 [hello_size + sizeof (struct TransportPingMessage) + slen],
3708 peer_address->addr, peer_address->addrlen);
3712 ping.header.size = htons (sizeof (struct TransportPingMessage));
3715 memcpy (&message_buf[hello_size], &ping,
3716 sizeof (struct TransportPingMessage));
3718 #if DEBUG_TRANSPORT_REVALIDATION
3719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3720 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3721 (peer_address->addr !=
3722 NULL) ? a2s (peer_address->plugin->short_name,
3724 peer_address->addrlen) : "<inbound>",
3725 tp->short_name, GNUNET_i2s (&neighbour->id), "HELLO", hello_size,
3728 if (peer_address->validated != GNUNET_YES)
3729 GNUNET_STATISTICS_update (stats,
3730 gettext_noop ("# PING with HELLO messages sent"),
3733 GNUNET_STATISTICS_update (stats,
3735 ("# PING without HELLO messages sent"), 1,
3737 GNUNET_STATISTICS_update (stats,
3739 ("# PING messages sent for re-validation"), 1,
3741 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3742 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
3744 GNUNET_free (message_buf);
3745 schedule_next_ping (peer_address);
3750 * Schedule the job that will cause us to send a PING to the
3751 * foreign address to evaluate its validity and latency.
3753 * @param fal address to PING
3756 schedule_next_ping (struct ForeignAddressList *fal)
3758 struct GNUNET_TIME_Relative delay;
3760 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3762 GNUNET_SCHEDULER_cancel (fal->revalidate_task);
3763 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3765 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3766 delay.rel_value /= 2; /* do before expiration */
3767 delay = GNUNET_TIME_relative_min (delay, LATENCY_EVALUATION_MAX_DELAY);
3768 if (GNUNET_YES != fal->estimated)
3770 delay = GNUNET_TIME_UNIT_ZERO;
3771 fal->estimated = GNUNET_YES;
3774 if (GNUNET_YES == fal->connected)
3777 GNUNET_TIME_relative_min (delay,
3778 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3780 /* FIXME: also adjust delay based on how close the last
3781 * observed latency is to the latency of the best alternative */
3782 /* bound how fast we can go */
3783 delay = GNUNET_TIME_relative_max (delay, GNUNET_TIME_UNIT_SECONDS);
3784 /* randomize a bit (to avoid doing all at the same time) */
3786 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3788 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3789 fal->revalidate_task =
3790 GNUNET_SCHEDULER_add_delayed (delay, &send_periodic_ping, fal);
3797 * Function that will be called if we receive some payload
3798 * from another peer.
3800 * @param message the payload
3801 * @param n peer who claimed to be the sender
3804 handle_payload_message (const struct GNUNET_MessageHeader *message,
3805 struct NeighbourMapEntry *n)
3807 struct InboundMessage *im;
3808 struct TransportClient *cpos;
3811 msize = ntohs (message->size);
3812 if (n->received_pong == GNUNET_NO)
3815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3816 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3817 ntohs (message->type), ntohs (message->size),
3818 GNUNET_i2s (&n->id));
3820 GNUNET_free_non_null (n->pre_connect_message_buffer);
3821 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3822 memcpy (n->pre_connect_message_buffer, message, msize);
3827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3828 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3829 ntohs (message->type), ntohs (message->size),
3830 GNUNET_i2s (&n->id));
3833 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, (ssize_t) msize))
3835 n->quota_violation_count++;
3837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3838 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3839 n->in_tracker.available_bytes_per_s__,
3840 n->quota_violation_count);
3842 /* Discount 32k per violation */
3843 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
3847 if (n->quota_violation_count > 0)
3849 /* try to add 32k back */
3850 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
3851 n->quota_violation_count--;
3854 GNUNET_STATISTICS_update (stats,
3856 ("# payload received from other peers"), msize,
3858 /* transmit message to all clients */
3859 uint32_t ats_count = 2;
3861 sizeof (struct InboundMessage) +
3862 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3863 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3866 im = GNUNET_malloc (size);
3867 im->header.size = htons (size);
3868 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3870 im->ats_count = htonl (ats_count);
3871 /* Setting ATS data */
3872 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3873 (&(im->ats))[0].value = htonl (n->distance);
3874 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3875 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3876 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3877 (&(im->ats))[ats_count].value = htonl (0);
3879 memcpy (&((&(im->ats))[ats_count + 1]), message, msize);
3881 while (cpos != NULL)
3883 transmit_to_client (cpos, &im->header, GNUNET_YES);
3891 * Iterator over hash map entries. Checks if the given validation
3892 * entry is for the same challenge as what is given in the PONG.
3894 * @param cls the 'struct TransportPongMessage*'
3895 * @param key peer identity
3896 * @param value value in the hash map ('struct ValidationEntry')
3897 * @return GNUNET_YES if we should continue to
3898 * iterate (mismatch), GNUNET_NO if not (entry matched)
3901 check_pending_validation (void *cls, const GNUNET_HashCode * key, void *value)
3903 const struct TransportPongMessage *pong = cls;
3904 struct ValidationEntry *ve = value;
3905 struct AddValidatedAddressContext avac;
3906 unsigned int challenge = ntohl (pong->challenge);
3907 struct GNUNET_HELLO_Message *hello;
3908 struct GNUNET_PeerIdentity target;
3909 struct NeighbourMapEntry *n;
3910 struct ForeignAddressList *fal;
3911 struct OwnAddressList *oal;
3912 struct TransportPlugin *tp;
3913 struct GNUNET_MessageHeader *prem;
3919 ps = ntohs (pong->header.size);
3920 if (ps < sizeof (struct TransportPongMessage))
3922 GNUNET_break_op (0);
3925 addr = (const char *) &pong[1];
3926 slen = strlen (ve->transport_name) + 1;
3927 if ((ps - sizeof (struct TransportPongMessage) < slen) ||
3928 (ve->challenge != challenge) || (addr[slen - 1] != '\0') ||
3929 (0 != strcmp (addr, ve->transport_name)) ||
3930 (ntohl (pong->purpose.size) !=
3931 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) +
3932 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3933 sizeof (struct GNUNET_PeerIdentity) + ps -
3934 sizeof (struct TransportPongMessage)))
3939 alen = ps - sizeof (struct TransportPongMessage) - slen;
3940 switch (ntohl (pong->purpose.purpose))
3942 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3943 if ((ve->addrlen + slen != ntohl (pong->addrlen)) ||
3944 (0 != memcmp (&addr[slen], ve->addr, ve->addrlen)))
3946 return GNUNET_YES; /* different entry, keep trying! */
3948 if (0 != memcmp (&pong->pid, key, sizeof (struct GNUNET_PeerIdentity)))
3950 GNUNET_break_op (0);
3954 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3955 &pong->purpose, &pong->signature,
3958 GNUNET_break_op (0);
3963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3964 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3965 GNUNET_h2s (key), a2s (ve->transport_name,
3966 (const struct sockaddr *) ve->addr,
3967 ve->addrlen), ve->transport_name);
3970 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3972 memcmp (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
3976 GNUNET_asprintf (&peer, "%s", GNUNET_i2s (&pong->pid));
3978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3979 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
3980 GNUNET_i2s (&my_identity), peer);
3985 if (ve->addrlen != 0)
3987 /* must have been for a different validation entry */
3990 tp = find_transport (ve->transport_name);
3996 oal = tp->addresses;
3999 if ((oal->addrlen == alen) && (0 == memcmp (&oal[1], &addr[slen], alen)))
4005 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4007 ("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4008 GNUNET_i2s (&pong->pid), a2s (ve->transport_name, &addr[slen],
4010 /* FIXME: since the sender of the PONG currently uses the
4011 * wrong address (see FIMXE there!), we cannot run a
4012 * proper check here... */
4018 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4019 &pong->purpose, &pong->signature,
4022 GNUNET_break_op (0);
4027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4028 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4029 GNUNET_h2s (key), a2s (ve->transport_name, &addr[slen], alen),
4030 ve->transport_name);
4034 GNUNET_break_op (0);
4037 if (GNUNET_TIME_absolute_get_remaining
4038 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4040 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4041 _("Received expired signature. Check system time.\n"));
4044 GNUNET_STATISTICS_update (stats,
4045 gettext_noop ("# address validation successes"), 1,
4047 /* create the updated HELLO */
4048 GNUNET_CRYPTO_hash (&ve->publicKey,
4049 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4050 &target.hashPubKey);
4051 if (ve->addr != NULL)
4053 avac.done = GNUNET_NO;
4055 hello = GNUNET_HELLO_create (&ve->publicKey, &add_validated_address, &avac);
4056 GNUNET_PEERINFO_add_peer (peerinfo, hello);
4057 GNUNET_free (hello);
4059 n = find_neighbour (&target);
4062 n->publicKey = ve->publicKey;
4063 n->public_key_valid = GNUNET_YES;
4065 add_peer_address (n, ve->transport_name, ve->session, ve->addr,
4067 GNUNET_assert (fal != NULL);
4068 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4069 fal->validated = GNUNET_YES;
4070 mark_address_connected (fal);
4071 GNUNET_STATISTICS_update (stats,
4073 ("# peer addresses considered valid"), 1,
4075 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4076 update_addr_value (fal,
4077 GNUNET_TIME_absolute_get_duration (ve->
4078 send_time).rel_value,
4079 GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4081 schedule_next_ping (fal);
4082 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4083 n->latency = fal->latency;
4085 n->latency.rel_value =
4086 (fal->latency.rel_value + n->latency.rel_value) / 2;
4088 n->distance = fal->distance;
4089 if (GNUNET_NO == n->received_pong)
4091 n->received_pong = GNUNET_YES;
4092 notify_clients_connect (&target, n->latency, n->distance);
4093 if (NULL != (prem = n->pre_connect_message_buffer))
4095 n->pre_connect_message_buffer = NULL;
4096 handle_payload_message (prem, n);
4100 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4102 GNUNET_SCHEDULER_cancel (n->retry_task);
4103 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4104 try_transmission_to_peer (n);
4108 /* clean up validation entry */
4109 GNUNET_assert (GNUNET_YES ==
4110 GNUNET_CONTAINER_multihashmap_remove (validation_map, key,
4112 abort_validation (NULL, NULL, ve);
4118 * Function that will be called if we receive a validation
4119 * of an address challenge that we transmitted to another
4120 * peer. Note that the validation should only be considered
4121 * acceptable if the challenge matches AND if the sender
4122 * address is at least a plausible address for this peer
4123 * (otherwise we may be seeing a MiM attack).
4125 * @param cls closure
4126 * @param message the pong message
4127 * @param peer who responded to our challenge
4128 * @param sender_address string describing our sender address (as observed
4129 * by the other peer in binary format)
4130 * @param sender_address_len number of bytes in 'sender_address'
4133 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4134 const struct GNUNET_PeerIdentity *peer, const char *sender_address,
4135 size_t sender_address_len)
4137 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4139 /* PONG send to self, ignore */
4140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from myself\n",
4144 #if DEBUG_TRANSPORT > 1
4145 /* we get tons of these that just get discarded, only log
4146 * if we are quite verbose */
4147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from `%4s'.\n",
4148 "PONG", GNUNET_i2s (peer));
4150 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), 1,
4152 if (GNUNET_SYSERR !=
4153 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4155 &check_pending_validation,
4158 /* This is *expected* to happen a lot since we send
4159 * PONGs to *all* known addresses of the sender of
4160 * the PING, so most likely we get multiple PONGs
4161 * per PING, and all but the first PONG will end up
4162 * here. So really we should not print anything here
4163 * unless we want to be very, very verbose... */
4164 #if DEBUG_TRANSPORT > 2
4165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4166 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4167 "PONG", GNUNET_i2s (peer), "PING");
4176 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4178 * @param cls the 'struct ValidationEntry*'
4179 * @param neighbour neighbour to validate, NULL if validation failed
4182 transmit_hello_and_ping (void *cls, struct NeighbourMapEntry *neighbour)
4184 struct ValidationEntry *va = cls;
4185 struct ForeignAddressList *peer_address;
4186 struct TransportPingMessage ping;
4187 uint16_t hello_size;
4190 struct GNUNET_PeerIdentity id;
4193 GNUNET_CRYPTO_hash (&va->publicKey,
4194 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4196 if (neighbour == NULL)
4198 /* FIXME: stats... */
4199 GNUNET_break (GNUNET_OK ==
4200 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4201 &id.hashPubKey, va));
4202 abort_validation (NULL, NULL, va);
4205 neighbour->publicKey = va->publicKey;
4206 neighbour->public_key_valid = GNUNET_YES;
4208 add_peer_address (neighbour, va->transport_name, NULL,
4209 (const void *) &va[1], va->addrlen);
4210 if (peer_address == NULL)
4212 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4213 "Failed to add peer `%4s' for plugin `%s'\n",
4214 GNUNET_i2s (&neighbour->id), va->transport_name);
4215 GNUNET_break (GNUNET_OK ==
4216 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4217 &id.hashPubKey, va));
4218 abort_validation (NULL, NULL, va);
4221 if (NULL == our_hello)
4222 refresh_hello_task (NULL, NULL);
4223 hello_size = GNUNET_HELLO_size (our_hello);
4224 slen = strlen (va->transport_name) + 1;
4226 sizeof (struct TransportPingMessage) + hello_size + va->addrlen + slen;
4227 message_buf = GNUNET_malloc (tsize);
4228 ping.challenge = htonl (va->challenge);
4230 htons (sizeof (struct TransportPingMessage) + slen + va->addrlen);
4231 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4232 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
4233 memcpy (message_buf, our_hello, hello_size);
4234 memcpy (&message_buf[hello_size], &ping,
4235 sizeof (struct TransportPingMessage));
4236 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4237 va->transport_name, slen);
4238 memcpy (&message_buf
4239 [hello_size + sizeof (struct TransportPingMessage) + slen], &va[1],
4242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4243 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4244 (va->addrlen == 0) ? "<inbound>" : a2s (va->transport_name,
4245 (const void *) &va[1],
4247 va->transport_name, GNUNET_i2s (&neighbour->id), "HELLO",
4249 sizeof (struct TransportPingMessage) + va->addrlen + slen);
4252 GNUNET_STATISTICS_update (stats,
4254 ("# PING messages sent for initial validation"), 1,
4256 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4257 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
4259 GNUNET_free (message_buf);
4264 * Check if the given address is already being validated; if not,
4265 * append the given address to the list of entries that are being be
4266 * validated and initiate validation.
4268 * @param cls closure ('struct CheckHelloValidatedContext *')
4269 * @param tname name of the transport
4270 * @param expiration expiration time
4271 * @param addr the address
4272 * @param addrlen length of the address
4273 * @return GNUNET_OK (always)
4276 run_validation (void *cls, const char *tname,
4277 struct GNUNET_TIME_Absolute expiration, const void *addr,
4280 struct CheckHelloValidatedContext *chvc = cls;
4281 struct GNUNET_PeerIdentity id;
4282 struct TransportPlugin *tp;
4283 struct ValidationEntry *va;
4284 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4285 struct CheckAddressExistsClosure caec;
4286 struct OwnAddressList *oal;
4288 GNUNET_assert (addr != NULL);
4290 GNUNET_STATISTICS_update (stats,
4292 ("# peer addresses scheduled for validation"), 1,
4294 tp = find_transport (tname);
4297 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
4299 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4301 GNUNET_STATISTICS_update (stats,
4303 ("# peer addresses not validated (plugin not available)"),
4307 /* check if this is one of our own addresses */
4308 oal = tp->addresses;
4311 if ((oal->addrlen == addrlen) && (0 == memcmp (&oal[1], addr, addrlen)))
4313 /* not plausible, this address is equivalent to our own address! */
4314 GNUNET_STATISTICS_update (stats,
4316 ("# peer addresses not validated (loopback)"),
4322 GNUNET_HELLO_get_key (chvc->hello, &pk);
4323 GNUNET_CRYPTO_hash (&pk,
4324 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4327 if (is_blacklisted (&id, tp))
4330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4331 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4332 GNUNET_i2s (&id), tname);
4338 caec.addrlen = addrlen;
4339 caec.session = NULL;
4341 caec.exists = GNUNET_NO;
4342 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
4344 if (caec.exists == GNUNET_YES)
4346 /* During validation attempts we will likely trigger the other
4347 * peer trying to validate our address which in turn will cause
4348 * it to send us its HELLO, so we expect to hit this case rather
4349 * frequently. Only print something if we are very verbose. */
4350 #if DEBUG_TRANSPORT > 1
4351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4352 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4353 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id));
4355 GNUNET_STATISTICS_update (stats,
4357 ("# peer addresses not validated (in progress)"),
4361 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4364 va->transport_name = GNUNET_strdup (tname);
4366 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
4367 va->send_time = GNUNET_TIME_absolute_get ();
4368 va->addr = (const void *) &va[1];
4369 memcpy (&va[1], addr, addrlen);
4370 va->addrlen = addrlen;
4371 GNUNET_HELLO_get_key (chvc->hello, &va->publicKey);
4373 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4374 &timeout_hello_validation, va);
4375 GNUNET_CONTAINER_multihashmap_put (validation_map, &id.hashPubKey, va,
4376 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4377 setup_peer_check_blacklist (&id, GNUNET_NO, &transmit_hello_and_ping, va);
4383 * Check if addresses in validated hello "h" overlap with
4384 * those in "chvc->hello" and validate the rest.
4386 * @param cls closure
4387 * @param peer id of the peer, NULL for last call
4388 * @param h hello message for the peer (can be NULL)
4389 * @param err_msg NULL if successful, otherwise contains error message
4392 check_hello_validated (void *cls, const struct GNUNET_PeerIdentity *peer,
4393 const struct GNUNET_HELLO_Message *h,
4394 const char *err_msg)
4396 struct CheckHelloValidatedContext *chvc = cls;
4397 struct GNUNET_HELLO_Message *plain_hello;
4398 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4399 struct GNUNET_PeerIdentity target;
4400 struct NeighbourMapEntry *n;
4402 if (err_msg != NULL)
4405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4406 _("Error in communication with PEERINFO service: %s\n"),
4414 GNUNET_STATISTICS_update (stats,
4416 ("# outstanding peerinfo iterate requests"), -1,
4419 if (GNUNET_NO == chvc->hello_known)
4421 /* notify PEERINFO about the peer now, so that we at least
4422 * have the public key if some other component needs it */
4423 GNUNET_HELLO_get_key (chvc->hello, &pk);
4424 GNUNET_CRYPTO_hash (&pk,
4426 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4427 &target.hashPubKey);
4428 plain_hello = GNUNET_HELLO_create (&pk, NULL, NULL);
4429 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4430 GNUNET_free (plain_hello);
4431 #if DEBUG_TRANSPORT_HELLO
4432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4433 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4434 "HELLO", GNUNET_i2s (&target));
4436 GNUNET_STATISTICS_update (stats,
4438 ("# new HELLOs requiring full validation"), 1,
4440 GNUNET_HELLO_iterate_addresses (chvc->hello, GNUNET_NO, &run_validation,
4445 GNUNET_STATISTICS_update (stats,
4446 gettext_noop ("# duplicate HELLO (peer known)"),
4450 if (chvc->ve_count == 0)
4452 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
4459 #if DEBUG_TRANSPORT_HELLO
4460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4461 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4462 "HELLO", GNUNET_i2s (peer));
4464 chvc->hello_known = GNUNET_YES;
4465 n = find_neighbour (peer);
4468 #if DEBUG_TRANSPORT_HELLO
4469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4470 "Calling hello_iterate_addresses for %s!\n", GNUNET_i2s (peer));
4472 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
4474 try_transmission_to_peer (n);
4478 #if DEBUG_TRANSPORT_HELLO
4479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4480 "No existing neighbor record for %s!\n", GNUNET_i2s (peer));
4482 GNUNET_STATISTICS_update (stats,
4484 ("# no existing neighbour record (validating HELLO)"),
4487 GNUNET_STATISTICS_update (stats,
4488 gettext_noop ("# HELLO validations (update case)"),
4490 GNUNET_HELLO_iterate_new_addresses (chvc->hello, h,
4491 GNUNET_TIME_relative_to_absolute
4492 (HELLO_REVALIDATION_START_TIME),
4493 &run_validation, chvc);
4498 * Process HELLO-message.
4500 * @param plugin transport involved, may be NULL
4501 * @param message the actual message
4502 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4505 process_hello (struct TransportPlugin *plugin,
4506 const struct GNUNET_MessageHeader *message)
4509 struct GNUNET_PeerIdentity target;
4510 const struct GNUNET_HELLO_Message *hello;
4511 struct CheckHelloValidatedContext *chvc;
4512 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4513 struct NeighbourMapEntry *n;
4515 #if DEBUG_TRANSPORT_HELLO > 2
4519 hsize = ntohs (message->size);
4520 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4521 (hsize < sizeof (struct GNUNET_MessageHeader)))
4524 return GNUNET_SYSERR;
4526 GNUNET_STATISTICS_update (stats,
4527 gettext_noop ("# HELLOs received for validation"),
4530 hello = (const struct GNUNET_HELLO_Message *) message;
4531 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4533 #if DEBUG_TRANSPORT_HELLO
4534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4535 "Unable to get public key from `%s' for `%4s'!\n", "HELLO",
4536 GNUNET_i2s (&target));
4538 GNUNET_break_op (0);
4539 return GNUNET_SYSERR;
4541 GNUNET_CRYPTO_hash (&publicKey,
4542 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4543 &target.hashPubKey);
4545 #if DEBUG_TRANSPORT_HELLO
4546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for `%4s'\n",
4547 "HELLO", GNUNET_i2s (&target));
4549 if (0 == memcmp (&my_identity, &target, sizeof (struct GNUNET_PeerIdentity)))
4551 GNUNET_STATISTICS_update (stats,
4553 ("# HELLOs ignored for validation (is my own HELLO)"),
4557 n = find_neighbour (&target);
4558 if ((NULL != n) && (!n->public_key_valid))
4560 GNUNET_HELLO_get_key (hello, &n->publicKey);
4561 n->public_key_valid = GNUNET_YES;
4564 /* check if load is too high before doing expensive stuff */
4565 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) >
4568 GNUNET_STATISTICS_update (stats,
4570 ("# HELLOs ignored due to high load"), 1,
4572 #if DEBUG_TRANSPORT_HELLO
4573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4574 "Ignoring `%s' for `%4s', load too high.\n", "HELLO",
4575 GNUNET_i2s (&target));
4582 while (NULL != chvc)
4584 if (GNUNET_HELLO_equals
4585 (hello, chvc->hello, GNUNET_TIME_absolute_get ()).abs_value > 0)
4587 #if DEBUG_TRANSPORT_HELLO > 2
4588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4589 "Received duplicate `%s' message for `%4s'; ignored\n",
4590 "HELLO", GNUNET_i2s (&target));
4592 return GNUNET_OK; /* validation already pending */
4594 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4596 memcmp (hello, chvc->hello, GNUNET_HELLO_size (hello)));
4601 struct NeighbourMapEntry *temp_neighbor = find_neighbour (&target);
4603 if ((NULL != temp_neighbor))
4605 fprintf (stderr, "Already know peer, ignoring hello\n");
4610 #if DEBUG_TRANSPORT_HELLO > 2
4614 my_id = GNUNET_strdup (GNUNET_i2s (plugin->env.my_identity));
4615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4616 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4617 my_id, "HELLO", GNUNET_i2s (&target), plugin->short_name,
4618 GNUNET_HELLO_size (hello));
4619 GNUNET_free (my_id);
4623 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4625 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4626 memcpy (&chvc[1], hello, hsize);
4627 GNUNET_CONTAINER_DLL_insert (chvc_head, chvc_tail, chvc);
4628 /* finally, check if HELLO was previously validated
4629 * (continuation will then schedule actual validation) */
4630 GNUNET_STATISTICS_update (stats,
4632 ("# peerinfo process hello iterate requests"), 1,
4634 GNUNET_STATISTICS_update (stats,
4636 ("# outstanding peerinfo iterate requests"), 1,
4639 GNUNET_PEERINFO_iterate (peerinfo, &target, HELLO_VERIFICATION_TIMEOUT,
4640 &check_hello_validated, chvc);
4646 * The peer specified by the given neighbour has timed-out or a plugin
4647 * has disconnected. We may either need to do nothing (other plugins
4648 * still up), or trigger a full disconnect and clean up. This
4649 * function updates our state and does the necessary notifications.
4650 * Also notifies our clients that the neighbour is now officially
4653 * @param n the neighbour list entry for the peer
4654 * @param check GNUNET_YES to check if ALL addresses for this peer
4655 * are gone, GNUNET_NO to force a disconnect of the peer
4656 * regardless of whether other addresses exist.
4659 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4661 struct ReadyList *rpos;
4662 struct MessageQueue *mq;
4663 struct ForeignAddressList *peer_addresses;
4664 struct ForeignAddressList *peer_pos;
4666 if (GNUNET_YES == n->in_disconnect)
4668 if (GNUNET_YES == check)
4671 while (NULL != rpos)
4673 peer_addresses = rpos->addresses;
4674 while (peer_addresses != NULL)
4676 /* Do not disconnect if: an address is connected or an inbound address exists */
4677 if ((GNUNET_YES == peer_addresses->connected) ||
4678 (peer_addresses->addrlen == 0))
4681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4682 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4683 GNUNET_i2s (&n->id),
4684 a2s (peer_addresses->ready_list->plugin->short_name,
4685 peer_addresses->addr, peer_addresses->addrlen));
4687 return; /* still connected */
4689 peer_addresses = peer_addresses->next;
4695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4696 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
4698 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4700 /* notify all clients about disconnect */
4701 if (GNUNET_YES == n->received_pong)
4703 n->received_pong = GNUNET_NO;
4704 notify_clients_disconnect (&n->id);
4707 ats_modify_problem_state (ats, ATS_MODIFIED);
4709 /* clean up all plugins, cancel connections and pending transmissions */
4710 while (NULL != (rpos = n->plugins))
4712 n->plugins = rpos->next;
4713 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4714 while (rpos->addresses != NULL)
4716 peer_pos = rpos->addresses;
4717 rpos->addresses = peer_pos->next;
4718 if (peer_pos->connected == GNUNET_YES)
4720 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
4722 peer_pos->connected = GNUNET_NO;
4724 if (GNUNET_YES == peer_pos->validated)
4725 GNUNET_STATISTICS_update (stats,
4727 ("# peer addresses considered valid"), -1,
4729 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4731 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4732 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4734 GNUNET_free (peer_pos->ressources);
4735 peer_pos->ressources = NULL;
4736 GNUNET_free (peer_pos->quality);
4737 peer_pos->ressources = NULL;
4738 GNUNET_free (peer_pos);
4743 /* free all messages on the queue */
4744 while (NULL != (mq = n->messages_head))
4746 GNUNET_STATISTICS_update (stats,
4748 ("# bytes in message queue for other peers"),
4749 -(int64_t) mq->message_buf_size, GNUNET_NO);
4750 GNUNET_STATISTICS_update (stats,
4752 ("# bytes discarded due to disconnect"),
4753 mq->message_buf_size, GNUNET_NO);
4754 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
4756 memcmp (&mq->neighbour_id, &n->id,
4757 sizeof (struct GNUNET_PeerIdentity)));
4761 while (NULL != (mq = n->cont_head))
4764 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
4766 memcmp (&mq->neighbour_id, &n->id,
4767 sizeof (struct GNUNET_PeerIdentity)));
4771 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4773 GNUNET_SCHEDULER_cancel (n->timeout_task);
4774 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4776 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4778 GNUNET_SCHEDULER_cancel (n->retry_task);
4779 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4781 if (n->piter != NULL)
4783 GNUNET_PEERINFO_iterate_cancel (n->piter);
4784 GNUNET_STATISTICS_update (stats,
4786 ("# outstanding peerinfo iterate requests"), -1,
4791 GNUNET_assert (GNUNET_OK ==
4792 GNUNET_CONTAINER_multihashmap_remove (neighbours,
4793 &n->id.hashPubKey, n));
4794 /* finally, free n itself */
4795 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), -1,
4797 GNUNET_free_non_null (n->pre_connect_message_buffer);
4803 * We have received a PING message from someone. Need to send a PONG message
4804 * in response to the peer by any means necessary.
4807 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4808 const struct GNUNET_PeerIdentity *peer, struct Session *session,
4809 const char *sender_address, uint16_t sender_address_len)
4811 struct TransportPlugin *plugin = cls;
4812 struct SessionHeader *session_header = (struct SessionHeader *) session;
4813 struct TransportPingMessage *ping;
4814 struct TransportPongMessage *pong;
4815 struct NeighbourMapEntry *n;
4816 struct ReadyList *rl;
4817 struct ForeignAddressList *fal;
4818 struct OwnAddressList *oal;
4824 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4826 GNUNET_break_op (0);
4827 return GNUNET_SYSERR;
4830 ping = (struct TransportPingMessage *) message;
4832 memcmp (&ping->target, plugin->env.my_identity,
4833 sizeof (struct GNUNET_PeerIdentity)))
4836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4838 ("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4839 "PING", (sender_address != NULL) ? a2s (plugin->short_name,
4840 (const struct sockaddr
4842 sender_address_len) :
4843 "<inbound>", GNUNET_i2s (&ping->target));
4845 return GNUNET_SYSERR;
4848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4849 "Processing `%s' from `%s'\n", "PING",
4850 (sender_address != NULL) ? a2s (plugin->short_name,
4851 (const struct sockaddr *)
4853 sender_address_len) :
4856 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), 1,
4858 addr = (const char *) &ping[1];
4859 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4860 slen = strlen (plugin->short_name) + 1;
4863 /* peer wants to confirm that we have an outbound connection to him */
4864 if (session == NULL)
4866 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4868 ("Refusing to create PONG since I do not have a session with `%s'.\n"),
4870 return GNUNET_SYSERR;
4872 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4873 * 1) it is NULL when we need to have a real value
4874 * 2) it is documented to be the address of the sender (source-IP), where
4875 * what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4879 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4880 a2s (plugin->short_name, sender_address, sender_address_len),
4884 GNUNET_malloc (sizeof (struct TransportPongMessage) +
4885 sender_address_len + slen);
4887 htons (sizeof (struct TransportPongMessage) + sender_address_len +
4889 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4890 pong->purpose.size =
4891 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4892 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4893 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4894 pong->purpose.purpose =
4895 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4896 pong->challenge = ping->challenge;
4897 pong->addrlen = htonl (sender_address_len + slen);
4898 memcpy (&pong->pid, peer, sizeof (struct GNUNET_PeerIdentity));
4899 memcpy (&pong[1], plugin->short_name, slen);
4900 if ((sender_address != NULL) && (sender_address_len > 0))
4901 memcpy (&((char *) &pong[1])[slen], sender_address, sender_address_len);
4902 if (GNUNET_TIME_absolute_get_remaining
4903 (session_header->pong_sig_expires).rel_value <
4904 PONG_SIGNATURE_LIFETIME.rel_value / 4)
4906 /* create / update cached sig */
4908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4909 "Creating PONG signature to indicate active connection.\n");
4911 session_header->pong_sig_expires =
4912 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4914 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4915 GNUNET_assert (GNUNET_OK ==
4916 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4917 &session_header->pong_signature));
4922 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4924 memcpy (&pong->signature, &session_header->pong_signature,
4925 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4931 /* peer wants to confirm that this is one of our addresses */
4934 if (GNUNET_OK != plugin->api->check_address (plugin->api->cls, addr, alen))
4936 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4938 ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4939 a2s (plugin->short_name, addr, alen));
4942 oal = plugin->addresses;
4945 if ((oal->addrlen == alen) && (0 == memcmp (addr, &oal[1], alen)))
4949 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4951 htons (sizeof (struct TransportPongMessage) + alen + slen);
4952 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4953 pong->purpose.size =
4954 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4955 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4956 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4957 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4958 pong->challenge = ping->challenge;
4959 pong->addrlen = htonl (alen + slen);
4960 memcpy (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity));
4961 memcpy (&pong[1], plugin->short_name, slen);
4962 memcpy (&((char *) &pong[1])[slen], addr, alen);
4963 if ((oal != NULL) &&
4964 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value <
4965 PONG_SIGNATURE_LIFETIME.rel_value / 4))
4967 /* create / update cached sig */
4969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4970 "Creating PONG signature to indicate ownership.\n");
4972 oal->pong_sig_expires =
4973 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4974 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4975 GNUNET_assert (GNUNET_OK ==
4976 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4977 &oal->pong_signature));
4978 memcpy (&pong->signature, &oal->pong_signature,
4979 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4981 else if (oal == NULL)
4983 /* not using cache (typically DV-only) */
4985 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
4986 (PONG_SIGNATURE_LIFETIME));
4987 GNUNET_assert (GNUNET_OK ==
4988 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4993 /* can used cached version */
4994 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4995 memcpy (&pong->signature, &oal->pong_signature,
4996 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4999 n = find_neighbour (peer);
5000 GNUNET_assert (n != NULL);
5001 did_pong = GNUNET_NO;
5002 /* first try reliable response transmission */
5006 fal = rl->addresses;
5010 rl->plugin->api->send (rl->plugin->api->cls, peer,
5011 (const char *) pong, ntohs (pong->header.size),
5012 TRANSPORT_PONG_PRIORITY,
5013 HELLO_VERIFICATION_TIMEOUT, fal->session,
5014 fal->addr, fal->addrlen, GNUNET_SYSERR, NULL,
5017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5018 "Transmitted PONG to `%s' via reliable mechanism\n",
5021 GNUNET_STATISTICS_update (stats,
5023 ("# PONGs unicast via reliable transport"), 1,
5028 did_pong = GNUNET_YES;
5033 /* no reliable method found, do multicast */
5034 GNUNET_STATISTICS_update (stats,
5036 ("# PONGs multicast to all available addresses"), 1,
5041 fal = rl->addresses;
5044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5045 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5046 GNUNET_i2s (peer), a2s (rl->plugin->short_name, fal->addr,
5048 rl->plugin->short_name);
5049 transmit_to_peer (NULL, fal, TRANSPORT_PONG_PRIORITY,
5050 HELLO_VERIFICATION_TIMEOUT, (const char *) pong,
5051 ntohs (pong->header.size), GNUNET_YES, n);
5052 did_pong = GNUNET_YES;
5058 if (GNUNET_YES != did_pong)
5059 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5060 _("Could not send PONG to `%s': no address available\n"),
5067 * Function called by the plugin for each received message. Update
5068 * data volumes, possibly notify plugins about reducing the rate at
5069 * which they read from the socket and generally forward to our
5072 * @param cls the "struct TransportPlugin *" we gave to the plugin
5073 * @param peer (claimed) identity of the other peer
5074 * @param message the message, NULL if we only care about
5075 * learning about the delay until we should receive again
5076 * @param ats_data information for automatic transport selection
5077 * @param ats_count number of elements in ats not including 0-terminator
5078 * @param session identifier used for this session (can be NULL)
5079 * @param sender_address binary address of the sender (if observed)
5080 * @param sender_address_len number of bytes in sender_address
5081 * @return how long in ms the plugin should wait until receiving more data
5082 * (plugins that do not support this, can ignore the return value)
5084 static struct GNUNET_TIME_Relative
5085 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5086 const struct GNUNET_MessageHeader *message,
5087 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5088 uint32_t ats_count, struct Session *session,
5089 const char *sender_address, uint16_t sender_address_len)
5091 struct TransportPlugin *plugin = cls;
5092 struct ReadyList *service_context;
5093 struct ForeignAddressList *peer_address;
5095 struct NeighbourMapEntry *n;
5096 struct GNUNET_TIME_Relative ret;
5100 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
5102 /* refuse to receive from myself */
5104 return GNUNET_TIME_UNIT_FOREVER_REL;
5106 if (is_blacklisted (peer, plugin))
5107 return GNUNET_TIME_UNIT_FOREVER_REL;
5108 n = find_neighbour (peer);
5110 n = setup_new_neighbour (peer, GNUNET_YES);
5111 service_context = n->plugins;
5112 while ((service_context != NULL) && (plugin != service_context->plugin))
5113 service_context = service_context->next;
5114 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5115 peer_address = NULL;
5118 for (c = 0; c < ats_count; c++)
5119 if (ntohl (ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5120 distance = ntohl (ats_data[c].value);
5123 if (message != NULL)
5125 if ((session != NULL) || (sender_address != NULL))
5127 add_peer_address (n, plugin->short_name, session, sender_address,
5128 sender_address_len);
5129 if (peer_address != NULL)
5131 update_addr_ats (peer_address, ats_data, ats_count);
5132 update_addr_value (peer_address, distance,
5133 GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5135 peer_address->distance = distance;
5136 if (GNUNET_YES == peer_address->validated)
5138 mark_address_connected (peer_address);
5139 schedule_next_ping (peer_address);
5144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5145 "New address is unvalidated, trying to validate it now\n");
5147 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5149 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5150 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5152 peer_address->revalidate_task =
5153 GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5156 peer_address->timeout =
5157 GNUNET_TIME_relative_to_absolute
5158 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5160 /* update traffic received amount ... */
5161 msize = ntohs (message->size);
5163 GNUNET_STATISTICS_update (stats,
5165 ("# bytes received from other peers"), msize,
5167 n->distance = distance;
5169 GNUNET_TIME_relative_to_absolute
5170 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5171 GNUNET_SCHEDULER_cancel (n->timeout_task);
5173 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5174 &neighbour_timeout_task, n);
5175 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5177 /* dropping message due to frequent inbound volume violations! */
5178 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
5180 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5181 n->in_tracker.available_bytes_per_s__,
5182 n->quota_violation_count);
5183 GNUNET_STATISTICS_update (stats,
5185 ("# bandwidth quota violations by other peers"),
5187 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5189 if ((ntohs (message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5190 (ntohs (message->size) ==
5191 (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5194 uint32_t value = ntohl (*((uint32_t *) & message[1]));
5196 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5197 /* Force ressource and quality update */
5198 if ((value == 4) && (ats != NULL))
5199 ats_modify_problem_state (ats, ATS_QUALITY_COST_UPDATED);
5200 /* Force cost update */
5201 if ((value == 3) && (ats != NULL))
5202 ats_modify_problem_state (ats, ATS_COST_UPDATED);
5203 /* Force quality update */
5204 if ((value == 2) && (ats != NULL))
5205 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
5206 /* Force full rebuild */
5207 if ((value == 1) && (ats != NULL))
5208 ats_modify_problem_state (ats, ATS_MODIFIED);
5213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5214 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5215 ntohs (message->type), ntohs (message->size),
5218 switch (ntohs (message->type))
5220 case GNUNET_MESSAGE_TYPE_HELLO:
5221 GNUNET_STATISTICS_update (stats,
5223 ("# HELLO messages received from other peers"),
5225 process_hello (plugin, message);
5227 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5228 handle_ping (plugin, message, peer, session, sender_address,
5229 sender_address_len);
5230 if (GNUNET_YES != n->received_pong)
5231 transmit_plain_ping (n);
5233 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5234 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5236 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5239 handle_payload_message (message, n);
5243 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5244 if (ret.rel_value > 0)
5247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5248 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5249 (unsigned long long) n->
5250 in_tracker.consumption_since_last_update__,
5251 (unsigned int) n->in_tracker.available_bytes_per_s__,
5252 (unsigned long long) ret.rel_value);
5254 GNUNET_STATISTICS_update (stats, gettext_noop ("# ms throttling suggested"),
5255 (int64_t) ret.rel_value, GNUNET_NO);
5262 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
5265 struct TransportClient *c = cls;
5266 struct NeighbourMapEntry *n = value;
5267 struct ConnectInfoMessage *cim;
5271 if (GNUNET_YES != n->received_pong)
5276 sizeof (struct ConnectInfoMessage) +
5277 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5278 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5279 cim = GNUNET_malloc (size);
5280 cim->header.size = htons (size);
5281 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5282 cim->ats_count = htonl (ats_count);
5283 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5284 (&(cim->ats))[2].value = htonl (0);
5285 if (GNUNET_YES == n->received_pong)
5287 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5288 (&cim->ats)[0].value = htonl (n->distance);
5289 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5290 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5292 transmit_to_client (c, &cim->header, GNUNET_NO);
5300 * Handle START-message. This is the first message sent to us
5301 * by any client which causes us to add it to our list.
5303 * @param cls closure (always NULL)
5304 * @param client identification of the client
5305 * @param message the actual message
5308 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
5309 const struct GNUNET_MessageHeader *message)
5311 const struct StartMessage *start;
5312 struct TransportClient *c;
5314 start = (const struct StartMessage *) message;
5316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n",
5322 if (c->client == client)
5324 /* client already on our list! */
5326 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5331 if ((GNUNET_NO != ntohl (start->do_check)) &&
5333 memcmp (&start->self, &my_identity,
5334 sizeof (struct GNUNET_PeerIdentity))))
5336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5338 ("Rejecting control connection from peer `%s', which is not me!\n"),
5339 GNUNET_i2s (&start->self));
5340 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5343 c = GNUNET_malloc (sizeof (struct TransportClient));
5347 if (our_hello != NULL)
5350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending our own `%s' to new client\n",
5353 transmit_to_client (c, (const struct GNUNET_MessageHeader *) our_hello,
5355 /* tell new client about all existing connections */
5356 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5357 ¬ify_client_about_neighbour, c);
5361 #if DEBUG_TRANSPORT_HELLO
5362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5363 "No HELLO created yet, will transmit HELLO to client later!\n");
5367 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5372 * Handle HELLO-message.
5374 * @param cls closure (always NULL)
5375 * @param client identification of the client
5376 * @param message the actual message
5379 handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
5380 const struct GNUNET_MessageHeader *message)
5384 GNUNET_STATISTICS_update (stats,
5385 gettext_noop ("# HELLOs received from clients"), 1,
5387 ret = process_hello (NULL, message);
5388 GNUNET_SERVER_receive_done (client, ret);
5393 * Closure for 'transmit_client_message'; followed by
5394 * 'msize' bytes of the actual message.
5396 struct TransmitClientMessageContext
5399 * Client on whom's behalf we are sending.
5401 struct GNUNET_SERVER_Client *client;
5404 * Timeout for the transmission.
5406 struct GNUNET_TIME_Absolute timeout;
5414 * Size of the message in bytes.
5421 * Schedule transmission of a message we got from a client to a peer.
5423 * @param cls the 'struct TransmitClientMessageContext*'
5424 * @param n destination, or NULL on error (in that case, drop the message)
5427 transmit_client_message (void *cls, struct NeighbourMapEntry *n)
5429 struct TransmitClientMessageContext *tcmc = cls;
5430 struct TransportClient *tc;
5433 while ((tc != NULL) && (tc->client != tcmc->client))
5438 transmit_to_peer (tc, NULL, tcmc->priority,
5439 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5440 (char *) &tcmc[1], tcmc->msize, GNUNET_NO, n);
5442 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5443 GNUNET_SERVER_client_drop (tcmc->client);
5449 * Handle SEND-message.
5451 * @param cls closure (always NULL)
5452 * @param client identification of the client
5453 * @param message the actual message
5456 handle_send (void *cls, struct GNUNET_SERVER_Client *client,
5457 const struct GNUNET_MessageHeader *message)
5459 const struct OutboundMessage *obm;
5460 const struct GNUNET_MessageHeader *obmm;
5461 struct TransmitClientMessageContext *tcmc;
5465 size = ntohs (message->size);
5467 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5470 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5473 GNUNET_STATISTICS_update (stats,
5474 gettext_noop ("# payload received for other peers"),
5476 obm = (const struct OutboundMessage *) message;
5477 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5478 msize = size - sizeof (struct OutboundMessage);
5480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5481 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5482 "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
5484 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5485 tcmc->client = client;
5486 tcmc->priority = ntohl (obm->priority);
5488 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh
5490 tcmc->msize = msize;
5491 /* FIXME: this memcpy can be up to 7% of our total runtime */
5492 memcpy (&tcmc[1], obmm, msize);
5493 GNUNET_SERVER_client_keep (client);
5494 setup_peer_check_blacklist (&obm->peer, GNUNET_YES, &transmit_client_message,
5500 * Handle request connect message
5502 * @param cls closure (always NULL)
5503 * @param client identification of the client
5504 * @param message the actual message
5507 handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
5508 const struct GNUNET_MessageHeader *message)
5510 const struct TransportRequestConnectMessage *trcm =
5511 (const struct TransportRequestConnectMessage *) message;
5513 GNUNET_STATISTICS_update (stats,
5515 ("# REQUEST CONNECT messages received"), 1,
5518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5519 "Received a request connect message for peer `%s'\n",
5520 GNUNET_i2s (&trcm->peer));
5522 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES, NULL, NULL);
5523 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5528 * Handle SET_QUOTA-message.
5530 * @param cls closure (always NULL)
5531 * @param client identification of the client
5532 * @param message the actual message
5535 handle_set_quota (void *cls, struct GNUNET_SERVER_Client *client,
5536 const struct GNUNET_MessageHeader *message)
5538 const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message;
5539 struct NeighbourMapEntry *n;
5541 GNUNET_STATISTICS_update (stats,
5542 gettext_noop ("# SET QUOTA messages received"), 1,
5544 n = find_neighbour (&qsm->peer);
5547 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5548 GNUNET_STATISTICS_update (stats,
5550 ("# SET QUOTA messages ignored (no such peer)"),
5555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5556 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5557 "SET_QUOTA", (unsigned int) ntohl (qsm->quota.value__),
5558 (unsigned int) n->in_tracker.available_bytes_per_s__,
5559 GNUNET_i2s (&qsm->peer));
5561 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, qsm->quota);
5562 if (0 == ntohl (qsm->quota.value__))
5565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
5566 GNUNET_i2s (&n->id), "SET_QUOTA");
5568 GNUNET_STATISTICS_update (stats,
5569 gettext_noop ("# disconnects due to quota of 0"),
5571 disconnect_neighbour (n, GNUNET_NO);
5573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5578 * Take the given address and append it to the set of results sent back to
5581 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5582 * @param address the resolved name, NULL to indicate the last response
5585 transmit_address_to_client (void *cls, const char *address)
5587 struct GNUNET_SERVER_TransmitContext *tc = cls;
5590 if (NULL != address)
5592 slen = strlen (address) + 1;
5593 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5594 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5598 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5599 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5600 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5606 * Handle AddressLookup-message.
5608 * @param cls closure (always NULL)
5609 * @param client identification of the client
5610 * @param message the actual message
5613 handle_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5614 const struct GNUNET_MessageHeader *message)
5616 const struct AddressLookupMessage *alum;
5617 struct TransportPlugin *lsPlugin;
5618 const char *nameTransport;
5619 const char *address;
5621 struct GNUNET_SERVER_TransmitContext *tc;
5622 struct GNUNET_TIME_Relative rtimeout;
5625 size = ntohs (message->size);
5626 if (size < sizeof (struct AddressLookupMessage))
5628 GNUNET_break_op (0);
5629 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5632 alum = (const struct AddressLookupMessage *) message;
5633 uint32_t addressLen = ntohl (alum->addrlen);
5635 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5637 GNUNET_break_op (0);
5638 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5641 address = (const char *) &alum[1];
5642 nameTransport = (const char *) &address[addressLen];
5644 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5646 GNUNET_break_op (0);
5647 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5650 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5651 numeric = ntohl (alum->numeric_only);
5652 lsPlugin = find_transport (nameTransport);
5653 if (NULL == lsPlugin)
5655 tc = GNUNET_SERVER_transmit_context_create (client);
5656 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5657 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5658 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5661 GNUNET_SERVER_disable_receive_done_warning (client);
5662 tc = GNUNET_SERVER_transmit_context_create (client);
5663 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls, nameTransport,
5664 address, addressLen, numeric, rtimeout,
5665 &transmit_address_to_client, tc);
5669 * Handle PeerAddressLookupMessage.
5671 * @param cls closure (always NULL)
5672 * @param client identification of the client
5673 * @param message the actual message
5676 handle_peer_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5677 const struct GNUNET_MessageHeader *message)
5679 const struct PeerAddressLookupMessage *peer_address_lookup;
5680 struct NeighbourMapEntry *neighbor_iterator;
5681 struct ReadyList *ready_iterator;
5682 struct ForeignAddressList *foreign_address_iterator;
5683 struct TransportPlugin *transport_plugin;
5686 struct GNUNET_SERVER_TransmitContext *tc;
5687 struct GNUNET_TIME_Relative rtimeout;
5690 size = ntohs (message->size);
5691 if (size < sizeof (struct PeerAddressLookupMessage))
5693 GNUNET_break_op (0);
5694 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5697 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5699 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5701 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5703 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5704 if (neighbor_iterator == NULL)
5707 tc = GNUNET_SERVER_transmit_context_create (client);
5708 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5709 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5710 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5714 ready_iterator = neighbor_iterator->plugins;
5715 GNUNET_SERVER_disable_receive_done_warning (client);
5716 tc = GNUNET_SERVER_transmit_context_create (client);
5717 while (ready_iterator != NULL)
5719 foreign_address_iterator = ready_iterator->addresses;
5720 while (foreign_address_iterator != NULL)
5722 transport_plugin = foreign_address_iterator->ready_list->plugin;
5723 if (foreign_address_iterator->addr != NULL)
5725 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
5726 a2s (transport_plugin->short_name,
5727 foreign_address_iterator->addr,
5728 foreign_address_iterator->addrlen),
5729 (foreign_address_iterator->connected ==
5730 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5731 (foreign_address_iterator->validated ==
5732 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5733 transmit_address_to_client (tc, addr_buf);
5734 GNUNET_free (addr_buf);
5736 else if (foreign_address_iterator->addrlen == 0)
5738 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5739 (foreign_address_iterator->connected ==
5740 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5741 (foreign_address_iterator->validated ==
5742 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5743 transmit_address_to_client (tc, addr_buf);
5744 GNUNET_free (addr_buf);
5747 foreign_address_iterator = foreign_address_iterator->next;
5749 ready_iterator = ready_iterator->next;
5751 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5752 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5753 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5759 output_addresses (void *cls, const GNUNET_HashCode * key, void *value)
5761 struct GNUNET_SERVER_TransmitContext *tc = cls;
5762 struct NeighbourMapEntry *neighbor_iterator = value;
5763 struct ForeignAddressList *foreign_address_iterator;
5764 struct TransportPlugin *transport_plugin;
5765 struct ReadyList *ready_iterator;
5768 ready_iterator = neighbor_iterator->plugins;
5769 while (ready_iterator != NULL)
5771 foreign_address_iterator = ready_iterator->addresses;
5772 while (foreign_address_iterator != NULL)
5774 transport_plugin = foreign_address_iterator->ready_list->plugin;
5775 if (foreign_address_iterator->addr != NULL)
5777 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5778 GNUNET_i2s (&neighbor_iterator->id),
5779 a2s (transport_plugin->short_name,
5780 foreign_address_iterator->addr,
5781 foreign_address_iterator->addrlen),
5782 (foreign_address_iterator->connected ==
5783 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5784 (foreign_address_iterator->validated ==
5785 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5786 transmit_address_to_client (tc, addr_buf);
5787 GNUNET_free (addr_buf);
5789 else if (foreign_address_iterator->addrlen == 0)
5791 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5792 GNUNET_i2s (&neighbor_iterator->id), "<inbound>",
5793 (foreign_address_iterator->connected ==
5794 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5795 (foreign_address_iterator->validated ==
5796 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5797 transmit_address_to_client (tc, addr_buf);
5798 GNUNET_free (addr_buf);
5801 foreign_address_iterator = foreign_address_iterator->next;
5803 ready_iterator = ready_iterator->next;
5810 * Handle AddressIterateMessage
5812 * @param cls closure (always NULL)
5813 * @param client identification of the client
5814 * @param message the actual message
5817 handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
5818 const struct GNUNET_MessageHeader *message)
5820 struct GNUNET_SERVER_TransmitContext *tc;
5823 size = ntohs (message->size);
5824 if (size < sizeof (struct AddressIterateMessage))
5826 GNUNET_break_op (0);
5827 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5830 GNUNET_SERVER_disable_receive_done_warning (client);
5831 tc = GNUNET_SERVER_transmit_context_create (client);
5832 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &output_addresses, tc);
5833 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5834 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5835 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5839 static const struct GNUNET_MessageHeader *
5842 return (const struct GNUNET_MessageHeader *) our_hello;
5847 * Setup the environment for this plugin.
5850 create_environment (struct TransportPlugin *plug)
5852 plug->env.cfg = cfg;
5853 plug->env.my_identity = &my_identity;
5854 plug->env.get_our_hello = &do_get_our_hello;
5855 plug->env.cls = plug;
5856 plug->env.receive = &plugin_env_receive;
5857 plug->env.notify_address = &plugin_env_notify_address;
5858 plug->env.session_end = &plugin_env_session_end;
5859 plug->env.max_connections = max_connect_per_transport;
5860 plug->env.stats = stats;
5865 * Start the specified transport (load the plugin).
5868 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
5870 struct TransportPlugin *plug;
5873 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
5875 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5876 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5877 create_environment (plug);
5878 plug->short_name = GNUNET_strdup (name);
5879 plug->lib_name = libname;
5880 plug->next = plugins;
5882 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5883 if (plug->api == NULL)
5885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5886 _("Failed to load transport plugin for `%s'\n"), name);
5887 GNUNET_free (plug->short_name);
5888 plugins = plug->next;
5889 GNUNET_free (libname);
5896 null_mq_client_pointers (void *cls, const GNUNET_HashCode * key, void *value)
5898 struct TransportClient *pos = cls;
5899 struct NeighbourMapEntry *n = value;
5900 struct MessageQueue *mq;
5902 for (mq = n->messages_head; mq != NULL; mq = mq->next)
5904 if (mq->client == pos)
5905 mq->client = NULL; /* do not use anymore! */
5912 * Called whenever a client is disconnected. Frees our
5913 * resources associated with that client.
5915 * @param cls closure
5916 * @param client identification of the client
5919 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
5921 struct TransportClient *pos;
5922 struct TransportClient *prev;
5923 struct ClientMessageQueueEntry *mqe;
5924 struct Blacklisters *bl;
5925 struct BlacklistCheck *bc;
5930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5931 "Client disconnected, cleaning up.\n");
5933 /* clean up blacklister */
5937 if (bl->client == client)
5942 if (bc->bl_pos == bl)
5944 bc->bl_pos = bl->next;
5947 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5950 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5951 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
5956 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
5957 GNUNET_SERVER_client_drop (bl->client);
5963 /* clean up 'normal' clients */
5966 while ((pos != NULL) && (pos->client != client))
5973 while (NULL != (mqe = pos->message_queue_head))
5975 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5976 pos->message_queue_tail, mqe);
5977 pos->message_count--;
5980 if (NULL != neighbours)
5981 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &null_mq_client_pointers,
5984 clients = pos->next;
5986 prev->next = pos->next;
5987 if (GNUNET_YES == pos->tcs_pending)
5992 if (pos->th != NULL)
5994 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5997 GNUNET_break (0 == pos->message_count);
6003 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
6005 struct NeighbourMapEntry *n = value;
6008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
6009 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
6011 disconnect_neighbour (n, GNUNET_NO);
6017 * Function called when the service shuts down. Unloads our plugins
6018 * and cancels pending validations.
6020 * @param cls closure, unused
6021 * @param tc task context (unused)
6024 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6026 struct TransportPlugin *plug;
6027 struct OwnAddressList *al;
6028 struct CheckHelloValidatedContext *chvc;
6030 shutdown_in_progress = GNUNET_YES;
6031 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
6034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6035 "Transport service is unloading plugins...\n");
6037 while (NULL != (plug = plugins))
6039 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6041 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6042 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6044 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6045 GNUNET_free (plug->lib_name);
6046 GNUNET_free (plug->short_name);
6047 while (NULL != (al = plug->addresses))
6049 plug->addresses = al->next;
6052 plugins = plug->next;
6055 if (my_private_key != NULL)
6056 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6057 GNUNET_free_non_null (our_hello);
6059 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &abort_validation,
6061 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6062 validation_map = NULL;
6065 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6067 GNUNET_SCHEDULER_cancel (ats_task);
6068 ats_task = GNUNET_SCHEDULER_NO_TASK;
6075 /* free 'chvc' data structure */
6076 while (NULL != (chvc = chvc_head))
6078 chvc_head = chvc->next;
6079 if (chvc->piter != NULL)
6081 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6082 GNUNET_STATISTICS_update (stats,
6084 ("# outstanding peerinfo iterate requests"), -1,
6090 GNUNET_assert (chvc->ve_count == 0);
6097 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6100 if (peerinfo != NULL)
6102 GNUNET_PEERINFO_disconnect (peerinfo);
6105 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6107 GNUNET_SCHEDULER_cancel (hello_task);
6108 hello_task = GNUNET_SCHEDULER_NO_TASK;
6110 /* Can we assume those are gone by now, or do we need to clean up
6112 GNUNET_break (bl_head == NULL);
6113 GNUNET_break (bc_head == NULL);
6114 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS Result callback\n");
6127 struct AtsBuildContext
6129 struct ATS_mechanism *mechanisms;
6130 struct ATS_peer *peers;
6137 find_and_count_addresses (void *cls, const GNUNET_HashCode * key, void *value)
6139 struct AtsBuildContext *abc = cls;
6140 struct NeighbourMapEntry *next = value;
6141 int found_addresses = GNUNET_NO;
6143 struct ReadyList *r_next = next->plugins;
6145 while (r_next != NULL)
6147 struct ForeignAddressList *a_next = r_next->addresses;
6149 while (a_next != NULL)
6152 found_addresses = GNUNET_YES;
6153 a_next = a_next->next;
6155 r_next = r_next->next;
6157 if (found_addresses)
6164 setup_ats_problem (void *cls, const GNUNET_HashCode * key, void *value)
6166 struct AtsBuildContext *abc = cls;
6167 struct NeighbourMapEntry *next = value;
6169 int found_addresses = GNUNET_NO;
6170 struct ReadyList *r_next = next->plugins;
6172 while (r_next != NULL)
6174 struct ForeignAddressList *a_next = r_next->addresses;
6176 while (a_next != NULL)
6178 if (found_addresses == GNUNET_NO)
6180 abc->peers[abc->c_peers].peer = next->id;
6181 abc->peers[abc->c_peers].m_head = NULL;
6182 abc->peers[abc->c_peers].m_tail = NULL;
6183 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6185 abc->mechanisms[abc->c_mechs].addr = a_next;
6186 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6187 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6188 abc->mechanisms[abc->c_mechs].next = NULL;
6189 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6190 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6191 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6192 GNUNET_CONTAINER_DLL_insert_tail (abc->peers[abc->c_peers].m_head,
6193 abc->peers[abc->c_peers].m_tail,
6194 &abc->mechanisms[abc->c_mechs]);
6195 found_addresses = GNUNET_YES;
6197 a_next = a_next->next;
6199 r_next = r_next->next;
6201 if (found_addresses == GNUNET_YES)
6208 create_ats_information (struct ATS_peer **p, int *c_p, struct ATS_mechanism **m,
6211 struct AtsBuildContext abc;
6214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6215 "ATS requires clean address information\n");
6219 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &find_and_count_addresses,
6222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6223 "Found %u peers with % u transport mechanisms\n", c_peers,
6227 if ((abc.c_peers == 0) && (abc.c_mechs == 0))
6237 GNUNET_malloc ((1 + abc.c_mechs) * sizeof (struct ATS_mechanism));
6238 abc.peers = GNUNET_malloc ((1 + abc.c_peers) * sizeof (struct ATS_peer));
6241 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &setup_ats_problem, &abc);
6244 (*c_m) = abc.c_mechs;
6245 (*c_p) = abc.c_peers;
6247 (*m) = abc.mechanisms;
6252 schedule_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6254 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6259 ats_task = GNUNET_SCHEDULER_NO_TASK;
6260 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6263 if (shutdown_in_progress == GNUNET_YES)
6266 struct GNUNET_TIME_Relative delta =
6267 GNUNET_TIME_absolute_get_difference (last_ats_execution,
6268 GNUNET_TIME_absolute_get ());
6270 if (delta.rel_value < ats_minimum_interval.rel_value)
6273 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6274 "Minimum time between cycles not reached\n");
6280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6283 ats_calculate_bandwidth_distribution (ats);
6285 last_ats_execution = GNUNET_TIME_absolute_get ();
6288 GNUNET_SCHEDULER_add_delayed (ats_regular_interval, &schedule_ats, ats);
6293 struct ForeignAddressList *
6294 get_preferred_ats_address (struct NeighbourMapEntry *n)
6296 // TODO get ATS prefered address
6297 return find_ready_address (n);
6301 * Initiate transport service.
6303 * @param cls closure
6304 * @param server the initialized server
6305 * @param c configuration to use
6308 run (void *cls, struct GNUNET_SERVER_Handle *server,
6309 const struct GNUNET_CONFIGURATION_Handle *c)
6311 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6312 {&handle_start, NULL,
6313 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6314 {&handle_hello, NULL,
6315 GNUNET_MESSAGE_TYPE_HELLO, 0},
6316 {&handle_send, NULL,
6317 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6318 {&handle_request_connect, NULL,
6319 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
6320 sizeof (struct TransportRequestConnectMessage)},
6321 {&handle_set_quota, NULL,
6322 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6323 {&handle_address_lookup, NULL,
6324 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6326 {&handle_peer_address_lookup, NULL,
6327 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6329 {&handle_address_iterate, NULL,
6330 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6332 {&handle_blacklist_init, NULL,
6333 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
6334 sizeof (struct GNUNET_MessageHeader)},
6335 {&handle_blacklist_reply, NULL,
6336 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
6337 sizeof (struct BlacklistMessage)},
6343 unsigned long long tneigh;
6346 shutdown_in_progress = GNUNET_NO;
6348 stats = GNUNET_STATISTICS_create ("transport", cfg);
6349 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6350 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6351 /* parse configuration */
6353 GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT", "NEIGHBOUR_LIMIT",
6356 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
6359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6361 ("Transport service is lacking key configuration settings. Exiting.\n"));
6362 GNUNET_SCHEDULER_shutdown ();
6365 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6368 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6369 validation_map = NULL;
6370 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6375 max_connect_per_transport = (uint32_t) tneigh;
6376 peerinfo = GNUNET_PEERINFO_connect (cfg);
6377 if (peerinfo == NULL)
6379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6380 _("Could not access PEERINFO service. Exiting.\n"));
6381 GNUNET_SCHEDULER_shutdown ();
6384 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6387 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6388 validation_map = NULL;
6389 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6391 GNUNET_free (keyfile);
6394 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6395 GNUNET_free (keyfile);
6396 if (my_private_key == NULL)
6398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6399 _("Transport service could not access hostkey. Exiting.\n"));
6400 GNUNET_SCHEDULER_shutdown ();
6403 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6406 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6407 validation_map = NULL;
6408 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6412 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6413 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
6414 &my_identity.hashPubKey);
6415 /* setup notification */
6416 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
6418 /* load plugins... */
6421 GNUNET_CONFIGURATION_get_value_string (c, "TRANSPORT", "PLUGINS", &plugs))
6423 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
6425 pos = strtok (plugs, " ");
6428 start_transport (server, pos);
6430 pos = strtok (NULL, " ");
6432 GNUNET_free (plugs);
6434 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
6439 /* Initializing ATS */
6442 unsigned long long value;
6448 int v_b_min = 64000;
6452 ats_minimum_interval = ATS_MIN_INTERVAL;
6453 ats_regular_interval = ATS_EXEC_INTERVAL;
6455 /* loading cost ressources */
6456 for (co = 0; co < available_ressources; co++)
6458 GNUNET_asprintf (§ion, "%s_UP", ressources[co].cfg_param);
6459 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6462 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6467 "Found ressource cost: [%s] = %llu\n", section, value);
6469 ressources[co].c_max = value;
6472 GNUNET_free (section);
6473 GNUNET_asprintf (§ion, "%s_DOWN", ressources[co].cfg_param);
6474 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6477 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6482 "Found ressource cost: [%s] = %llu\n", section, value);
6484 ressources[co].c_min = value;
6487 GNUNET_free (section);
6491 ats_init (D, U, R, v_b_min, v_n_min, ATS_MAX_ITERATIONS,
6492 ATS_MAX_EXEC_DURATION, &create_ats_information, ats_result_cb);
6493 ats_set_logging_options (ats, stats, cfg);
6494 GNUNET_break (GNUNET_OK ==
6495 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6496 "ATS_EXEC_INTERVAL",
6497 &ats_regular_interval));
6498 GNUNET_break (GNUNET_OK ==
6499 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6501 &ats_minimum_interval));
6503 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6508 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6510 /* If we have a blacklist file, read from it */
6511 read_blacklist_file (cfg);
6512 /* process client requests */
6513 GNUNET_SERVER_add_handlers (server, handlers);
6518 * The main function for the transport service.
6520 * @param argc number of arguments from the command line
6521 * @param argv command line arguments
6522 * @return 0 ok, 1 on error
6525 main (int argc, char *const *argv)
6527 a2s (NULL, NULL, 0); /* make compiler happy */
6528 return (GNUNET_OK ==
6529 GNUNET_SERVICE_run (argc, argv, "transport",
6530 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
6533 /* end of gnunet-service-transport.c */