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 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "transmit_send_continuation",
1619 "Neighbour `%s' no longer exists\n",
1620 GNUNET_i2s (&mq->neighbour_id));
1623 if (mq->client != NULL)
1624 transmit_send_ok (mq->client, n, target, result);
1625 GNUNET_assert (n != NULL);
1626 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
1628 if (result == GNUNET_OK)
1629 try_transmission_to_peer (n);
1630 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1631 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, n);
1636 * Check the ready list for the given neighbour and if a plugin is
1637 * ready for transmission (and if we have a message), do so!
1639 * @param neighbour target peer for which to transmit
1642 try_transmission_to_peer (struct NeighbourMapEntry *n)
1644 struct ReadyList *rl;
1645 struct MessageQueue *mq;
1646 struct GNUNET_TIME_Relative timeout;
1650 if (n->messages_head == NULL)
1653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1654 "Transmission queue for `%4s' is empty\n", GNUNET_i2s (&n->id));
1656 return; /* nothing to do */
1659 mq = n->messages_head;
1660 force_address = GNUNET_YES;
1661 if (mq->specific_address == NULL)
1664 mq->specific_address = get_preferred_ats_address (n);
1665 GNUNET_STATISTICS_update (stats,
1667 ("# transport selected peer address freely"), 1,
1669 force_address = GNUNET_NO;
1671 if (mq->specific_address == NULL)
1673 GNUNET_STATISTICS_update (stats,
1675 ("# transport failed to selected peer address"),
1677 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1678 if (timeout.rel_value == 0)
1681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1682 "No destination address available to transmit message of size %u to peer `%4s'\n",
1683 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id));
1685 GNUNET_STATISTICS_update (stats,
1687 ("# bytes in message queue for other peers"),
1688 -(int64_t) mq->message_buf_size, GNUNET_NO);
1689 GNUNET_STATISTICS_update (stats,
1691 ("# bytes discarded (no destination address available)"),
1692 mq->message_buf_size, GNUNET_NO);
1693 if (mq->client != NULL)
1694 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1695 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1697 return; /* nobody ready */
1699 GNUNET_STATISTICS_update (stats,
1701 ("# message delivery deferred (no address)"), 1,
1703 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1704 GNUNET_SCHEDULER_cancel (n->retry_task);
1706 GNUNET_SCHEDULER_add_delayed (timeout, &retry_transmission_task, n);
1708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1709 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1710 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id),
1713 /* FIXME: might want to trigger peerinfo lookup here
1714 * (unless that's already pending...) */
1717 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1718 if (mq->specific_address->connected == GNUNET_NO)
1719 mq->specific_address->connect_attempts++;
1720 rl = mq->specific_address->ready_list;
1721 mq->plugin = rl->plugin;
1722 if (!mq->internal_msg)
1723 mq->specific_address->in_transmit = GNUNET_YES;
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1727 mq->message_buf_size, GNUNET_i2s (&n->id),
1728 (mq->specific_address->addr !=
1729 NULL) ? a2s (mq->plugin->short_name, mq->specific_address->addr,
1730 mq->specific_address->addrlen) : "<inbound>",
1731 rl->plugin->short_name);
1733 GNUNET_STATISTICS_update (stats,
1735 ("# bytes in message queue for other peers"),
1736 -(int64_t) mq->message_buf_size, GNUNET_NO);
1737 GNUNET_STATISTICS_update (stats,
1738 gettext_noop ("# bytes pending with plugins"),
1739 mq->message_buf_size, GNUNET_NO);
1741 GNUNET_CONTAINER_DLL_insert (n->cont_head, n->cont_tail, mq);
1744 rl->plugin->api->send (rl->plugin->api->cls, &mq->neighbour_id,
1745 mq->message_buf, mq->message_buf_size,
1747 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1748 mq->specific_address->session,
1749 mq->specific_address->addr,
1750 mq->specific_address->addrlen, force_address,
1751 &transmit_send_continuation, mq);
1754 /* failure, but 'send' would not call continuation in this case,
1755 * so we need to do it here! */
1756 transmit_send_continuation (mq, &mq->neighbour_id, GNUNET_SYSERR);
1762 * Send the specified message to the specified peer.
1764 * @param client source of the transmission request (can be NULL)
1765 * @param peer_address ForeignAddressList where we should send this message
1766 * @param priority how important is the message
1767 * @param timeout how long do we have to transmit?
1768 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1769 * @param message_buf_size total size of all messages in message_buf
1770 * @param is_internal is this an internal message; these are pre-pended and
1771 * also do not count for plugins being "ready" to transmit
1772 * @param neighbour handle to the neighbour for transmission
1775 transmit_to_peer (struct TransportClient *client,
1776 struct ForeignAddressList *peer_address,
1777 unsigned int priority, struct GNUNET_TIME_Relative timeout,
1778 const char *message_buf, size_t message_buf_size,
1779 int is_internal, struct NeighbourMapEntry *neighbour)
1781 struct MessageQueue *mq;
1786 /* check for duplicate submission */
1787 mq = neighbour->messages_head;
1790 if (mq->client == client)
1792 /* client transmitted to same peer twice
1793 * before getting SEND_OK! */
1801 GNUNET_STATISTICS_update (stats,
1803 ("# bytes in message queue for other peers"),
1804 message_buf_size, GNUNET_NO);
1805 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1806 mq->specific_address = peer_address;
1807 mq->client = client;
1808 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1809 memcpy (&mq[1], message_buf, message_buf_size);
1810 mq->message_buf = (const char *) &mq[1];
1811 mq->message_buf_size = message_buf_size;
1812 memcpy (&mq->neighbour_id, &neighbour->id,
1813 sizeof (struct GNUNET_PeerIdentity));
1814 mq->internal_msg = is_internal;
1815 mq->priority = priority;
1816 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1818 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1819 neighbour->messages_tail, mq);
1821 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1822 neighbour->messages_tail,
1823 neighbour->messages_tail, mq);
1824 try_transmission_to_peer (neighbour);
1829 * Send a plain PING (without address or our HELLO) to the given
1830 * foreign address to try to establish a connection (and validate
1831 * that the other peer is really who he claimed he is).
1833 * @param n neighbour to PING
1836 transmit_plain_ping (struct NeighbourMapEntry *n)
1838 struct ValidationEntry *ve;
1839 struct TransportPingMessage ping;
1840 struct ReadyList *rl;
1841 struct TransportPlugin *plugin;
1842 struct ForeignAddressList *fal;
1844 if (!n->public_key_valid)
1846 /* This should not happen since the other peer
1847 * should send us a HELLO prior to sending his
1849 GNUNET_break_op (0);
1850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1851 "Could not transmit plain PING to `%s': public key not known\n",
1852 GNUNET_i2s (&n->id));
1855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1856 "Looking for addresses to transmit plain PING to `%s'\n",
1857 GNUNET_i2s (&n->id));
1858 for (rl = n->plugins; rl != NULL; rl = rl->next)
1860 plugin = rl->plugin;
1861 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1863 if (!fal->connected)
1865 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1866 ve->transport_name = GNUNET_strdup (plugin->short_name);
1868 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
1869 ve->send_time = GNUNET_TIME_absolute_get ();
1870 ve->session = fal->session;
1871 memcpy (&ve->publicKey, &n->publicKey,
1872 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1874 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1875 &timeout_hello_validation, ve);
1876 GNUNET_CONTAINER_multihashmap_put (validation_map, &n->id.hashPubKey, ve,
1877 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1878 ping.header.size = htons (sizeof (struct TransportPingMessage));
1879 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1880 ping.challenge = htonl (ve->challenge);
1881 memcpy (&ping.target, &n->id, sizeof (struct GNUNET_PeerIdentity));
1882 GNUNET_STATISTICS_update (stats,
1884 ("# PING without HELLO messages sent"), 1,
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s'\n",
1887 GNUNET_i2s (&n->id));
1888 transmit_to_peer (NULL, fal, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1889 HELLO_VERIFICATION_TIMEOUT, (const char *) &ping,
1890 sizeof (ping), GNUNET_YES, n);
1897 * Mark the given FAL entry as 'connected' (and hence preferred for
1898 * sending); also mark all others for the same peer as 'not connected'
1899 * (since only one can be preferred).
1901 * @param fal address to set to 'connected'
1904 mark_address_connected (struct ForeignAddressList *fal)
1906 struct ForeignAddressList *pos;
1907 struct ForeignAddressList *inbound;
1908 struct ForeignAddressList *outbound;
1910 GNUNET_assert (GNUNET_YES == fal->validated);
1911 if (fal->connected == GNUNET_YES)
1912 return; /* nothing to do */
1916 pos = fal->ready_list->addresses;
1919 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1920 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) &&
1921 (0 == fal->addrlen))
1923 if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1928 pos = fal->ready_list->addresses;
1931 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1932 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) &&
1935 if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1941 if (inbound != NULL)
1942 fprintf (stderr, "Peer: %s, have inbound connection.\n",
1943 GNUNET_i2s (&my_identity));
1944 if (outbound != NULL)
1945 fprintf (stderr, "Peer: %s, have outbound connection.\n",
1946 GNUNET_i2s (&my_identity));
1949 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1950 if ((inbound != NULL) && (0 != fal->addrlen) &&
1952 GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.
1953 hashPubKey, &my_identity.hashPubKey,
1957 fprintf (stderr, "Peer: %s, had inbound connection, ignoring outbound!\n",
1958 GNUNET_i2s (&my_identity));
1962 else if ((outbound != NULL) && (0 == fal->addrlen) &&
1964 GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->
1965 id.hashPubKey, &my_identity.hashPubKey,
1969 fprintf (stderr, "Peer: %s, have outbound connection, ignoring inbound!\n",
1970 GNUNET_i2s (&my_identity));
1975 pos = fal->ready_list->addresses;
1978 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1982 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1983 a2s (pos->ready_list->plugin->short_name, pos->addr,
1987 fprintf (stderr, "Peer: %s, setting %s connection to disconnected.\n",
1988 GNUNET_i2s (&my_identity),
1989 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
1991 pos->connected = GNUNET_NO;
1992 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1997 GNUNET_assert (GNUNET_NO == fal->connected);
1998 fal->connected = GNUNET_YES;
1999 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), 1,
2005 * Find an address in any of the available transports for
2006 * the given neighbour that would be good for message
2007 * transmission. This is essentially the transport selection
2010 * @param neighbour for whom to select an address
2011 * @return selected address, NULL if we have none
2013 struct ForeignAddressList *
2014 find_ready_address (struct NeighbourMapEntry *neighbour)
2016 struct ReadyList *head = neighbour->plugins;
2017 struct ForeignAddressList *addresses;
2018 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2019 struct ForeignAddressList *best_address;
2021 /* Hack to prefer unix domain sockets */
2022 struct ForeignAddressList *unix_address = NULL;
2024 best_address = NULL;
2025 while (head != NULL)
2027 addresses = head->addresses;
2028 while (addresses != NULL)
2030 if ((addresses->timeout.abs_value < now.abs_value) &&
2031 (addresses->connected == GNUNET_YES))
2034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2035 "Marking long-time inactive connection to `%4s' as down.\n",
2036 GNUNET_i2s (&neighbour->id));
2038 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2040 addresses->connected = GNUNET_NO;
2042 addresses = addresses->next;
2045 addresses = head->addresses;
2046 while (addresses != NULL)
2049 if (addresses->addr != NULL)
2050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2051 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2052 a2s (head->plugin->short_name, addresses->addr,
2053 addresses->addrlen), GNUNET_i2s (&neighbour->id),
2054 addresses->connected, addresses->in_transmit,
2055 addresses->validated, addresses->connect_attempts,
2056 (unsigned long long) addresses->timeout.abs_value,
2057 (unsigned int) addresses->distance);
2059 if (0 == strcmp (head->plugin->short_name, "unix"))
2061 if ((unix_address == NULL) ||
2062 ((unix_address != NULL) &&
2063 (addresses->latency.rel_value < unix_address->latency.rel_value)))
2064 unix_address = addresses;
2066 if (((best_address == NULL) || (addresses->connected == GNUNET_YES) ||
2067 (best_address->connected == GNUNET_NO)) &&
2068 (addresses->in_transmit == GNUNET_NO) && ((best_address == NULL) ||
2072 latency.rel_value)))
2073 best_address = addresses;
2074 /* FIXME: also give lower-latency addresses that are not
2075 * connected a chance some times... */
2076 addresses = addresses->next;
2078 if (unix_address != NULL)
2082 if (unix_address != NULL)
2084 best_address = unix_address;
2086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2087 "Found UNIX address, forced this address\n");
2090 if (best_address != NULL)
2093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2094 "Best address found (`%s') has latency of %llu ms.\n",
2095 (best_address->addrlen >
2096 0) ? a2s (best_address->ready_list->plugin->short_name,
2098 best_address->addrlen) : "<inbound>",
2099 best_address->latency.rel_value);
2104 GNUNET_STATISTICS_update (stats,
2106 ("# transmission attempts failed (no address)"),
2110 return best_address;
2117 struct GeneratorContext
2119 struct TransportPlugin *plug_pos;
2120 struct OwnAddressList *addr_pos;
2121 struct GNUNET_TIME_Absolute expiration;
2129 address_generator (void *cls, size_t max, void *buf)
2131 struct GeneratorContext *gc = cls;
2134 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2136 gc->plug_pos = gc->plug_pos->next;
2137 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2139 if (NULL == gc->plug_pos)
2145 GNUNET_HELLO_add_address (gc->plug_pos->short_name, gc->expiration,
2146 &gc->addr_pos[1], gc->addr_pos->addrlen, buf,
2148 gc->addr_pos = gc->addr_pos->next;
2155 transmit_our_hello_if_pong (void *cls, const GNUNET_HashCode * key, void *value)
2157 struct NeighbourMapEntry *npos = value;
2159 if (GNUNET_YES != npos->received_pong)
2162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2163 "Transmitting updated `%s' to neighbour `%4s'\n", "HELLO",
2164 GNUNET_i2s (&npos->id));
2166 GNUNET_STATISTICS_update (stats,
2168 ("# transmitted my HELLO to other peers"), 1,
2170 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
2171 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
2178 * Construct our HELLO message from all of the addresses of
2179 * all of the transports.
2182 * @param tc scheduler context
2185 refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2187 struct GNUNET_HELLO_Message *hello;
2188 struct TransportClient *cpos;
2189 struct GeneratorContext gc;
2191 hello_task = GNUNET_SCHEDULER_NO_TASK;
2192 gc.plug_pos = plugins;
2193 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2194 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2195 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2198 "Refreshed my `%s', new size is %d\n", "HELLO",
2199 GNUNET_HELLO_size (hello));
2201 GNUNET_STATISTICS_update (stats, gettext_noop ("# refreshed my HELLO"), 1,
2204 while (cpos != NULL)
2206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting my HELLO to client!\n");
2207 transmit_to_client (cpos, (const struct GNUNET_MessageHeader *) hello,
2212 GNUNET_free_non_null (our_hello);
2214 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2215 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2216 &transmit_our_hello_if_pong, NULL);
2221 * Schedule task to refresh hello (unless such a
2222 * task exists already).
2227 #if DEBUG_TRANSPORT_HELLO
2228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refresh_hello() called!\n");
2230 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2232 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
2237 * Iterator over hash map entries that NULLs the session of validation
2238 * entries that match the given session.
2240 * @param cls closure (the 'struct Session*' to match against)
2241 * @param key current key code (peer ID, not used)
2242 * @param value value in the hash map ('struct ValidationEntry*')
2243 * @return GNUNET_YES (we should continue to iterate)
2246 remove_session_validations (void *cls, const GNUNET_HashCode * key, void *value)
2248 struct Session *session = cls;
2249 struct ValidationEntry *ve = value;
2251 if (session == ve->session)
2258 * We've been disconnected from the other peer (for some
2259 * connection-oriented transport). Either quickly
2260 * re-establish the connection or signal the disconnect
2263 * Only signal CORE level disconnect if ALL addresses
2264 * for the peer are exhausted.
2266 * @param p overall plugin context
2267 * @param nl neighbour that was disconnected
2270 try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl)
2272 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2273 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "try_fast_reconnect not implemented!\n");
2274 /* Note: the idea here is to hide problems with transports (or
2275 * switching between plugins) from the core to eliminate the need to
2276 * re-negotiate session keys and the like; OTOH, we should tell core
2277 * quickly (much faster than timeout) `if a connection was lost and
2278 * could not be re-established (i.e. other peer went down or is
2279 * unable / refuses to communicate);
2281 * So we should consider:
2282 * 1) ideally: our own willingness / need to connect
2283 * 2) prior failures to connect to this peer (by plugin)
2284 * 3) ideally: reasons why other peer terminated (as far as knowable)
2286 * Most importantly, it must be POSSIBLE for another peer to terminate
2287 * a connection for a while (without us instantly re-establishing it).
2288 * Similarly, if another peer is gone we should quickly notify CORE.
2289 * OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2290 * on the other end), we should reconnect in such a way that BOTH CORE
2291 * services never even notice.
2292 * Furthermore, the same mechanism (or small variation) could be used
2293 * to switch to a better-performing plugin (ATS).
2295 * Finally, this needs to be tested throughly... */
2298 * GNUNET_NO in the call below makes transport disconnect the peer,
2299 * even if only a single address (out of say, six) went away. This
2300 * function must be careful to ONLY disconnect if the peer is gone,
2301 * not just a specific address.
2303 * More specifically, half the places it was used had it WRONG.
2306 /* No reconnect, signal disconnect instead! */
2309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2310 GNUNET_i2s (&nl->id), "try_fast_reconnect");
2312 GNUNET_STATISTICS_update (stats,
2314 ("# disconnects due to try_fast_reconnect"), 1,
2317 disconnect_neighbour (nl, GNUNET_YES);
2323 * Function that will be called whenever the plugin internally
2324 * cleans up a session pointer and hence the service needs to
2325 * discard all of those sessions as well. Plugins that do not
2326 * use sessions can simply omit calling this function and always
2327 * use NULL wherever a session pointer is needed.
2329 * @param cls closure
2330 * @param peer which peer was the session for
2331 * @param session which session is being destoyed
2334 plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
2335 struct Session *session)
2337 struct TransportPlugin *p = cls;
2338 struct NeighbourMapEntry *nl;
2339 struct ReadyList *rl;
2340 struct ForeignAddressList *pos;
2341 struct ForeignAddressList *prev;
2344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session ended with peer `%4s', %s\n",
2345 GNUNET_i2s (peer), "plugin_env_session_end");
2347 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2348 &remove_session_validations, session);
2349 nl = find_neighbour (peer);
2353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2354 "No neighbour record found for peer `%4s'\n",
2357 return; /* was never marked as connected */
2362 if (rl->plugin == p)
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370 "Plugin was associated with peer `%4s'\n", GNUNET_i2s (peer));
2372 GNUNET_STATISTICS_update (stats,
2373 gettext_noop ("# disconnects due to session end"),
2375 disconnect_neighbour (nl, GNUNET_YES);
2379 pos = rl->addresses;
2380 while ((pos != NULL) && (pos->session != session))
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2389 "Session was never marked as ready for peer `%4s'\n",
2393 int validations_pending =
2394 GNUNET_CONTAINER_multihashmap_contains (validation_map,
2397 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2398 if (validations_pending == GNUNET_YES)
2401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2402 "Not disconnecting from peer `%4s due to pending address validations\n",
2408 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2409 GNUNET_STATISTICS_update (stats,
2411 ("# disconnects due to unready session"), 1,
2414 disconnect_neighbour (nl, GNUNET_YES);
2415 return; /* was never marked as connected */
2417 pos->session = NULL;
2418 if (GNUNET_YES == pos->connected)
2420 pos->connected = GNUNET_NO;
2421 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2424 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2426 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2427 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2430 if (pos->addrlen != 0)
2432 if (nl->received_pong != GNUNET_NO)
2434 GNUNET_STATISTICS_update (stats,
2436 ("# try_fast_reconnect thanks to plugin_env_session_end"),
2438 if (GNUNET_YES == pos->connected)
2439 try_fast_reconnect (p, nl);
2443 GNUNET_STATISTICS_update (stats,
2445 ("# disconnects due to missing pong"), 1,
2447 /* FIXME this is never true?! See: line 2416 */
2448 if (GNUNET_YES == pos->connected)
2449 disconnect_neighbour (nl, GNUNET_YES);
2454 /* was inbound connection, free 'pos' */
2456 rl->addresses = pos->next;
2458 prev->next = pos->next;
2459 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2461 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2462 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2464 GNUNET_free_non_null (pos->ressources);
2465 GNUNET_free_non_null (pos->quality);
2467 ats_modify_problem_state (ats, ATS_MODIFIED);
2469 if (GNUNET_YES != pos->connected)
2471 /* nothing else to do, connection was never up... */
2475 pos->connected = GNUNET_NO;
2476 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2480 if (nl->received_pong == GNUNET_NO)
2482 GNUNET_STATISTICS_update (stats,
2483 gettext_noop ("# disconnects due to NO pong"), 1,
2485 disconnect_neighbour (nl, GNUNET_YES);
2486 return; /* nothing to do, never connected... */
2488 /* check if we have any validated addresses left */
2489 pos = rl->addresses;
2492 if (GNUNET_YES == pos->validated)
2494 GNUNET_STATISTICS_update (stats,
2496 ("# try_fast_reconnect thanks to validated_address"),
2498 try_fast_reconnect (p, nl);
2503 /* no valid addresses left, signal disconnect! */
2506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2507 GNUNET_i2s (peer), "plugin_env_session_end");
2509 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2510 * it means there aren't any left for this PLUGIN/PEER combination! So
2511 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2512 * when it isn't necessary. Using GNUNET_YES at least checks to see
2513 * if there are any addresses that work first, so as not to overdo it.
2516 GNUNET_STATISTICS_update (stats,
2518 ("# disconnects due to plugin_env_session_end"), 1,
2520 disconnect_neighbour (nl, GNUNET_YES);
2525 * Function that must be called by each plugin to notify the
2526 * transport service about the addresses under which the transport
2527 * provided by the plugin can be reached.
2529 * @param cls closure
2530 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2531 * @param addr one of the addresses of the host, NULL for the last address
2532 * the specific address format depends on the transport
2533 * @param addrlen length of the address
2536 plugin_env_notify_address (void *cls, int add_remove, const void *addr,
2539 struct TransportPlugin *p = cls;
2540 struct OwnAddressList *al;
2541 struct OwnAddressList *prev;
2543 GNUNET_assert (p->api != NULL);
2545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547 GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" :
2548 "Removing `%s':%s from the set of our addresses\n",
2549 a2s (p->short_name, addr, addrlen), p->short_name);
2551 GNUNET_assert (addr != NULL);
2552 if (GNUNET_NO == add_remove)
2558 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2561 p->addresses = al->next;
2563 prev->next = al->next;
2574 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2575 al->next = p->addresses;
2577 al->addrlen = addrlen;
2578 memcpy (&al[1], addr, addrlen);
2584 * Notify all of our clients about a peer connecting.
2587 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2588 struct GNUNET_TIME_Relative latency, uint32_t distance)
2590 struct ConnectInfoMessage *cim;
2591 struct TransportClient *cpos;
2595 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2602 "Notifying clients about connection with `%s'\n",
2605 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), 1,
2610 sizeof (struct ConnectInfoMessage) +
2611 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2612 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2613 cim = GNUNET_malloc (size);
2614 cim->header.size = htons (size);
2615 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2616 cim->ats_count = htonl (2);
2617 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2618 (&cim->ats)[0].value = htonl (distance);
2619 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2620 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2621 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2622 (&cim->ats)[2].value = htonl (0);
2623 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2625 /* notify ats about connecting peer */
2626 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2629 ats_modify_problem_state (ats, ATS_MODIFIED);
2630 ats_calculate_bandwidth_distribution (ats);
2634 while (cpos != NULL)
2636 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2644 * Notify all of our clients about a peer disconnecting.
2647 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2649 struct DisconnectInfoMessage dim;
2650 struct TransportClient *cpos;
2652 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2659 "Notifying clients about lost connection to `%s'\n",
2662 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), -1,
2664 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2665 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2666 dim.reserved = htonl (0);
2667 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2669 /* notify ats about connecting peer */
2670 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2673 ats_modify_problem_state (ats, ATS_MODIFIED);
2674 ats_calculate_bandwidth_distribution (ats);
2679 while (cpos != NULL)
2681 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2688 * Find a ForeignAddressList entry for the given neighbour
2689 * that matches the given address and transport.
2691 * @param neighbour which peer we care about
2692 * @param tname name of the transport plugin
2693 * @param session session to look for, NULL for 'any'; otherwise
2694 * can be used for the service to "learn" this session ID
2696 * @param addr binary address
2697 * @param addrlen length of addr
2698 * @return NULL if no such entry exists
2700 static struct ForeignAddressList *
2701 find_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2702 struct Session *session, const char *addr, uint16_t addrlen)
2704 struct ReadyList *head;
2705 struct ForeignAddressList *pos;
2707 head = neighbour->plugins;
2708 while (head != NULL)
2710 if (0 == strcmp (tname, head->plugin->short_name))
2716 pos = head->addresses;
2717 while ((pos != NULL) &&
2718 ((pos->addrlen != addrlen) ||
2719 (memcmp (pos->addr, addr, addrlen) != 0)))
2721 if ((session != NULL) && (pos->session == session))
2725 if ((session != NULL) && (pos != NULL))
2726 pos->session = session; /* learn it! */
2732 * Get the peer address struct for the given neighbour and
2733 * address. If it doesn't yet exist, create it.
2735 * @param neighbour which peer we care about
2736 * @param tname name of the transport plugin
2737 * @param session session of the plugin, or NULL for none
2738 * @param addr binary address
2739 * @param addrlen length of addr
2740 * @return NULL if we do not have a transport plugin for 'tname'
2742 static struct ForeignAddressList *
2743 add_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2744 struct Session *session, const char *addr, uint16_t addrlen)
2746 struct ReadyList *head;
2747 struct ForeignAddressList *ret;
2750 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2753 head = neighbour->plugins;
2755 while (head != NULL)
2757 if (0 == strcmp (tname, head->plugin->short_name))
2763 ret = GNUNET_malloc (sizeof (struct ForeignAddressList) + addrlen);
2764 ret->session = session;
2765 if ((addrlen > 0) && (addr != NULL))
2767 ret->addr = (const char *) &ret[1];
2768 memcpy (&ret[1], addr, addrlen);
2776 GNUNET_malloc (available_ressources *
2777 sizeof (struct ATS_ressource_entry));
2778 for (c = 0; c < available_ressources; c++)
2780 struct ATS_ressource_entry *r = ret->ressources;
2783 r[c].atis_index = ressources[c].atis_index;
2784 if (0 == strcmp (neighbour->plugins->plugin->short_name, "unix"))
2786 r[c].c = ressources[c].c_unix;
2788 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "udp"))
2790 r[c].c = ressources[c].c_udp;
2792 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "tcp"))
2794 r[c].c = ressources[c].c_tcp;
2796 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "http"))
2798 r[c].c = ressources[c].c_http;
2800 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "https"))
2802 r[c].c = ressources[c].c_https;
2804 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "wlan"))
2806 r[c].c = ressources[c].c_wlan;
2810 r[c].c = ressources[c].c_default;
2811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2812 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2813 GNUNET_i2s (&neighbour->id),
2814 neighbour->plugins->plugin->short_name);
2819 GNUNET_malloc (available_quality_metrics *
2820 sizeof (struct ATS_quality_entry));
2821 ret->addrlen = addrlen;
2823 GNUNET_TIME_relative_to_absolute
2824 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2825 ret->latency = GNUNET_TIME_relative_get_forever ();
2828 GNUNET_TIME_relative_to_absolute
2829 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2830 ret->ready_list = head;
2831 ret->next = head->addresses;
2832 head->addresses = ret;
2838 * Closure for 'add_validated_address'.
2840 struct AddValidatedAddressContext
2843 * Entry that has been validated.
2845 const struct ValidationEntry *ve;
2848 * Flag set after we have added the address so
2849 * that we terminate the iteration next time.
2856 * Callback function used to fill a buffer of max bytes with a list of
2857 * addresses in the format used by HELLOs. Should use
2858 * "GNUNET_HELLO_add_address" as a helper function.
2860 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2861 * @param max maximum number of bytes that can be written to buf
2862 * @param buf where to write the address information
2863 * @return number of bytes written, 0 to signal the
2864 * end of the iteration.
2867 add_validated_address (void *cls, size_t max, void *buf)
2869 struct AddValidatedAddressContext *avac = cls;
2870 const struct ValidationEntry *ve = avac->ve;
2872 if (GNUNET_YES == avac->done)
2874 avac->done = GNUNET_YES;
2875 return GNUNET_HELLO_add_address (ve->transport_name,
2876 GNUNET_TIME_relative_to_absolute
2877 (HELLO_ADDRESS_EXPIRATION), ve->addr,
2878 ve->addrlen, buf, max);
2884 * Closure for 'check_address_exists'.
2886 struct CheckAddressExistsClosure
2889 * Address to check for.
2894 * Name of the transport.
2901 struct Session *session;
2904 * Set to GNUNET_YES if the address exists.
2917 * Iterator over hash map entries. Checks if the given
2918 * validation entry is for the same address as what is given
2921 * @param cls the 'struct CheckAddressExistsClosure*'
2922 * @param key current key code (ignored)
2923 * @param value value in the hash map ('struct ValidationEntry')
2924 * @return GNUNET_YES if we should continue to
2925 * iterate (mismatch), GNUNET_NO if not (entry matched)
2928 check_address_exists (void *cls, const GNUNET_HashCode * key, void *value)
2930 struct CheckAddressExistsClosure *caec = cls;
2931 struct ValidationEntry *ve = value;
2933 if ((0 == strcmp (caec->tname, ve->transport_name)) &&
2934 (caec->addrlen == ve->addrlen) &&
2935 (0 == memcmp (caec->addr, ve->addr, caec->addrlen)))
2937 caec->exists = GNUNET_YES;
2940 if ((ve->session != NULL) && (caec->session == ve->session))
2942 caec->exists = GNUNET_YES;
2950 neighbour_timeout_task (void *cls,
2951 const struct GNUNET_SCHEDULER_TaskContext *tc)
2953 struct NeighbourMapEntry *n = cls;
2956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2957 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2959 GNUNET_STATISTICS_update (stats,
2960 gettext_noop ("# disconnects due to timeout"), 1,
2962 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2963 disconnect_neighbour (n, GNUNET_NO);
2968 * Schedule the job that will cause us to send a PING to the
2969 * foreign address to evaluate its validity and latency.
2971 * @param fal address to PING
2974 schedule_next_ping (struct ForeignAddressList *fal);
2978 * Add the given address to the list of foreign addresses
2979 * available for the given peer (check for duplicates).
2981 * @param cls the respective 'struct NeighbourMapEntry' to update
2982 * @param tname name of the transport
2983 * @param expiration expiration time
2984 * @param addr the address
2985 * @param addrlen length of the address
2986 * @return GNUNET_OK (always)
2989 add_to_foreign_address_list (void *cls, const char *tname,
2990 struct GNUNET_TIME_Absolute expiration,
2991 const void *addr, uint16_t addrlen)
2993 struct NeighbourMapEntry *n = cls;
2994 struct ForeignAddressList *fal;
2997 GNUNET_STATISTICS_update (stats,
2999 ("# valid peer addresses returned by PEERINFO"), 1,
3002 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3005 #if DEBUG_TRANSPORT_HELLO
3006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3007 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3008 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&n->id),
3009 expiration.abs_value);
3011 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3014 GNUNET_STATISTICS_update (stats,
3016 ("# previously validated addresses lacking transport"),
3021 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3022 schedule_next_ping (fal);
3028 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3034 "Failed to add new address for `%4s'\n", GNUNET_i2s (&n->id));
3038 if (fal->validated == GNUNET_NO)
3040 fal->validated = GNUNET_YES;
3041 GNUNET_STATISTICS_update (stats,
3043 ("# peer addresses considered valid"), 1,
3046 if (try == GNUNET_YES)
3049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3050 "Have new addresses, will try to trigger transmissions.\n");
3052 try_transmission_to_peer (n);
3059 * Add addresses in validated HELLO "h" to the set of addresses
3060 * we have for this peer.
3062 * @param cls closure ('struct NeighbourMapEntry*')
3063 * @param peer id of the peer, NULL for last call
3064 * @param h hello message for the peer (can be NULL)
3065 * @param err_msg NULL if successful, otherwise contains error message
3068 add_hello_for_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
3069 const struct GNUNET_HELLO_Message *h, const char *err_msg)
3071 struct NeighbourMapEntry *n = cls;
3073 if (err_msg != NULL)
3076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3077 _("Error in communication with PEERINFO service: %s\n"),
3084 GNUNET_STATISTICS_update (stats,
3086 ("# outstanding peerinfo iterate requests"), -1,
3092 return; /* no HELLO available */
3094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3095 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3096 "HELLO", GNUNET_i2s (peer));
3098 if (GNUNET_YES != n->public_key_valid)
3100 GNUNET_HELLO_get_key (h, &n->publicKey);
3101 n->public_key_valid = GNUNET_YES;
3103 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
3109 * Create a fresh entry in our neighbour list for the given peer.
3110 * Will try to transmit our current HELLO to the new neighbour.
3111 * Do not call this function directly, use 'setup_peer_check_blacklist.
3113 * @param peer the peer for which we create the entry
3114 * @param do_hello should we schedule transmitting a HELLO
3115 * @return the new neighbour list entry
3117 static struct NeighbourMapEntry *
3118 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer, int do_hello)
3120 struct NeighbourMapEntry *n;
3121 struct TransportPlugin *tp;
3122 struct ReadyList *rl;
3125 memcmp (peer, &my_identity,
3126 sizeof (struct GNUNET_PeerIdentity)));
3128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up state for neighbour `%4s'\n",
3131 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), 1,
3133 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3136 GNUNET_TIME_relative_to_absolute
3137 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3138 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3139 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3140 MAX_BANDWIDTH_CARRY_S);
3144 if ((tp->api->send != NULL) && (!is_blacklisted (peer, tp)))
3146 rl = GNUNET_malloc (sizeof (struct ReadyList));
3148 rl->next = n->plugins;
3151 rl->addresses = NULL;
3155 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3158 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3159 &neighbour_timeout_task, n);
3160 GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n,
3161 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3164 GNUNET_STATISTICS_update (stats,
3166 ("# peerinfo new neighbor iterate requests"), 1,
3168 GNUNET_STATISTICS_update (stats,
3170 ("# outstanding peerinfo iterate requests"), 1,
3173 GNUNET_PEERINFO_iterate (peerinfo, peer, GNUNET_TIME_UNIT_FOREVER_REL,
3174 &add_hello_for_peer, n);
3176 GNUNET_STATISTICS_update (stats,
3177 gettext_noop ("# HELLO's sent to new neighbors"),
3179 if (NULL != our_hello)
3180 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
3181 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
3189 * Function called after we have checked if communicating
3190 * with a given peer is acceptable.
3192 * @param cls closure
3193 * @param n NULL if communication is not acceptable
3195 typedef void (*SetupContinuation) (void *cls, struct NeighbourMapEntry * n);
3199 * Information kept for each client registered to perform
3205 * This is a linked list.
3207 struct Blacklisters *next;
3210 * This is a linked list.
3212 struct Blacklisters *prev;
3215 * Client responsible for this entry.
3217 struct GNUNET_SERVER_Client *client;
3220 * Blacklist check that we're currently performing.
3222 struct BlacklistCheck *bc;
3228 * Head of DLL of blacklisting clients.
3230 static struct Blacklisters *bl_head;
3233 * Tail of DLL of blacklisting clients.
3235 static struct Blacklisters *bl_tail;
3239 * Context we use when performing a blacklist check.
3241 struct BlacklistCheck
3245 * This is a linked list.
3247 struct BlacklistCheck *next;
3250 * This is a linked list.
3252 struct BlacklistCheck *prev;
3255 * Peer being checked.
3257 struct GNUNET_PeerIdentity peer;
3260 * Option for setup neighbour afterwards.
3265 * Continuation to call with the result.
3267 SetupContinuation cont;
3275 * Current transmission request handle for this client, or NULL if no
3276 * request is pending.
3278 struct GNUNET_CONNECTION_TransmitHandle *th;
3281 * Our current position in the blacklisters list.
3283 struct Blacklisters *bl_pos;
3286 * Current task performing the check.
3288 GNUNET_SCHEDULER_TaskIdentifier task;
3293 * Head of DLL of active blacklisting queries.
3295 static struct BlacklistCheck *bc_head;
3298 * Tail of DLL of active blacklisting queries.
3300 static struct BlacklistCheck *bc_tail;
3304 * Perform next action in the blacklist check.
3306 * @param cls the 'struct BlacklistCheck*'
3310 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3313 * Transmit blacklist query to the client.
3315 * @param cls the 'struct BlacklistCheck'
3316 * @param size number of bytes allowed
3317 * @param buf where to copy the message
3318 * @return number of bytes copied to buf
3321 transmit_blacklist_message (void *cls, size_t size, void *buf)
3323 struct BlacklistCheck *bc = cls;
3324 struct Blacklisters *bl;
3325 struct BlacklistMessage bm;
3330 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3331 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3332 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3333 "Failed to send blacklist test for peer `%s' to client\n",
3334 GNUNET_i2s (&bc->peer));
3338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3339 "Sending blacklist test for peer `%s' to client\n",
3340 GNUNET_i2s (&bc->peer));
3343 bm.header.size = htons (sizeof (struct BlacklistMessage));
3344 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3345 bm.is_allowed = htonl (0);
3347 memcpy (buf, &bm, sizeof (bm));
3348 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3354 * Perform next action in the blacklist check.
3356 * @param cls the 'struct BlacklistCheck*'
3360 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3362 struct BlacklistCheck *bc = cls;
3363 struct Blacklisters *bl;
3365 bc->task = GNUNET_SCHEDULER_NO_TASK;
3370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3371 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3372 GNUNET_i2s (&bc->peer));
3374 bc->cont (bc->cont_cls, setup_new_neighbour (&bc->peer, bc->do_hello));
3382 GNUNET_SERVER_notify_transmit_ready (bl->client,
3383 sizeof (struct BlacklistMessage),
3384 GNUNET_TIME_UNIT_FOREVER_REL,
3385 &transmit_blacklist_message, bc);
3391 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3392 * does not yet exist, check the blacklist. If the blacklist says creating
3393 * one is acceptable, create one and call the continuation; otherwise
3394 * call the continuation with NULL.
3396 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3397 * @param do_hello should we also schedule sending our HELLO to the peer
3398 * if this is a new record
3399 * @param cont function to call with the 'struct NeigbhbourList*'
3400 * @param cont_cls closure for cont
3403 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3404 int do_hello, SetupContinuation cont,
3407 struct NeighbourMapEntry *n;
3408 struct BlacklistCheck *bc;
3410 n = find_neighbour (peer);
3414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3415 "Neighbour record exists for peer `%s'\n", GNUNET_i2s (peer));
3421 if (bl_head == NULL)
3424 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3426 setup_new_neighbour (peer, do_hello);
3429 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3430 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3432 bc->do_hello = do_hello;
3434 bc->cont_cls = cont_cls;
3435 bc->bl_pos = bl_head;
3436 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3441 * Function called with the result of querying a new blacklister about
3442 * it being allowed (or not) to continue to talk to an existing neighbour.
3444 * @param cls the original 'struct NeighbourMapEntry'
3445 * @param n NULL if we need to disconnect
3448 confirm_or_drop_neighbour (void *cls, struct NeighbourMapEntry *n)
3450 struct NeighbourMapEntry *orig = cls;
3455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
3456 GNUNET_i2s (&orig->id), "confirm_or_drop_neighboUr");
3458 GNUNET_STATISTICS_update (stats,
3459 gettext_noop ("# disconnects due to blacklist"),
3461 disconnect_neighbour (orig, GNUNET_NO);
3466 struct TestConnectionContext
3470 struct Blacklisters *bl;
3475 test_connection_ok (void *cls, const GNUNET_HashCode * key, void *value)
3477 struct TestConnectionContext *tcc = cls;
3478 struct NeighbourMapEntry *n = value;
3479 struct BlacklistCheck *bc;
3482 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3483 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3485 bc->do_hello = GNUNET_NO;
3486 bc->cont = &confirm_or_drop_neighbour;
3488 bc->bl_pos = tcc->bl;
3489 if (GNUNET_YES == tcc->first)
3491 /* all would wait for the same client, no need to
3492 * create more than just the first task right now */
3493 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3494 tcc->first = GNUNET_NO;
3501 * Handle a request to start a blacklist.
3503 * @param cls closure (always NULL)
3504 * @param client identification of the client
3505 * @param message the actual message
3508 handle_blacklist_init (void *cls, struct GNUNET_SERVER_Client *client,
3509 const struct GNUNET_MessageHeader *message)
3511 struct Blacklisters *bl;
3512 struct TestConnectionContext tcc;
3517 if (bl->client == client)
3520 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3525 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3526 bl->client = client;
3527 GNUNET_SERVER_client_keep (client);
3528 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3529 /* confirm that all existing connections are OK! */
3531 tcc.first = GNUNET_YES;
3532 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &test_connection_ok, &tcc);
3537 * Handle a request to blacklist a peer.
3539 * @param cls closure (always NULL)
3540 * @param client identification of the client
3541 * @param message the actual message
3544 handle_blacklist_reply (void *cls, struct GNUNET_SERVER_Client *client,
3545 const struct GNUNET_MessageHeader *message)
3547 const struct BlacklistMessage *msg =
3548 (const struct BlacklistMessage *) message;
3549 struct Blacklisters *bl;
3550 struct BlacklistCheck *bc;
3553 while ((bl != NULL) && (bl->client != client))
3558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
3560 /* FIXME: other error handling here!? */
3561 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3566 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3570 "Blacklist check failed, peer not allowed\n");
3572 bc->cont (bc->cont_cls, NULL);
3573 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3580 "Blacklist check succeeded, continuing with checks\n");
3582 bc->bl_pos = bc->bl_pos->next;
3583 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3585 /* check if any other bc's are waiting for this blacklister */
3589 if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
3590 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3597 * Send periodic PING messages to a given foreign address.
3599 * @param cls our 'struct PeriodicValidationContext*'
3600 * @param tc task context
3603 send_periodic_ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3605 struct ForeignAddressList *peer_address = cls;
3606 struct TransportPlugin *tp;
3607 struct ValidationEntry *va;
3608 struct NeighbourMapEntry *neighbour;
3609 struct TransportPingMessage ping;
3610 struct CheckAddressExistsClosure caec;
3612 uint16_t hello_size;
3616 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3617 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3619 GNUNET_assert (peer_address != NULL);
3620 tp = peer_address->ready_list->plugin;
3621 neighbour = peer_address->ready_list->neighbour;
3622 if (GNUNET_YES != neighbour->public_key_valid)
3624 /* no public key yet, try again later */
3625 schedule_next_ping (peer_address);
3628 caec.addr = peer_address->addr;
3629 caec.addrlen = peer_address->addrlen;
3630 caec.tname = tp->short_name;
3631 caec.session = peer_address->session;
3632 caec.exists = GNUNET_NO;
3634 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
3636 if (caec.exists == GNUNET_YES)
3638 /* During validation attempts we will likely trigger the other
3639 * peer trying to validate our address which in turn will cause
3640 * it to send us its HELLO, so we expect to hit this case rather
3641 * frequently. Only print something if we are very verbose. */
3642 #if DEBUG_TRANSPORT > 1
3643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3644 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3645 (peer_address->addr != NULL) ? a2s (tp->short_name,
3647 peer_address->addrlen) :
3648 "<inbound>", tp->short_name, GNUNET_i2s (&neighbour->id));
3650 schedule_next_ping (peer_address);
3653 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3654 va->transport_name = GNUNET_strdup (tp->short_name);
3656 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
3657 va->send_time = GNUNET_TIME_absolute_get ();
3658 va->session = peer_address->session;
3659 if (peer_address->addr != NULL)
3661 va->addr = (const void *) &va[1];
3662 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3663 va->addrlen = peer_address->addrlen;
3665 memcpy (&va->publicKey, &neighbour->publicKey,
3666 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3669 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3670 &timeout_hello_validation, va);
3671 GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->id.hashPubKey,
3673 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3675 if (peer_address->validated != GNUNET_YES)
3676 hello_size = GNUNET_HELLO_size (our_hello);
3680 tsize = sizeof (struct TransportPingMessage) + hello_size;
3682 if (peer_address->addr != NULL)
3684 slen = strlen (tp->short_name) + 1;
3685 tsize += slen + peer_address->addrlen;
3689 slen = 0; /* make gcc happy */
3691 message_buf = GNUNET_malloc (tsize);
3692 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3693 ping.challenge = htonl (va->challenge);
3694 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
3695 if (peer_address->validated != GNUNET_YES)
3697 memcpy (message_buf, our_hello, hello_size);
3700 if (peer_address->addr != NULL)
3703 htons (sizeof (struct TransportPingMessage) + peer_address->addrlen +
3705 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3706 tp->short_name, slen);
3707 memcpy (&message_buf
3708 [hello_size + sizeof (struct TransportPingMessage) + slen],
3709 peer_address->addr, peer_address->addrlen);
3713 ping.header.size = htons (sizeof (struct TransportPingMessage));
3716 memcpy (&message_buf[hello_size], &ping,
3717 sizeof (struct TransportPingMessage));
3719 #if DEBUG_TRANSPORT_REVALIDATION
3720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3721 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3722 (peer_address->addr !=
3723 NULL) ? a2s (peer_address->plugin->short_name,
3725 peer_address->addrlen) : "<inbound>",
3726 tp->short_name, GNUNET_i2s (&neighbour->id), "HELLO", hello_size,
3729 if (peer_address->validated != GNUNET_YES)
3730 GNUNET_STATISTICS_update (stats,
3731 gettext_noop ("# PING with HELLO messages sent"),
3734 GNUNET_STATISTICS_update (stats,
3736 ("# PING without HELLO messages sent"), 1,
3738 GNUNET_STATISTICS_update (stats,
3740 ("# PING messages sent for re-validation"), 1,
3742 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3743 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
3745 GNUNET_free (message_buf);
3746 schedule_next_ping (peer_address);
3751 * Schedule the job that will cause us to send a PING to the
3752 * foreign address to evaluate its validity and latency.
3754 * @param fal address to PING
3757 schedule_next_ping (struct ForeignAddressList *fal)
3759 struct GNUNET_TIME_Relative delay;
3761 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3763 GNUNET_SCHEDULER_cancel (fal->revalidate_task);
3764 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3766 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3767 delay.rel_value /= 2; /* do before expiration */
3768 delay = GNUNET_TIME_relative_min (delay, LATENCY_EVALUATION_MAX_DELAY);
3769 if (GNUNET_YES != fal->estimated)
3771 delay = GNUNET_TIME_UNIT_ZERO;
3772 fal->estimated = GNUNET_YES;
3775 if (GNUNET_YES == fal->connected)
3778 GNUNET_TIME_relative_min (delay,
3779 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3781 /* FIXME: also adjust delay based on how close the last
3782 * observed latency is to the latency of the best alternative */
3783 /* bound how fast we can go */
3784 delay = GNUNET_TIME_relative_max (delay, GNUNET_TIME_UNIT_SECONDS);
3785 /* randomize a bit (to avoid doing all at the same time) */
3787 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3789 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3790 fal->revalidate_task =
3791 GNUNET_SCHEDULER_add_delayed (delay, &send_periodic_ping, fal);
3798 * Function that will be called if we receive some payload
3799 * from another peer.
3801 * @param message the payload
3802 * @param n peer who claimed to be the sender
3805 handle_payload_message (const struct GNUNET_MessageHeader *message,
3806 struct NeighbourMapEntry *n)
3808 struct InboundMessage *im;
3809 struct TransportClient *cpos;
3812 msize = ntohs (message->size);
3813 if (n->received_pong == GNUNET_NO)
3816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3817 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3818 ntohs (message->type), ntohs (message->size),
3819 GNUNET_i2s (&n->id));
3821 GNUNET_free_non_null (n->pre_connect_message_buffer);
3822 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3823 memcpy (n->pre_connect_message_buffer, message, msize);
3828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3829 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3830 ntohs (message->type), ntohs (message->size),
3831 GNUNET_i2s (&n->id));
3834 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, (ssize_t) msize))
3836 n->quota_violation_count++;
3838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3839 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3840 n->in_tracker.available_bytes_per_s__,
3841 n->quota_violation_count);
3843 /* Discount 32k per violation */
3844 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
3848 if (n->quota_violation_count > 0)
3850 /* try to add 32k back */
3851 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
3852 n->quota_violation_count--;
3855 GNUNET_STATISTICS_update (stats,
3857 ("# payload received from other peers"), msize,
3859 /* transmit message to all clients */
3860 uint32_t ats_count = 2;
3862 sizeof (struct InboundMessage) +
3863 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3864 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3867 im = GNUNET_malloc (size);
3868 im->header.size = htons (size);
3869 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3871 im->ats_count = htonl (ats_count);
3872 /* Setting ATS data */
3873 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3874 (&(im->ats))[0].value = htonl (n->distance);
3875 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3876 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3877 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3878 (&(im->ats))[ats_count].value = htonl (0);
3880 memcpy (&((&(im->ats))[ats_count + 1]), message, msize);
3882 while (cpos != NULL)
3884 transmit_to_client (cpos, &im->header, GNUNET_YES);
3892 * Iterator over hash map entries. Checks if the given validation
3893 * entry is for the same challenge as what is given in the PONG.
3895 * @param cls the 'struct TransportPongMessage*'
3896 * @param key peer identity
3897 * @param value value in the hash map ('struct ValidationEntry')
3898 * @return GNUNET_YES if we should continue to
3899 * iterate (mismatch), GNUNET_NO if not (entry matched)
3902 check_pending_validation (void *cls, const GNUNET_HashCode * key, void *value)
3904 const struct TransportPongMessage *pong = cls;
3905 struct ValidationEntry *ve = value;
3906 struct AddValidatedAddressContext avac;
3907 unsigned int challenge = ntohl (pong->challenge);
3908 struct GNUNET_HELLO_Message *hello;
3909 struct GNUNET_PeerIdentity target;
3910 struct NeighbourMapEntry *n;
3911 struct ForeignAddressList *fal;
3912 struct OwnAddressList *oal;
3913 struct TransportPlugin *tp;
3914 struct GNUNET_MessageHeader *prem;
3920 ps = ntohs (pong->header.size);
3921 if (ps < sizeof (struct TransportPongMessage))
3923 GNUNET_break_op (0);
3926 addr = (const char *) &pong[1];
3927 slen = strlen (ve->transport_name) + 1;
3928 if ((ps - sizeof (struct TransportPongMessage) < slen) ||
3929 (ve->challenge != challenge) || (addr[slen - 1] != '\0') ||
3930 (0 != strcmp (addr, ve->transport_name)) ||
3931 (ntohl (pong->purpose.size) !=
3932 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) +
3933 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3934 sizeof (struct GNUNET_PeerIdentity) + ps -
3935 sizeof (struct TransportPongMessage)))
3940 alen = ps - sizeof (struct TransportPongMessage) - slen;
3941 switch (ntohl (pong->purpose.purpose))
3943 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3944 if ((ve->addrlen + slen != ntohl (pong->addrlen)) ||
3945 (0 != memcmp (&addr[slen], ve->addr, ve->addrlen)))
3947 return GNUNET_YES; /* different entry, keep trying! */
3949 if (0 != memcmp (&pong->pid, key, sizeof (struct GNUNET_PeerIdentity)))
3951 GNUNET_break_op (0);
3955 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3956 &pong->purpose, &pong->signature,
3959 GNUNET_break_op (0);
3964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3965 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3966 GNUNET_h2s (key), a2s (ve->transport_name,
3967 (const struct sockaddr *) ve->addr,
3968 ve->addrlen), ve->transport_name);
3971 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3973 memcmp (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
3977 GNUNET_asprintf (&peer, "%s", GNUNET_i2s (&pong->pid));
3979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3980 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
3981 GNUNET_i2s (&my_identity), peer);
3986 if (ve->addrlen != 0)
3988 /* must have been for a different validation entry */
3991 tp = find_transport (ve->transport_name);
3997 oal = tp->addresses;
4000 if ((oal->addrlen == alen) && (0 == memcmp (&oal[1], &addr[slen], alen)))
4006 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4008 ("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4009 GNUNET_i2s (&pong->pid), a2s (ve->transport_name, &addr[slen],
4011 /* FIXME: since the sender of the PONG currently uses the
4012 * wrong address (see FIMXE there!), we cannot run a
4013 * proper check here... */
4019 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4020 &pong->purpose, &pong->signature,
4023 GNUNET_break_op (0);
4028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4029 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4030 GNUNET_h2s (key), a2s (ve->transport_name, &addr[slen], alen),
4031 ve->transport_name);
4035 GNUNET_break_op (0);
4038 if (GNUNET_TIME_absolute_get_remaining
4039 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4041 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4042 _("Received expired signature. Check system time.\n"));
4045 GNUNET_STATISTICS_update (stats,
4046 gettext_noop ("# address validation successes"), 1,
4048 /* create the updated HELLO */
4049 GNUNET_CRYPTO_hash (&ve->publicKey,
4050 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4051 &target.hashPubKey);
4052 if (ve->addr != NULL)
4054 avac.done = GNUNET_NO;
4056 hello = GNUNET_HELLO_create (&ve->publicKey, &add_validated_address, &avac);
4057 GNUNET_PEERINFO_add_peer (peerinfo, hello);
4058 GNUNET_free (hello);
4060 n = find_neighbour (&target);
4063 n->publicKey = ve->publicKey;
4064 n->public_key_valid = GNUNET_YES;
4066 add_peer_address (n, ve->transport_name, ve->session, ve->addr,
4068 GNUNET_assert (fal != NULL);
4069 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4070 fal->validated = GNUNET_YES;
4071 mark_address_connected (fal);
4072 GNUNET_STATISTICS_update (stats,
4074 ("# peer addresses considered valid"), 1,
4076 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4077 update_addr_value (fal,
4078 GNUNET_TIME_absolute_get_duration (ve->
4079 send_time).rel_value,
4080 GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4082 schedule_next_ping (fal);
4083 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4084 n->latency = fal->latency;
4086 n->latency.rel_value =
4087 (fal->latency.rel_value + n->latency.rel_value) / 2;
4089 n->distance = fal->distance;
4090 if (GNUNET_NO == n->received_pong)
4092 n->received_pong = GNUNET_YES;
4093 notify_clients_connect (&target, n->latency, n->distance);
4094 if (NULL != (prem = n->pre_connect_message_buffer))
4096 n->pre_connect_message_buffer = NULL;
4097 handle_payload_message (prem, n);
4101 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4103 GNUNET_SCHEDULER_cancel (n->retry_task);
4104 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4105 try_transmission_to_peer (n);
4109 /* clean up validation entry */
4110 GNUNET_assert (GNUNET_YES ==
4111 GNUNET_CONTAINER_multihashmap_remove (validation_map, key,
4113 abort_validation (NULL, NULL, ve);
4119 * Function that will be called if we receive a validation
4120 * of an address challenge that we transmitted to another
4121 * peer. Note that the validation should only be considered
4122 * acceptable if the challenge matches AND if the sender
4123 * address is at least a plausible address for this peer
4124 * (otherwise we may be seeing a MiM attack).
4126 * @param cls closure
4127 * @param message the pong message
4128 * @param peer who responded to our challenge
4129 * @param sender_address string describing our sender address (as observed
4130 * by the other peer in binary format)
4131 * @param sender_address_len number of bytes in 'sender_address'
4134 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4135 const struct GNUNET_PeerIdentity *peer, const char *sender_address,
4136 size_t sender_address_len)
4138 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4140 /* PONG send to self, ignore */
4141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from myself\n",
4145 #if DEBUG_TRANSPORT > 1
4146 /* we get tons of these that just get discarded, only log
4147 * if we are quite verbose */
4148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from `%4s'.\n",
4149 "PONG", GNUNET_i2s (peer));
4151 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), 1,
4153 if (GNUNET_SYSERR !=
4154 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4156 &check_pending_validation,
4159 /* This is *expected* to happen a lot since we send
4160 * PONGs to *all* known addresses of the sender of
4161 * the PING, so most likely we get multiple PONGs
4162 * per PING, and all but the first PONG will end up
4163 * here. So really we should not print anything here
4164 * unless we want to be very, very verbose... */
4165 #if DEBUG_TRANSPORT > 2
4166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4167 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4168 "PONG", GNUNET_i2s (peer), "PING");
4177 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4179 * @param cls the 'struct ValidationEntry*'
4180 * @param neighbour neighbour to validate, NULL if validation failed
4183 transmit_hello_and_ping (void *cls, struct NeighbourMapEntry *neighbour)
4185 struct ValidationEntry *va = cls;
4186 struct ForeignAddressList *peer_address;
4187 struct TransportPingMessage ping;
4188 uint16_t hello_size;
4191 struct GNUNET_PeerIdentity id;
4194 GNUNET_CRYPTO_hash (&va->publicKey,
4195 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4197 if (neighbour == NULL)
4199 /* FIXME: stats... */
4200 GNUNET_break (GNUNET_OK ==
4201 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4202 &id.hashPubKey, va));
4203 abort_validation (NULL, NULL, va);
4206 neighbour->publicKey = va->publicKey;
4207 neighbour->public_key_valid = GNUNET_YES;
4209 add_peer_address (neighbour, va->transport_name, NULL,
4210 (const void *) &va[1], va->addrlen);
4211 if (peer_address == NULL)
4213 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4214 "Failed to add peer `%4s' for plugin `%s'\n",
4215 GNUNET_i2s (&neighbour->id), va->transport_name);
4216 GNUNET_break (GNUNET_OK ==
4217 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4218 &id.hashPubKey, va));
4219 abort_validation (NULL, NULL, va);
4222 if (NULL == our_hello)
4223 refresh_hello_task (NULL, NULL);
4224 hello_size = GNUNET_HELLO_size (our_hello);
4225 slen = strlen (va->transport_name) + 1;
4227 sizeof (struct TransportPingMessage) + hello_size + va->addrlen + slen;
4228 message_buf = GNUNET_malloc (tsize);
4229 ping.challenge = htonl (va->challenge);
4231 htons (sizeof (struct TransportPingMessage) + slen + va->addrlen);
4232 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4233 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
4234 memcpy (message_buf, our_hello, hello_size);
4235 memcpy (&message_buf[hello_size], &ping,
4236 sizeof (struct TransportPingMessage));
4237 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4238 va->transport_name, slen);
4239 memcpy (&message_buf
4240 [hello_size + sizeof (struct TransportPingMessage) + slen], &va[1],
4243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4244 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4245 (va->addrlen == 0) ? "<inbound>" : a2s (va->transport_name,
4246 (const void *) &va[1],
4248 va->transport_name, GNUNET_i2s (&neighbour->id), "HELLO",
4250 sizeof (struct TransportPingMessage) + va->addrlen + slen);
4253 GNUNET_STATISTICS_update (stats,
4255 ("# PING messages sent for initial validation"), 1,
4257 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4258 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
4260 GNUNET_free (message_buf);
4265 * Check if the given address is already being validated; if not,
4266 * append the given address to the list of entries that are being be
4267 * validated and initiate validation.
4269 * @param cls closure ('struct CheckHelloValidatedContext *')
4270 * @param tname name of the transport
4271 * @param expiration expiration time
4272 * @param addr the address
4273 * @param addrlen length of the address
4274 * @return GNUNET_OK (always)
4277 run_validation (void *cls, const char *tname,
4278 struct GNUNET_TIME_Absolute expiration, const void *addr,
4281 struct CheckHelloValidatedContext *chvc = cls;
4282 struct GNUNET_PeerIdentity id;
4283 struct TransportPlugin *tp;
4284 struct ValidationEntry *va;
4285 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4286 struct CheckAddressExistsClosure caec;
4287 struct OwnAddressList *oal;
4289 GNUNET_assert (addr != NULL);
4291 GNUNET_STATISTICS_update (stats,
4293 ("# peer addresses scheduled for validation"), 1,
4295 tp = find_transport (tname);
4298 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
4300 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4302 GNUNET_STATISTICS_update (stats,
4304 ("# peer addresses not validated (plugin not available)"),
4308 /* check if this is one of our own addresses */
4309 oal = tp->addresses;
4312 if ((oal->addrlen == addrlen) && (0 == memcmp (&oal[1], addr, addrlen)))
4314 /* not plausible, this address is equivalent to our own address! */
4315 GNUNET_STATISTICS_update (stats,
4317 ("# peer addresses not validated (loopback)"),
4323 GNUNET_HELLO_get_key (chvc->hello, &pk);
4324 GNUNET_CRYPTO_hash (&pk,
4325 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4328 if (is_blacklisted (&id, tp))
4331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4332 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4333 GNUNET_i2s (&id), tname);
4339 caec.addrlen = addrlen;
4340 caec.session = NULL;
4342 caec.exists = GNUNET_NO;
4343 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
4345 if (caec.exists == GNUNET_YES)
4347 /* During validation attempts we will likely trigger the other
4348 * peer trying to validate our address which in turn will cause
4349 * it to send us its HELLO, so we expect to hit this case rather
4350 * frequently. Only print something if we are very verbose. */
4351 #if DEBUG_TRANSPORT > 1
4352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4353 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4354 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id));
4356 GNUNET_STATISTICS_update (stats,
4358 ("# peer addresses not validated (in progress)"),
4362 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4365 va->transport_name = GNUNET_strdup (tname);
4367 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
4368 va->send_time = GNUNET_TIME_absolute_get ();
4369 va->addr = (const void *) &va[1];
4370 memcpy (&va[1], addr, addrlen);
4371 va->addrlen = addrlen;
4372 GNUNET_HELLO_get_key (chvc->hello, &va->publicKey);
4374 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4375 &timeout_hello_validation, va);
4376 GNUNET_CONTAINER_multihashmap_put (validation_map, &id.hashPubKey, va,
4377 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4378 setup_peer_check_blacklist (&id, GNUNET_NO, &transmit_hello_and_ping, va);
4384 * Check if addresses in validated hello "h" overlap with
4385 * those in "chvc->hello" and validate the rest.
4387 * @param cls closure
4388 * @param peer id of the peer, NULL for last call
4389 * @param h hello message for the peer (can be NULL)
4390 * @param err_msg NULL if successful, otherwise contains error message
4393 check_hello_validated (void *cls, const struct GNUNET_PeerIdentity *peer,
4394 const struct GNUNET_HELLO_Message *h,
4395 const char *err_msg)
4397 struct CheckHelloValidatedContext *chvc = cls;
4398 struct GNUNET_HELLO_Message *plain_hello;
4399 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4400 struct GNUNET_PeerIdentity target;
4401 struct NeighbourMapEntry *n;
4403 if (err_msg != NULL)
4406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4407 _("Error in communication with PEERINFO service: %s\n"),
4415 GNUNET_STATISTICS_update (stats,
4417 ("# outstanding peerinfo iterate requests"), -1,
4420 if (GNUNET_NO == chvc->hello_known)
4422 /* notify PEERINFO about the peer now, so that we at least
4423 * have the public key if some other component needs it */
4424 GNUNET_HELLO_get_key (chvc->hello, &pk);
4425 GNUNET_CRYPTO_hash (&pk,
4427 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4428 &target.hashPubKey);
4429 plain_hello = GNUNET_HELLO_create (&pk, NULL, NULL);
4430 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4431 GNUNET_free (plain_hello);
4432 #if DEBUG_TRANSPORT_HELLO
4433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4434 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4435 "HELLO", GNUNET_i2s (&target));
4437 GNUNET_STATISTICS_update (stats,
4439 ("# new HELLOs requiring full validation"), 1,
4441 GNUNET_HELLO_iterate_addresses (chvc->hello, GNUNET_NO, &run_validation,
4446 GNUNET_STATISTICS_update (stats,
4447 gettext_noop ("# duplicate HELLO (peer known)"),
4451 if (chvc->ve_count == 0)
4453 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
4460 #if DEBUG_TRANSPORT_HELLO
4461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4462 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4463 "HELLO", GNUNET_i2s (peer));
4465 chvc->hello_known = GNUNET_YES;
4466 n = find_neighbour (peer);
4469 #if DEBUG_TRANSPORT_HELLO
4470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4471 "Calling hello_iterate_addresses for %s!\n", GNUNET_i2s (peer));
4473 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
4475 try_transmission_to_peer (n);
4479 #if DEBUG_TRANSPORT_HELLO
4480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4481 "No existing neighbor record for %s!\n", GNUNET_i2s (peer));
4483 GNUNET_STATISTICS_update (stats,
4485 ("# no existing neighbour record (validating HELLO)"),
4488 GNUNET_STATISTICS_update (stats,
4489 gettext_noop ("# HELLO validations (update case)"),
4491 GNUNET_HELLO_iterate_new_addresses (chvc->hello, h,
4492 GNUNET_TIME_relative_to_absolute
4493 (HELLO_REVALIDATION_START_TIME),
4494 &run_validation, chvc);
4499 * Process HELLO-message.
4501 * @param plugin transport involved, may be NULL
4502 * @param message the actual message
4503 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4506 process_hello (struct TransportPlugin *plugin,
4507 const struct GNUNET_MessageHeader *message)
4510 struct GNUNET_PeerIdentity target;
4511 const struct GNUNET_HELLO_Message *hello;
4512 struct CheckHelloValidatedContext *chvc;
4513 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4514 struct NeighbourMapEntry *n;
4516 #if DEBUG_TRANSPORT_HELLO > 2
4520 hsize = ntohs (message->size);
4521 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4522 (hsize < sizeof (struct GNUNET_MessageHeader)))
4525 return GNUNET_SYSERR;
4527 GNUNET_STATISTICS_update (stats,
4528 gettext_noop ("# HELLOs received for validation"),
4531 hello = (const struct GNUNET_HELLO_Message *) message;
4532 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4534 #if DEBUG_TRANSPORT_HELLO
4535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4536 "Unable to get public key from `%s' for `%4s'!\n", "HELLO",
4537 GNUNET_i2s (&target));
4539 GNUNET_break_op (0);
4540 return GNUNET_SYSERR;
4542 GNUNET_CRYPTO_hash (&publicKey,
4543 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4544 &target.hashPubKey);
4546 #if DEBUG_TRANSPORT_HELLO
4547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for `%4s'\n",
4548 "HELLO", GNUNET_i2s (&target));
4550 if (0 == memcmp (&my_identity, &target, sizeof (struct GNUNET_PeerIdentity)))
4552 GNUNET_STATISTICS_update (stats,
4554 ("# HELLOs ignored for validation (is my own HELLO)"),
4558 n = find_neighbour (&target);
4559 if ((NULL != n) && (!n->public_key_valid))
4561 GNUNET_HELLO_get_key (hello, &n->publicKey);
4562 n->public_key_valid = GNUNET_YES;
4565 /* check if load is too high before doing expensive stuff */
4566 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) >
4569 GNUNET_STATISTICS_update (stats,
4571 ("# HELLOs ignored due to high load"), 1,
4573 #if DEBUG_TRANSPORT_HELLO
4574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4575 "Ignoring `%s' for `%4s', load too high.\n", "HELLO",
4576 GNUNET_i2s (&target));
4583 while (NULL != chvc)
4585 if (GNUNET_HELLO_equals
4586 (hello, chvc->hello, GNUNET_TIME_absolute_get ()).abs_value > 0)
4588 #if DEBUG_TRANSPORT_HELLO > 2
4589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4590 "Received duplicate `%s' message for `%4s'; ignored\n",
4591 "HELLO", GNUNET_i2s (&target));
4593 return GNUNET_OK; /* validation already pending */
4595 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4597 memcmp (hello, chvc->hello, GNUNET_HELLO_size (hello)));
4602 struct NeighbourMapEntry *temp_neighbor = find_neighbour (&target);
4604 if ((NULL != temp_neighbor))
4606 fprintf (stderr, "Already know peer, ignoring hello\n");
4611 #if DEBUG_TRANSPORT_HELLO > 2
4615 my_id = GNUNET_strdup (GNUNET_i2s (plugin->env.my_identity));
4616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4617 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4618 my_id, "HELLO", GNUNET_i2s (&target), plugin->short_name,
4619 GNUNET_HELLO_size (hello));
4620 GNUNET_free (my_id);
4624 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4626 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4627 memcpy (&chvc[1], hello, hsize);
4628 GNUNET_CONTAINER_DLL_insert (chvc_head, chvc_tail, chvc);
4629 /* finally, check if HELLO was previously validated
4630 * (continuation will then schedule actual validation) */
4631 GNUNET_STATISTICS_update (stats,
4633 ("# peerinfo process hello iterate requests"), 1,
4635 GNUNET_STATISTICS_update (stats,
4637 ("# outstanding peerinfo iterate requests"), 1,
4640 GNUNET_PEERINFO_iterate (peerinfo, &target, HELLO_VERIFICATION_TIMEOUT,
4641 &check_hello_validated, chvc);
4647 * The peer specified by the given neighbour has timed-out or a plugin
4648 * has disconnected. We may either need to do nothing (other plugins
4649 * still up), or trigger a full disconnect and clean up. This
4650 * function updates our state and does the necessary notifications.
4651 * Also notifies our clients that the neighbour is now officially
4654 * @param n the neighbour list entry for the peer
4655 * @param check GNUNET_YES to check if ALL addresses for this peer
4656 * are gone, GNUNET_NO to force a disconnect of the peer
4657 * regardless of whether other addresses exist.
4660 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4662 struct ReadyList *rpos;
4663 struct MessageQueue *mq;
4664 struct ForeignAddressList *peer_addresses;
4665 struct ForeignAddressList *peer_pos;
4667 if (GNUNET_YES == n->in_disconnect)
4669 if (GNUNET_YES == check)
4672 while (NULL != rpos)
4674 peer_addresses = rpos->addresses;
4675 while (peer_addresses != NULL)
4677 /* Do not disconnect if: an address is connected or an inbound address exists */
4678 if ((GNUNET_YES == peer_addresses->connected) ||
4679 (peer_addresses->addrlen == 0))
4682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4683 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4684 GNUNET_i2s (&n->id),
4685 a2s (peer_addresses->ready_list->plugin->short_name,
4686 peer_addresses->addr, peer_addresses->addrlen));
4688 return; /* still connected */
4690 peer_addresses = peer_addresses->next;
4696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4697 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
4699 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4701 /* notify all clients about disconnect */
4702 if (GNUNET_YES == n->received_pong)
4704 n->received_pong = GNUNET_NO;
4705 notify_clients_disconnect (&n->id);
4708 ats_modify_problem_state (ats, ATS_MODIFIED);
4710 /* clean up all plugins, cancel connections and pending transmissions */
4711 while (NULL != (rpos = n->plugins))
4713 n->plugins = rpos->next;
4714 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4715 while (rpos->addresses != NULL)
4717 peer_pos = rpos->addresses;
4718 rpos->addresses = peer_pos->next;
4719 if (peer_pos->connected == GNUNET_YES)
4721 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
4723 peer_pos->connected = GNUNET_NO;
4725 if (GNUNET_YES == peer_pos->validated)
4726 GNUNET_STATISTICS_update (stats,
4728 ("# peer addresses considered valid"), -1,
4730 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4732 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4733 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4735 GNUNET_free (peer_pos->ressources);
4736 peer_pos->ressources = NULL;
4737 GNUNET_free (peer_pos->quality);
4738 peer_pos->ressources = NULL;
4739 GNUNET_free (peer_pos);
4744 /* free all messages on the queue */
4745 while (NULL != (mq = n->messages_head))
4747 GNUNET_STATISTICS_update (stats,
4749 ("# bytes in message queue for other peers"),
4750 -(int64_t) mq->message_buf_size, GNUNET_NO);
4751 GNUNET_STATISTICS_update (stats,
4753 ("# bytes discarded due to disconnect"),
4754 mq->message_buf_size, GNUNET_NO);
4755 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
4757 memcmp (&mq->neighbour_id, &n->id,
4758 sizeof (struct GNUNET_PeerIdentity)));
4762 while (NULL != (mq = n->cont_head))
4765 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
4767 memcmp (&mq->neighbour_id, &n->id,
4768 sizeof (struct GNUNET_PeerIdentity)));
4772 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4774 GNUNET_SCHEDULER_cancel (n->timeout_task);
4775 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4777 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4779 GNUNET_SCHEDULER_cancel (n->retry_task);
4780 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4782 if (n->piter != NULL)
4784 GNUNET_PEERINFO_iterate_cancel (n->piter);
4785 GNUNET_STATISTICS_update (stats,
4787 ("# outstanding peerinfo iterate requests"), -1,
4792 GNUNET_assert (GNUNET_OK ==
4793 GNUNET_CONTAINER_multihashmap_remove (neighbours,
4794 &n->id.hashPubKey, n));
4795 /* finally, free n itself */
4796 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), -1,
4798 GNUNET_free_non_null (n->pre_connect_message_buffer);
4804 * We have received a PING message from someone. Need to send a PONG message
4805 * in response to the peer by any means necessary.
4808 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4809 const struct GNUNET_PeerIdentity *peer, struct Session *session,
4810 const char *sender_address, uint16_t sender_address_len)
4812 struct TransportPlugin *plugin = cls;
4813 struct SessionHeader *session_header = (struct SessionHeader *) session;
4814 struct TransportPingMessage *ping;
4815 struct TransportPongMessage *pong;
4816 struct NeighbourMapEntry *n;
4817 struct ReadyList *rl;
4818 struct ForeignAddressList *fal;
4819 struct OwnAddressList *oal;
4825 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4827 GNUNET_break_op (0);
4828 return GNUNET_SYSERR;
4831 ping = (struct TransportPingMessage *) message;
4833 memcmp (&ping->target, plugin->env.my_identity,
4834 sizeof (struct GNUNET_PeerIdentity)))
4837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4839 ("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4840 "PING", (sender_address != NULL) ? a2s (plugin->short_name,
4841 (const struct sockaddr
4843 sender_address_len) :
4844 "<inbound>", GNUNET_i2s (&ping->target));
4846 return GNUNET_SYSERR;
4849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4850 "Processing `%s' from `%s'\n", "PING",
4851 (sender_address != NULL) ? a2s (plugin->short_name,
4852 (const struct sockaddr *)
4854 sender_address_len) :
4857 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), 1,
4859 addr = (const char *) &ping[1];
4860 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4861 slen = strlen (plugin->short_name) + 1;
4864 /* peer wants to confirm that we have an outbound connection to him */
4865 if (session == NULL)
4867 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4869 ("Refusing to create PONG since I do not have a session with `%s'.\n"),
4871 return GNUNET_SYSERR;
4873 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4874 * 1) it is NULL when we need to have a real value
4875 * 2) it is documented to be the address of the sender (source-IP), where
4876 * what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4880 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4881 a2s (plugin->short_name, sender_address, sender_address_len),
4885 GNUNET_malloc (sizeof (struct TransportPongMessage) +
4886 sender_address_len + slen);
4888 htons (sizeof (struct TransportPongMessage) + sender_address_len +
4890 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4891 pong->purpose.size =
4892 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4893 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4894 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4895 pong->purpose.purpose =
4896 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4897 pong->challenge = ping->challenge;
4898 pong->addrlen = htonl (sender_address_len + slen);
4899 memcpy (&pong->pid, peer, sizeof (struct GNUNET_PeerIdentity));
4900 memcpy (&pong[1], plugin->short_name, slen);
4901 if ((sender_address != NULL) && (sender_address_len > 0))
4902 memcpy (&((char *) &pong[1])[slen], sender_address, sender_address_len);
4903 if (GNUNET_TIME_absolute_get_remaining
4904 (session_header->pong_sig_expires).rel_value <
4905 PONG_SIGNATURE_LIFETIME.rel_value / 4)
4907 /* create / update cached sig */
4909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4910 "Creating PONG signature to indicate active connection.\n");
4912 session_header->pong_sig_expires =
4913 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4915 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4916 GNUNET_assert (GNUNET_OK ==
4917 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4918 &session_header->pong_signature));
4923 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4925 memcpy (&pong->signature, &session_header->pong_signature,
4926 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4932 /* peer wants to confirm that this is one of our addresses */
4935 if (GNUNET_OK != plugin->api->check_address (plugin->api->cls, addr, alen))
4937 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4939 ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4940 a2s (plugin->short_name, addr, alen));
4943 oal = plugin->addresses;
4946 if ((oal->addrlen == alen) && (0 == memcmp (addr, &oal[1], alen)))
4950 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4952 htons (sizeof (struct TransportPongMessage) + alen + slen);
4953 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4954 pong->purpose.size =
4955 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4956 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4957 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4958 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4959 pong->challenge = ping->challenge;
4960 pong->addrlen = htonl (alen + slen);
4961 memcpy (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity));
4962 memcpy (&pong[1], plugin->short_name, slen);
4963 memcpy (&((char *) &pong[1])[slen], addr, alen);
4964 if ((oal != NULL) &&
4965 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value <
4966 PONG_SIGNATURE_LIFETIME.rel_value / 4))
4968 /* create / update cached sig */
4970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4971 "Creating PONG signature to indicate ownership.\n");
4973 oal->pong_sig_expires =
4974 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4975 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4976 GNUNET_assert (GNUNET_OK ==
4977 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4978 &oal->pong_signature));
4979 memcpy (&pong->signature, &oal->pong_signature,
4980 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4982 else if (oal == NULL)
4984 /* not using cache (typically DV-only) */
4986 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
4987 (PONG_SIGNATURE_LIFETIME));
4988 GNUNET_assert (GNUNET_OK ==
4989 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4994 /* can used cached version */
4995 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4996 memcpy (&pong->signature, &oal->pong_signature,
4997 sizeof (struct GNUNET_CRYPTO_RsaSignature));
5000 n = find_neighbour (peer);
5001 GNUNET_assert (n != NULL);
5002 did_pong = GNUNET_NO;
5003 /* first try reliable response transmission */
5007 fal = rl->addresses;
5011 rl->plugin->api->send (rl->plugin->api->cls, peer,
5012 (const char *) pong, ntohs (pong->header.size),
5013 TRANSPORT_PONG_PRIORITY,
5014 HELLO_VERIFICATION_TIMEOUT, fal->session,
5015 fal->addr, fal->addrlen, GNUNET_SYSERR, NULL,
5018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5019 "Transmitted PONG to `%s' via reliable mechanism\n",
5022 GNUNET_STATISTICS_update (stats,
5024 ("# PONGs unicast via reliable transport"), 1,
5029 did_pong = GNUNET_YES;
5034 /* no reliable method found, do multicast */
5035 GNUNET_STATISTICS_update (stats,
5037 ("# PONGs multicast to all available addresses"), 1,
5042 fal = rl->addresses;
5045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5046 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5047 GNUNET_i2s (peer), a2s (rl->plugin->short_name, fal->addr,
5049 rl->plugin->short_name);
5050 transmit_to_peer (NULL, fal, TRANSPORT_PONG_PRIORITY,
5051 HELLO_VERIFICATION_TIMEOUT, (const char *) pong,
5052 ntohs (pong->header.size), GNUNET_YES, n);
5053 did_pong = GNUNET_YES;
5059 if (GNUNET_YES != did_pong)
5060 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5061 _("Could not send PONG to `%s': no address available\n"),
5068 * Function called by the plugin for each received message. Update
5069 * data volumes, possibly notify plugins about reducing the rate at
5070 * which they read from the socket and generally forward to our
5073 * @param cls the "struct TransportPlugin *" we gave to the plugin
5074 * @param peer (claimed) identity of the other peer
5075 * @param message the message, NULL if we only care about
5076 * learning about the delay until we should receive again
5077 * @param ats_data information for automatic transport selection
5078 * @param ats_count number of elements in ats not including 0-terminator
5079 * @param session identifier used for this session (can be NULL)
5080 * @param sender_address binary address of the sender (if observed)
5081 * @param sender_address_len number of bytes in sender_address
5082 * @return how long in ms the plugin should wait until receiving more data
5083 * (plugins that do not support this, can ignore the return value)
5085 static struct GNUNET_TIME_Relative
5086 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5087 const struct GNUNET_MessageHeader *message,
5088 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5089 uint32_t ats_count, struct Session *session,
5090 const char *sender_address, uint16_t sender_address_len)
5092 struct TransportPlugin *plugin = cls;
5093 struct ReadyList *service_context;
5094 struct ForeignAddressList *peer_address;
5096 struct NeighbourMapEntry *n;
5097 struct GNUNET_TIME_Relative ret;
5101 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
5103 /* refuse to receive from myself */
5105 return GNUNET_TIME_UNIT_FOREVER_REL;
5107 if (is_blacklisted (peer, plugin))
5108 return GNUNET_TIME_UNIT_FOREVER_REL;
5109 n = find_neighbour (peer);
5111 n = setup_new_neighbour (peer, GNUNET_YES);
5112 service_context = n->plugins;
5113 while ((service_context != NULL) && (plugin != service_context->plugin))
5114 service_context = service_context->next;
5115 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5116 peer_address = NULL;
5119 for (c = 0; c < ats_count; c++)
5120 if (ntohl (ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5121 distance = ntohl (ats_data[c].value);
5124 if (message != NULL)
5126 if ((session != NULL) || (sender_address != NULL))
5128 add_peer_address (n, plugin->short_name, session, sender_address,
5129 sender_address_len);
5130 if (peer_address != NULL)
5132 update_addr_ats (peer_address, ats_data, ats_count);
5133 update_addr_value (peer_address, distance,
5134 GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5136 peer_address->distance = distance;
5137 if (GNUNET_YES == peer_address->validated)
5139 mark_address_connected (peer_address);
5140 schedule_next_ping (peer_address);
5145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5146 "New address is unvalidated, trying to validate it now\n");
5148 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5150 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5151 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5153 peer_address->revalidate_task =
5154 GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5157 peer_address->timeout =
5158 GNUNET_TIME_relative_to_absolute
5159 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5161 /* update traffic received amount ... */
5162 msize = ntohs (message->size);
5164 GNUNET_STATISTICS_update (stats,
5166 ("# bytes received from other peers"), msize,
5168 n->distance = distance;
5170 GNUNET_TIME_relative_to_absolute
5171 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5172 GNUNET_SCHEDULER_cancel (n->timeout_task);
5174 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5175 &neighbour_timeout_task, n);
5176 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5178 /* dropping message due to frequent inbound volume violations! */
5179 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
5181 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5182 n->in_tracker.available_bytes_per_s__,
5183 n->quota_violation_count);
5184 GNUNET_STATISTICS_update (stats,
5186 ("# bandwidth quota violations by other peers"),
5188 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5190 if ((ntohs (message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5191 (ntohs (message->size) ==
5192 (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5195 uint32_t value = ntohl (*((uint32_t *) & message[1]));
5197 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5198 /* Force ressource and quality update */
5199 if ((value == 4) && (ats != NULL))
5200 ats_modify_problem_state (ats, ATS_QUALITY_COST_UPDATED);
5201 /* Force cost update */
5202 if ((value == 3) && (ats != NULL))
5203 ats_modify_problem_state (ats, ATS_COST_UPDATED);
5204 /* Force quality update */
5205 if ((value == 2) && (ats != NULL))
5206 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
5207 /* Force full rebuild */
5208 if ((value == 1) && (ats != NULL))
5209 ats_modify_problem_state (ats, ATS_MODIFIED);
5214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5215 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5216 ntohs (message->type), ntohs (message->size),
5219 switch (ntohs (message->type))
5221 case GNUNET_MESSAGE_TYPE_HELLO:
5222 GNUNET_STATISTICS_update (stats,
5224 ("# HELLO messages received from other peers"),
5226 process_hello (plugin, message);
5228 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5229 handle_ping (plugin, message, peer, session, sender_address,
5230 sender_address_len);
5231 if (GNUNET_YES != n->received_pong)
5232 transmit_plain_ping (n);
5234 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5235 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5237 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5240 handle_payload_message (message, n);
5244 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5245 if (ret.rel_value > 0)
5248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5249 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5250 (unsigned long long) n->
5251 in_tracker.consumption_since_last_update__,
5252 (unsigned int) n->in_tracker.available_bytes_per_s__,
5253 (unsigned long long) ret.rel_value);
5255 GNUNET_STATISTICS_update (stats, gettext_noop ("# ms throttling suggested"),
5256 (int64_t) ret.rel_value, GNUNET_NO);
5263 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
5266 struct TransportClient *c = cls;
5267 struct NeighbourMapEntry *n = value;
5268 struct ConnectInfoMessage *cim;
5272 if (GNUNET_YES != n->received_pong)
5277 sizeof (struct ConnectInfoMessage) +
5278 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5279 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5280 cim = GNUNET_malloc (size);
5281 cim->header.size = htons (size);
5282 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5283 cim->ats_count = htonl (ats_count);
5284 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5285 (&(cim->ats))[2].value = htonl (0);
5286 if (GNUNET_YES == n->received_pong)
5288 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5289 (&cim->ats)[0].value = htonl (n->distance);
5290 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5291 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5293 transmit_to_client (c, &cim->header, GNUNET_NO);
5301 * Handle START-message. This is the first message sent to us
5302 * by any client which causes us to add it to our list.
5304 * @param cls closure (always NULL)
5305 * @param client identification of the client
5306 * @param message the actual message
5309 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
5310 const struct GNUNET_MessageHeader *message)
5312 const struct StartMessage *start;
5313 struct TransportClient *c;
5315 start = (const struct StartMessage *) message;
5317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n",
5323 if (c->client == client)
5325 /* client already on our list! */
5327 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5332 if ((GNUNET_NO != ntohl (start->do_check)) &&
5334 memcmp (&start->self, &my_identity,
5335 sizeof (struct GNUNET_PeerIdentity))))
5337 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5339 ("Rejecting control connection from peer `%s', which is not me!\n"),
5340 GNUNET_i2s (&start->self));
5341 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5344 c = GNUNET_malloc (sizeof (struct TransportClient));
5348 if (our_hello != NULL)
5351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending our own `%s' to new client\n",
5354 transmit_to_client (c, (const struct GNUNET_MessageHeader *) our_hello,
5356 /* tell new client about all existing connections */
5357 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5358 ¬ify_client_about_neighbour, c);
5362 #if DEBUG_TRANSPORT_HELLO
5363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5364 "No HELLO created yet, will transmit HELLO to client later!\n");
5368 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5373 * Handle HELLO-message.
5375 * @param cls closure (always NULL)
5376 * @param client identification of the client
5377 * @param message the actual message
5380 handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
5381 const struct GNUNET_MessageHeader *message)
5385 GNUNET_STATISTICS_update (stats,
5386 gettext_noop ("# HELLOs received from clients"), 1,
5388 ret = process_hello (NULL, message);
5389 GNUNET_SERVER_receive_done (client, ret);
5394 * Closure for 'transmit_client_message'; followed by
5395 * 'msize' bytes of the actual message.
5397 struct TransmitClientMessageContext
5400 * Client on whom's behalf we are sending.
5402 struct GNUNET_SERVER_Client *client;
5405 * Timeout for the transmission.
5407 struct GNUNET_TIME_Absolute timeout;
5415 * Size of the message in bytes.
5422 * Schedule transmission of a message we got from a client to a peer.
5424 * @param cls the 'struct TransmitClientMessageContext*'
5425 * @param n destination, or NULL on error (in that case, drop the message)
5428 transmit_client_message (void *cls, struct NeighbourMapEntry *n)
5430 struct TransmitClientMessageContext *tcmc = cls;
5431 struct TransportClient *tc;
5434 while ((tc != NULL) && (tc->client != tcmc->client))
5439 transmit_to_peer (tc, NULL, tcmc->priority,
5440 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5441 (char *) &tcmc[1], tcmc->msize, GNUNET_NO, n);
5443 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5444 GNUNET_SERVER_client_drop (tcmc->client);
5450 * Handle SEND-message.
5452 * @param cls closure (always NULL)
5453 * @param client identification of the client
5454 * @param message the actual message
5457 handle_send (void *cls, struct GNUNET_SERVER_Client *client,
5458 const struct GNUNET_MessageHeader *message)
5460 const struct OutboundMessage *obm;
5461 const struct GNUNET_MessageHeader *obmm;
5462 struct TransmitClientMessageContext *tcmc;
5466 size = ntohs (message->size);
5468 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5471 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5474 GNUNET_STATISTICS_update (stats,
5475 gettext_noop ("# payload received for other peers"),
5477 obm = (const struct OutboundMessage *) message;
5478 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5479 msize = size - sizeof (struct OutboundMessage);
5481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5482 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5483 "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
5485 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5486 tcmc->client = client;
5487 tcmc->priority = ntohl (obm->priority);
5489 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh
5491 tcmc->msize = msize;
5492 /* FIXME: this memcpy can be up to 7% of our total runtime */
5493 memcpy (&tcmc[1], obmm, msize);
5494 GNUNET_SERVER_client_keep (client);
5495 setup_peer_check_blacklist (&obm->peer, GNUNET_YES, &transmit_client_message,
5501 * Handle request connect message
5503 * @param cls closure (always NULL)
5504 * @param client identification of the client
5505 * @param message the actual message
5508 handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
5509 const struct GNUNET_MessageHeader *message)
5511 const struct TransportRequestConnectMessage *trcm =
5512 (const struct TransportRequestConnectMessage *) message;
5514 GNUNET_STATISTICS_update (stats,
5516 ("# REQUEST CONNECT messages received"), 1,
5519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5520 "Received a request connect message for peer `%s'\n",
5521 GNUNET_i2s (&trcm->peer));
5523 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES, NULL, NULL);
5524 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5529 * Handle SET_QUOTA-message.
5531 * @param cls closure (always NULL)
5532 * @param client identification of the client
5533 * @param message the actual message
5536 handle_set_quota (void *cls, struct GNUNET_SERVER_Client *client,
5537 const struct GNUNET_MessageHeader *message)
5539 const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message;
5540 struct NeighbourMapEntry *n;
5542 GNUNET_STATISTICS_update (stats,
5543 gettext_noop ("# SET QUOTA messages received"), 1,
5545 n = find_neighbour (&qsm->peer);
5548 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5549 GNUNET_STATISTICS_update (stats,
5551 ("# SET QUOTA messages ignored (no such peer)"),
5556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5557 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5558 "SET_QUOTA", (unsigned int) ntohl (qsm->quota.value__),
5559 (unsigned int) n->in_tracker.available_bytes_per_s__,
5560 GNUNET_i2s (&qsm->peer));
5562 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, qsm->quota);
5563 if (0 == ntohl (qsm->quota.value__))
5566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
5567 GNUNET_i2s (&n->id), "SET_QUOTA");
5569 GNUNET_STATISTICS_update (stats,
5570 gettext_noop ("# disconnects due to quota of 0"),
5572 disconnect_neighbour (n, GNUNET_NO);
5574 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5579 * Take the given address and append it to the set of results sent back to
5582 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5583 * @param address the resolved name, NULL to indicate the last response
5586 transmit_address_to_client (void *cls, const char *address)
5588 struct GNUNET_SERVER_TransmitContext *tc = cls;
5591 if (NULL != address)
5593 slen = strlen (address) + 1;
5594 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5595 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5599 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5600 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5601 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5607 * Handle AddressLookup-message.
5609 * @param cls closure (always NULL)
5610 * @param client identification of the client
5611 * @param message the actual message
5614 handle_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5615 const struct GNUNET_MessageHeader *message)
5617 const struct AddressLookupMessage *alum;
5618 struct TransportPlugin *lsPlugin;
5619 const char *nameTransport;
5620 const char *address;
5622 struct GNUNET_SERVER_TransmitContext *tc;
5623 struct GNUNET_TIME_Relative rtimeout;
5626 size = ntohs (message->size);
5627 if (size < sizeof (struct AddressLookupMessage))
5629 GNUNET_break_op (0);
5630 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5633 alum = (const struct AddressLookupMessage *) message;
5634 uint32_t addressLen = ntohl (alum->addrlen);
5636 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5638 GNUNET_break_op (0);
5639 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5642 address = (const char *) &alum[1];
5643 nameTransport = (const char *) &address[addressLen];
5645 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5647 GNUNET_break_op (0);
5648 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5651 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5652 numeric = ntohl (alum->numeric_only);
5653 lsPlugin = find_transport (nameTransport);
5654 if (NULL == lsPlugin)
5656 tc = GNUNET_SERVER_transmit_context_create (client);
5657 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5658 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5659 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5662 GNUNET_SERVER_disable_receive_done_warning (client);
5663 tc = GNUNET_SERVER_transmit_context_create (client);
5664 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls, nameTransport,
5665 address, addressLen, numeric, rtimeout,
5666 &transmit_address_to_client, tc);
5670 * Handle PeerAddressLookupMessage.
5672 * @param cls closure (always NULL)
5673 * @param client identification of the client
5674 * @param message the actual message
5677 handle_peer_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5678 const struct GNUNET_MessageHeader *message)
5680 const struct PeerAddressLookupMessage *peer_address_lookup;
5681 struct NeighbourMapEntry *neighbor_iterator;
5682 struct ReadyList *ready_iterator;
5683 struct ForeignAddressList *foreign_address_iterator;
5684 struct TransportPlugin *transport_plugin;
5687 struct GNUNET_SERVER_TransmitContext *tc;
5688 struct GNUNET_TIME_Relative rtimeout;
5691 size = ntohs (message->size);
5692 if (size < sizeof (struct PeerAddressLookupMessage))
5694 GNUNET_break_op (0);
5695 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5698 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5700 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5702 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5704 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5705 if (neighbor_iterator == NULL)
5708 tc = GNUNET_SERVER_transmit_context_create (client);
5709 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5710 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5711 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5715 ready_iterator = neighbor_iterator->plugins;
5716 GNUNET_SERVER_disable_receive_done_warning (client);
5717 tc = GNUNET_SERVER_transmit_context_create (client);
5718 while (ready_iterator != NULL)
5720 foreign_address_iterator = ready_iterator->addresses;
5721 while (foreign_address_iterator != NULL)
5723 transport_plugin = foreign_address_iterator->ready_list->plugin;
5724 if (foreign_address_iterator->addr != NULL)
5726 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
5727 a2s (transport_plugin->short_name,
5728 foreign_address_iterator->addr,
5729 foreign_address_iterator->addrlen),
5730 (foreign_address_iterator->connected ==
5731 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5732 (foreign_address_iterator->validated ==
5733 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5734 transmit_address_to_client (tc, addr_buf);
5735 GNUNET_free (addr_buf);
5737 else if (foreign_address_iterator->addrlen == 0)
5739 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5740 (foreign_address_iterator->connected ==
5741 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5742 (foreign_address_iterator->validated ==
5743 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5744 transmit_address_to_client (tc, addr_buf);
5745 GNUNET_free (addr_buf);
5748 foreign_address_iterator = foreign_address_iterator->next;
5750 ready_iterator = ready_iterator->next;
5752 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5753 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5754 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5760 output_addresses (void *cls, const GNUNET_HashCode * key, void *value)
5762 struct GNUNET_SERVER_TransmitContext *tc = cls;
5763 struct NeighbourMapEntry *neighbor_iterator = value;
5764 struct ForeignAddressList *foreign_address_iterator;
5765 struct TransportPlugin *transport_plugin;
5766 struct ReadyList *ready_iterator;
5769 ready_iterator = neighbor_iterator->plugins;
5770 while (ready_iterator != NULL)
5772 foreign_address_iterator = ready_iterator->addresses;
5773 while (foreign_address_iterator != NULL)
5775 transport_plugin = foreign_address_iterator->ready_list->plugin;
5776 if (foreign_address_iterator->addr != NULL)
5778 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5779 GNUNET_i2s (&neighbor_iterator->id),
5780 a2s (transport_plugin->short_name,
5781 foreign_address_iterator->addr,
5782 foreign_address_iterator->addrlen),
5783 (foreign_address_iterator->connected ==
5784 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5785 (foreign_address_iterator->validated ==
5786 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5787 transmit_address_to_client (tc, addr_buf);
5788 GNUNET_free (addr_buf);
5790 else if (foreign_address_iterator->addrlen == 0)
5792 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5793 GNUNET_i2s (&neighbor_iterator->id), "<inbound>",
5794 (foreign_address_iterator->connected ==
5795 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5796 (foreign_address_iterator->validated ==
5797 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5798 transmit_address_to_client (tc, addr_buf);
5799 GNUNET_free (addr_buf);
5802 foreign_address_iterator = foreign_address_iterator->next;
5804 ready_iterator = ready_iterator->next;
5811 * Handle AddressIterateMessage
5813 * @param cls closure (always NULL)
5814 * @param client identification of the client
5815 * @param message the actual message
5818 handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
5819 const struct GNUNET_MessageHeader *message)
5821 struct GNUNET_SERVER_TransmitContext *tc;
5824 size = ntohs (message->size);
5825 if (size < sizeof (struct AddressIterateMessage))
5827 GNUNET_break_op (0);
5828 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5831 GNUNET_SERVER_disable_receive_done_warning (client);
5832 tc = GNUNET_SERVER_transmit_context_create (client);
5833 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &output_addresses, tc);
5834 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5835 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5836 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5840 static const struct GNUNET_MessageHeader *
5843 return (const struct GNUNET_MessageHeader *) our_hello;
5848 * Setup the environment for this plugin.
5851 create_environment (struct TransportPlugin *plug)
5853 plug->env.cfg = cfg;
5854 plug->env.my_identity = &my_identity;
5855 plug->env.get_our_hello = &do_get_our_hello;
5856 plug->env.cls = plug;
5857 plug->env.receive = &plugin_env_receive;
5858 plug->env.notify_address = &plugin_env_notify_address;
5859 plug->env.session_end = &plugin_env_session_end;
5860 plug->env.max_connections = max_connect_per_transport;
5861 plug->env.stats = stats;
5866 * Start the specified transport (load the plugin).
5869 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
5871 struct TransportPlugin *plug;
5874 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
5876 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5877 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5878 create_environment (plug);
5879 plug->short_name = GNUNET_strdup (name);
5880 plug->lib_name = libname;
5881 plug->next = plugins;
5883 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5884 if (plug->api == NULL)
5886 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5887 _("Failed to load transport plugin for `%s'\n"), name);
5888 GNUNET_free (plug->short_name);
5889 plugins = plug->next;
5890 GNUNET_free (libname);
5897 null_mq_client_pointers (void *cls, const GNUNET_HashCode * key, void *value)
5899 struct TransportClient *pos = cls;
5900 struct NeighbourMapEntry *n = value;
5901 struct MessageQueue *mq;
5903 for (mq = n->messages_head; mq != NULL; mq = mq->next)
5905 if (mq->client == pos)
5906 mq->client = NULL; /* do not use anymore! */
5913 * Called whenever a client is disconnected. Frees our
5914 * resources associated with that client.
5916 * @param cls closure
5917 * @param client identification of the client
5920 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
5922 struct TransportClient *pos;
5923 struct TransportClient *prev;
5924 struct ClientMessageQueueEntry *mqe;
5925 struct Blacklisters *bl;
5926 struct BlacklistCheck *bc;
5931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5932 "Client disconnected, cleaning up.\n");
5934 /* clean up blacklister */
5938 if (bl->client == client)
5943 if (bc->bl_pos == bl)
5945 bc->bl_pos = bl->next;
5948 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5951 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5952 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
5957 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
5958 GNUNET_SERVER_client_drop (bl->client);
5964 /* clean up 'normal' clients */
5967 while ((pos != NULL) && (pos->client != client))
5974 while (NULL != (mqe = pos->message_queue_head))
5976 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5977 pos->message_queue_tail, mqe);
5978 pos->message_count--;
5981 if (NULL != neighbours)
5982 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &null_mq_client_pointers,
5985 clients = pos->next;
5987 prev->next = pos->next;
5988 if (GNUNET_YES == pos->tcs_pending)
5993 if (pos->th != NULL)
5995 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5998 GNUNET_break (0 == pos->message_count);
6004 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
6006 struct NeighbourMapEntry *n = value;
6009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
6010 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
6012 disconnect_neighbour (n, GNUNET_NO);
6018 * Function called when the service shuts down. Unloads our plugins
6019 * and cancels pending validations.
6021 * @param cls closure, unused
6022 * @param tc task context (unused)
6025 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6027 struct TransportPlugin *plug;
6028 struct OwnAddressList *al;
6029 struct CheckHelloValidatedContext *chvc;
6031 shutdown_in_progress = GNUNET_YES;
6032 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
6035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6036 "Transport service is unloading plugins...\n");
6038 while (NULL != (plug = plugins))
6040 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6042 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6043 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6045 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6046 GNUNET_free (plug->lib_name);
6047 GNUNET_free (plug->short_name);
6048 while (NULL != (al = plug->addresses))
6050 plug->addresses = al->next;
6053 plugins = plug->next;
6056 if (my_private_key != NULL)
6057 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6058 GNUNET_free_non_null (our_hello);
6060 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &abort_validation,
6062 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6063 validation_map = NULL;
6066 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6068 GNUNET_SCHEDULER_cancel (ats_task);
6069 ats_task = GNUNET_SCHEDULER_NO_TASK;
6076 /* free 'chvc' data structure */
6077 while (NULL != (chvc = chvc_head))
6079 chvc_head = chvc->next;
6080 if (chvc->piter != NULL)
6082 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6083 GNUNET_STATISTICS_update (stats,
6085 ("# outstanding peerinfo iterate requests"), -1,
6091 GNUNET_assert (chvc->ve_count == 0);
6098 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6101 if (peerinfo != NULL)
6103 GNUNET_PEERINFO_disconnect (peerinfo);
6106 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6108 GNUNET_SCHEDULER_cancel (hello_task);
6109 hello_task = GNUNET_SCHEDULER_NO_TASK;
6111 /* Can we assume those are gone by now, or do we need to clean up
6113 GNUNET_break (bl_head == NULL);
6114 GNUNET_break (bc_head == NULL);
6115 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS Result callback\n");
6128 struct AtsBuildContext
6130 struct ATS_mechanism *mechanisms;
6131 struct ATS_peer *peers;
6138 find_and_count_addresses (void *cls, const GNUNET_HashCode * key, void *value)
6140 struct AtsBuildContext *abc = cls;
6141 struct NeighbourMapEntry *next = value;
6142 int found_addresses = GNUNET_NO;
6144 struct ReadyList *r_next = next->plugins;
6146 while (r_next != NULL)
6148 struct ForeignAddressList *a_next = r_next->addresses;
6150 while (a_next != NULL)
6153 found_addresses = GNUNET_YES;
6154 a_next = a_next->next;
6156 r_next = r_next->next;
6158 if (found_addresses)
6165 setup_ats_problem (void *cls, const GNUNET_HashCode * key, void *value)
6167 struct AtsBuildContext *abc = cls;
6168 struct NeighbourMapEntry *next = value;
6170 int found_addresses = GNUNET_NO;
6171 struct ReadyList *r_next = next->plugins;
6173 while (r_next != NULL)
6175 struct ForeignAddressList *a_next = r_next->addresses;
6177 while (a_next != NULL)
6179 if (found_addresses == GNUNET_NO)
6181 abc->peers[abc->c_peers].peer = next->id;
6182 abc->peers[abc->c_peers].m_head = NULL;
6183 abc->peers[abc->c_peers].m_tail = NULL;
6184 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6186 abc->mechanisms[abc->c_mechs].addr = a_next;
6187 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6188 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6189 abc->mechanisms[abc->c_mechs].next = NULL;
6190 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6191 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6192 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6193 GNUNET_CONTAINER_DLL_insert_tail (abc->peers[abc->c_peers].m_head,
6194 abc->peers[abc->c_peers].m_tail,
6195 &abc->mechanisms[abc->c_mechs]);
6196 found_addresses = GNUNET_YES;
6198 a_next = a_next->next;
6200 r_next = r_next->next;
6202 if (found_addresses == GNUNET_YES)
6209 create_ats_information (struct ATS_peer **p, int *c_p, struct ATS_mechanism **m,
6212 struct AtsBuildContext abc;
6215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6216 "ATS requires clean address information\n");
6220 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &find_and_count_addresses,
6223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6224 "Found %u peers with % u transport mechanisms\n", c_peers,
6228 if ((abc.c_peers == 0) && (abc.c_mechs == 0))
6238 GNUNET_malloc ((1 + abc.c_mechs) * sizeof (struct ATS_mechanism));
6239 abc.peers = GNUNET_malloc ((1 + abc.c_peers) * sizeof (struct ATS_peer));
6242 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &setup_ats_problem, &abc);
6245 (*c_m) = abc.c_mechs;
6246 (*c_p) = abc.c_peers;
6248 (*m) = abc.mechanisms;
6253 schedule_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6255 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6260 ats_task = GNUNET_SCHEDULER_NO_TASK;
6261 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6264 if (shutdown_in_progress == GNUNET_YES)
6267 struct GNUNET_TIME_Relative delta =
6268 GNUNET_TIME_absolute_get_difference (last_ats_execution,
6269 GNUNET_TIME_absolute_get ());
6271 if (delta.rel_value < ats_minimum_interval.rel_value)
6274 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6275 "Minimum time between cycles not reached\n");
6281 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6284 ats_calculate_bandwidth_distribution (ats);
6286 last_ats_execution = GNUNET_TIME_absolute_get ();
6289 GNUNET_SCHEDULER_add_delayed (ats_regular_interval, &schedule_ats, ats);
6294 struct ForeignAddressList *
6295 get_preferred_ats_address (struct NeighbourMapEntry *n)
6297 // TODO get ATS prefered address
6298 return find_ready_address (n);
6302 * Initiate transport service.
6304 * @param cls closure
6305 * @param server the initialized server
6306 * @param c configuration to use
6309 run (void *cls, struct GNUNET_SERVER_Handle *server,
6310 const struct GNUNET_CONFIGURATION_Handle *c)
6312 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6313 {&handle_start, NULL,
6314 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6315 {&handle_hello, NULL,
6316 GNUNET_MESSAGE_TYPE_HELLO, 0},
6317 {&handle_send, NULL,
6318 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6319 {&handle_request_connect, NULL,
6320 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
6321 sizeof (struct TransportRequestConnectMessage)},
6322 {&handle_set_quota, NULL,
6323 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6324 {&handle_address_lookup, NULL,
6325 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6327 {&handle_peer_address_lookup, NULL,
6328 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6330 {&handle_address_iterate, NULL,
6331 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6333 {&handle_blacklist_init, NULL,
6334 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
6335 sizeof (struct GNUNET_MessageHeader)},
6336 {&handle_blacklist_reply, NULL,
6337 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
6338 sizeof (struct BlacklistMessage)},
6344 unsigned long long tneigh;
6347 shutdown_in_progress = GNUNET_NO;
6349 stats = GNUNET_STATISTICS_create ("transport", cfg);
6350 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6351 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6352 /* parse configuration */
6354 GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT", "NEIGHBOUR_LIMIT",
6357 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
6360 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6362 ("Transport service is lacking key configuration settings. Exiting.\n"));
6363 GNUNET_SCHEDULER_shutdown ();
6366 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6369 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6370 validation_map = NULL;
6371 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6376 max_connect_per_transport = (uint32_t) tneigh;
6377 peerinfo = GNUNET_PEERINFO_connect (cfg);
6378 if (peerinfo == NULL)
6380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6381 _("Could not access PEERINFO service. Exiting.\n"));
6382 GNUNET_SCHEDULER_shutdown ();
6385 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6388 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6389 validation_map = NULL;
6390 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6392 GNUNET_free (keyfile);
6395 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6396 GNUNET_free (keyfile);
6397 if (my_private_key == NULL)
6399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6400 _("Transport service could not access hostkey. Exiting.\n"));
6401 GNUNET_SCHEDULER_shutdown ();
6404 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6407 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6408 validation_map = NULL;
6409 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6413 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6414 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
6415 &my_identity.hashPubKey);
6416 /* setup notification */
6417 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
6419 /* load plugins... */
6422 GNUNET_CONFIGURATION_get_value_string (c, "TRANSPORT", "PLUGINS", &plugs))
6424 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
6426 pos = strtok (plugs, " ");
6429 start_transport (server, pos);
6431 pos = strtok (NULL, " ");
6433 GNUNET_free (plugs);
6435 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
6440 /* Initializing ATS */
6443 unsigned long long value;
6449 int v_b_min = 64000;
6453 ats_minimum_interval = ATS_MIN_INTERVAL;
6454 ats_regular_interval = ATS_EXEC_INTERVAL;
6456 /* loading cost ressources */
6457 for (co = 0; co < available_ressources; co++)
6459 GNUNET_asprintf (§ion, "%s_UP", ressources[co].cfg_param);
6460 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6463 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6467 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6468 "Found ressource cost: [%s] = %llu\n", section, value);
6470 ressources[co].c_max = value;
6473 GNUNET_free (section);
6474 GNUNET_asprintf (§ion, "%s_DOWN", ressources[co].cfg_param);
6475 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6478 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6483 "Found ressource cost: [%s] = %llu\n", section, value);
6485 ressources[co].c_min = value;
6488 GNUNET_free (section);
6492 ats_init (D, U, R, v_b_min, v_n_min, ATS_MAX_ITERATIONS,
6493 ATS_MAX_EXEC_DURATION, &create_ats_information, ats_result_cb);
6494 ats_set_logging_options (ats, stats, cfg);
6495 GNUNET_break (GNUNET_OK ==
6496 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6497 "ATS_EXEC_INTERVAL",
6498 &ats_regular_interval));
6499 GNUNET_break (GNUNET_OK ==
6500 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6502 &ats_minimum_interval));
6504 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6509 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6511 /* If we have a blacklist file, read from it */
6512 read_blacklist_file (cfg);
6513 /* process client requests */
6514 GNUNET_SERVER_add_handlers (server, handlers);
6519 * The main function for the transport service.
6521 * @param argc number of arguments from the command line
6522 * @param argv command line arguments
6523 * @return 0 ok, 1 on error
6526 main (int argc, char *const *argv)
6528 a2s (NULL, NULL, 0); /* make compiler happy */
6529 return (GNUNET_OK ==
6530 GNUNET_SERVICE_run (argc, argv, "transport",
6531 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
6534 /* end of gnunet-service-transport.c */