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);
1616 if (mq->client != NULL)
1617 transmit_send_ok (mq->client, n, target, result);
1618 GNUNET_assert (n != NULL);
1619 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
1621 if (result == GNUNET_OK)
1622 try_transmission_to_peer (n);
1623 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1624 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, n);
1629 * Check the ready list for the given neighbour and if a plugin is
1630 * ready for transmission (and if we have a message), do so!
1632 * @param neighbour target peer for which to transmit
1635 try_transmission_to_peer (struct NeighbourMapEntry *n)
1637 struct ReadyList *rl;
1638 struct MessageQueue *mq;
1639 struct GNUNET_TIME_Relative timeout;
1643 if (n->messages_head == NULL)
1646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1647 "Transmission queue for `%4s' is empty\n", GNUNET_i2s (&n->id));
1649 return; /* nothing to do */
1652 mq = n->messages_head;
1653 force_address = GNUNET_YES;
1654 if (mq->specific_address == NULL)
1657 mq->specific_address = get_preferred_ats_address (n);
1658 GNUNET_STATISTICS_update (stats,
1660 ("# transport selected peer address freely"), 1,
1662 force_address = GNUNET_NO;
1664 if (mq->specific_address == NULL)
1666 GNUNET_STATISTICS_update (stats,
1668 ("# transport failed to selected peer address"),
1670 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1671 if (timeout.rel_value == 0)
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "No destination address available to transmit message of size %u to peer `%4s'\n",
1676 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id));
1678 GNUNET_STATISTICS_update (stats,
1680 ("# bytes in message queue for other peers"),
1681 -(int64_t) mq->message_buf_size, GNUNET_NO);
1682 GNUNET_STATISTICS_update (stats,
1684 ("# bytes discarded (no destination address available)"),
1685 mq->message_buf_size, GNUNET_NO);
1686 if (mq->client != NULL)
1687 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1688 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1690 return; /* nobody ready */
1692 GNUNET_STATISTICS_update (stats,
1694 ("# message delivery deferred (no address)"), 1,
1696 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1697 GNUNET_SCHEDULER_cancel (n->retry_task);
1699 GNUNET_SCHEDULER_add_delayed (timeout, &retry_transmission_task, n);
1701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1703 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id),
1706 /* FIXME: might want to trigger peerinfo lookup here
1707 * (unless that's already pending...) */
1710 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1711 if (mq->specific_address->connected == GNUNET_NO)
1712 mq->specific_address->connect_attempts++;
1713 rl = mq->specific_address->ready_list;
1714 mq->plugin = rl->plugin;
1715 if (!mq->internal_msg)
1716 mq->specific_address->in_transmit = GNUNET_YES;
1718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1719 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1720 mq->message_buf_size, GNUNET_i2s (&n->id),
1721 (mq->specific_address->addr !=
1722 NULL) ? a2s (mq->plugin->short_name, mq->specific_address->addr,
1723 mq->specific_address->addrlen) : "<inbound>",
1724 rl->plugin->short_name);
1726 GNUNET_STATISTICS_update (stats,
1728 ("# bytes in message queue for other peers"),
1729 -(int64_t) mq->message_buf_size, GNUNET_NO);
1730 GNUNET_STATISTICS_update (stats,
1731 gettext_noop ("# bytes pending with plugins"),
1732 mq->message_buf_size, GNUNET_NO);
1734 GNUNET_CONTAINER_DLL_insert (n->cont_head, n->cont_tail, mq);
1737 rl->plugin->api->send (rl->plugin->api->cls, &mq->neighbour_id,
1738 mq->message_buf, mq->message_buf_size,
1740 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1741 mq->specific_address->session,
1742 mq->specific_address->addr,
1743 mq->specific_address->addrlen, force_address,
1744 &transmit_send_continuation, mq);
1747 /* failure, but 'send' would not call continuation in this case,
1748 * so we need to do it here! */
1749 transmit_send_continuation (mq, &mq->neighbour_id, GNUNET_SYSERR);
1755 * Send the specified message to the specified peer.
1757 * @param client source of the transmission request (can be NULL)
1758 * @param peer_address ForeignAddressList where we should send this message
1759 * @param priority how important is the message
1760 * @param timeout how long do we have to transmit?
1761 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1762 * @param message_buf_size total size of all messages in message_buf
1763 * @param is_internal is this an internal message; these are pre-pended and
1764 * also do not count for plugins being "ready" to transmit
1765 * @param neighbour handle to the neighbour for transmission
1768 transmit_to_peer (struct TransportClient *client,
1769 struct ForeignAddressList *peer_address,
1770 unsigned int priority, struct GNUNET_TIME_Relative timeout,
1771 const char *message_buf, size_t message_buf_size,
1772 int is_internal, struct NeighbourMapEntry *neighbour)
1774 struct MessageQueue *mq;
1779 /* check for duplicate submission */
1780 mq = neighbour->messages_head;
1783 if (mq->client == client)
1785 /* client transmitted to same peer twice
1786 * before getting SEND_OK! */
1794 GNUNET_STATISTICS_update (stats,
1796 ("# bytes in message queue for other peers"),
1797 message_buf_size, GNUNET_NO);
1798 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1799 mq->specific_address = peer_address;
1800 mq->client = client;
1801 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1802 memcpy (&mq[1], message_buf, message_buf_size);
1803 mq->message_buf = (const char *) &mq[1];
1804 mq->message_buf_size = message_buf_size;
1805 memcpy (&mq->neighbour_id, &neighbour->id,
1806 sizeof (struct GNUNET_PeerIdentity));
1807 mq->internal_msg = is_internal;
1808 mq->priority = priority;
1809 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1811 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1812 neighbour->messages_tail, mq);
1814 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1815 neighbour->messages_tail,
1816 neighbour->messages_tail, mq);
1817 try_transmission_to_peer (neighbour);
1822 * Send a plain PING (without address or our HELLO) to the given
1823 * foreign address to try to establish a connection (and validate
1824 * that the other peer is really who he claimed he is).
1826 * @param n neighbour to PING
1829 transmit_plain_ping (struct NeighbourMapEntry *n)
1831 struct ValidationEntry *ve;
1832 struct TransportPingMessage ping;
1833 struct ReadyList *rl;
1834 struct TransportPlugin *plugin;
1835 struct ForeignAddressList *fal;
1837 if (!n->public_key_valid)
1839 /* This should not happen since the other peer
1840 * should send us a HELLO prior to sending his
1842 GNUNET_break_op (0);
1843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1844 "Could not transmit plain PING to `%s': public key not known\n",
1845 GNUNET_i2s (&n->id));
1848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1849 "Looking for addresses to transmit plain PING to `%s'\n",
1850 GNUNET_i2s (&n->id));
1851 for (rl = n->plugins; rl != NULL; rl = rl->next)
1853 plugin = rl->plugin;
1854 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1856 if (!fal->connected)
1858 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1859 ve->transport_name = GNUNET_strdup (plugin->short_name);
1861 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
1862 ve->send_time = GNUNET_TIME_absolute_get ();
1863 ve->session = fal->session;
1864 memcpy (&ve->publicKey, &n->publicKey,
1865 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1867 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1868 &timeout_hello_validation, ve);
1869 GNUNET_CONTAINER_multihashmap_put (validation_map, &n->id.hashPubKey, ve,
1870 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1871 ping.header.size = htons (sizeof (struct TransportPingMessage));
1872 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1873 ping.challenge = htonl (ve->challenge);
1874 memcpy (&ping.target, &n->id, sizeof (struct GNUNET_PeerIdentity));
1875 GNUNET_STATISTICS_update (stats,
1877 ("# PING without HELLO messages sent"), 1,
1879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s'\n",
1880 GNUNET_i2s (&n->id));
1881 transmit_to_peer (NULL, fal, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1882 HELLO_VERIFICATION_TIMEOUT, (const char *) &ping,
1883 sizeof (ping), GNUNET_YES, n);
1890 * Mark the given FAL entry as 'connected' (and hence preferred for
1891 * sending); also mark all others for the same peer as 'not connected'
1892 * (since only one can be preferred).
1894 * @param fal address to set to 'connected'
1897 mark_address_connected (struct ForeignAddressList *fal)
1899 struct ForeignAddressList *pos;
1900 struct ForeignAddressList *inbound;
1901 struct ForeignAddressList *outbound;
1903 GNUNET_assert (GNUNET_YES == fal->validated);
1904 if (fal->connected == GNUNET_YES)
1905 return; /* nothing to do */
1909 pos = fal->ready_list->addresses;
1912 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1913 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) &&
1914 (0 == fal->addrlen))
1916 if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1921 pos = fal->ready_list->addresses;
1924 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1925 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) &&
1928 if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1934 if (inbound != NULL)
1935 fprintf (stderr, "Peer: %s, have inbound connection.\n",
1936 GNUNET_i2s (&my_identity));
1937 if (outbound != NULL)
1938 fprintf (stderr, "Peer: %s, have outbound connection.\n",
1939 GNUNET_i2s (&my_identity));
1942 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1943 if ((inbound != NULL) && (0 != fal->addrlen) &&
1945 GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.
1946 hashPubKey, &my_identity.hashPubKey,
1950 fprintf (stderr, "Peer: %s, had inbound connection, ignoring outbound!\n",
1951 GNUNET_i2s (&my_identity));
1955 else if ((outbound != NULL) && (0 == fal->addrlen) &&
1957 GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->
1958 id.hashPubKey, &my_identity.hashPubKey,
1962 fprintf (stderr, "Peer: %s, have outbound connection, ignoring inbound!\n",
1963 GNUNET_i2s (&my_identity));
1968 pos = fal->ready_list->addresses;
1971 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1975 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1976 a2s (pos->ready_list->plugin->short_name, pos->addr,
1980 fprintf (stderr, "Peer: %s, setting %s connection to disconnected.\n",
1981 GNUNET_i2s (&my_identity),
1982 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
1984 pos->connected = GNUNET_NO;
1985 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1990 GNUNET_assert (GNUNET_NO == fal->connected);
1991 fal->connected = GNUNET_YES;
1992 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), 1,
1998 * Find an address in any of the available transports for
1999 * the given neighbour that would be good for message
2000 * transmission. This is essentially the transport selection
2003 * @param neighbour for whom to select an address
2004 * @return selected address, NULL if we have none
2006 struct ForeignAddressList *
2007 find_ready_address (struct NeighbourMapEntry *neighbour)
2009 struct ReadyList *head = neighbour->plugins;
2010 struct ForeignAddressList *addresses;
2011 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2012 struct ForeignAddressList *best_address;
2014 /* Hack to prefer unix domain sockets */
2015 struct ForeignAddressList *unix_address = NULL;
2017 best_address = NULL;
2018 while (head != NULL)
2020 addresses = head->addresses;
2021 while (addresses != NULL)
2023 if ((addresses->timeout.abs_value < now.abs_value) &&
2024 (addresses->connected == GNUNET_YES))
2027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2028 "Marking long-time inactive connection to `%4s' as down.\n",
2029 GNUNET_i2s (&neighbour->id));
2031 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2033 addresses->connected = GNUNET_NO;
2035 addresses = addresses->next;
2038 addresses = head->addresses;
2039 while (addresses != NULL)
2042 if (addresses->addr != NULL)
2043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2045 a2s (head->plugin->short_name, addresses->addr,
2046 addresses->addrlen), GNUNET_i2s (&neighbour->id),
2047 addresses->connected, addresses->in_transmit,
2048 addresses->validated, addresses->connect_attempts,
2049 (unsigned long long) addresses->timeout.abs_value,
2050 (unsigned int) addresses->distance);
2052 if (0 == strcmp (head->plugin->short_name, "unix"))
2054 if ((unix_address == NULL) ||
2055 ((unix_address != NULL) &&
2056 (addresses->latency.rel_value < unix_address->latency.rel_value)))
2057 unix_address = addresses;
2059 if (((best_address == NULL) || (addresses->connected == GNUNET_YES) ||
2060 (best_address->connected == GNUNET_NO)) &&
2061 (addresses->in_transmit == GNUNET_NO) && ((best_address == NULL) ||
2065 latency.rel_value)))
2066 best_address = addresses;
2067 /* FIXME: also give lower-latency addresses that are not
2068 * connected a chance some times... */
2069 addresses = addresses->next;
2071 if (unix_address != NULL)
2075 if (unix_address != NULL)
2077 best_address = unix_address;
2079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2080 "Found UNIX address, forced this address\n");
2083 if (best_address != NULL)
2086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2087 "Best address found (`%s') has latency of %llu ms.\n",
2088 (best_address->addrlen >
2089 0) ? a2s (best_address->ready_list->plugin->short_name,
2091 best_address->addrlen) : "<inbound>",
2092 best_address->latency.rel_value);
2097 GNUNET_STATISTICS_update (stats,
2099 ("# transmission attempts failed (no address)"),
2103 return best_address;
2110 struct GeneratorContext
2112 struct TransportPlugin *plug_pos;
2113 struct OwnAddressList *addr_pos;
2114 struct GNUNET_TIME_Absolute expiration;
2122 address_generator (void *cls, size_t max, void *buf)
2124 struct GeneratorContext *gc = cls;
2127 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2129 gc->plug_pos = gc->plug_pos->next;
2130 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2132 if (NULL == gc->plug_pos)
2138 GNUNET_HELLO_add_address (gc->plug_pos->short_name, gc->expiration,
2139 &gc->addr_pos[1], gc->addr_pos->addrlen, buf,
2141 gc->addr_pos = gc->addr_pos->next;
2148 transmit_our_hello_if_pong (void *cls, const GNUNET_HashCode * key, void *value)
2150 struct NeighbourMapEntry *npos = value;
2152 if (GNUNET_YES != npos->received_pong)
2155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2156 "Transmitting updated `%s' to neighbour `%4s'\n", "HELLO",
2157 GNUNET_i2s (&npos->id));
2159 GNUNET_STATISTICS_update (stats,
2161 ("# transmitted my HELLO to other peers"), 1,
2163 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
2164 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
2171 * Construct our HELLO message from all of the addresses of
2172 * all of the transports.
2175 * @param tc scheduler context
2178 refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2180 struct GNUNET_HELLO_Message *hello;
2181 struct TransportClient *cpos;
2182 struct GeneratorContext gc;
2184 hello_task = GNUNET_SCHEDULER_NO_TASK;
2185 gc.plug_pos = plugins;
2186 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2187 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2188 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2191 "Refreshed my `%s', new size is %d\n", "HELLO",
2192 GNUNET_HELLO_size (hello));
2194 GNUNET_STATISTICS_update (stats, gettext_noop ("# refreshed my HELLO"), 1,
2197 while (cpos != NULL)
2199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting my HELLO to client!\n");
2200 transmit_to_client (cpos, (const struct GNUNET_MessageHeader *) hello,
2205 GNUNET_free_non_null (our_hello);
2207 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2208 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2209 &transmit_our_hello_if_pong, NULL);
2214 * Schedule task to refresh hello (unless such a
2215 * task exists already).
2220 #if DEBUG_TRANSPORT_HELLO
2221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refresh_hello() called!\n");
2223 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2225 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
2230 * Iterator over hash map entries that NULLs the session of validation
2231 * entries that match the given session.
2233 * @param cls closure (the 'struct Session*' to match against)
2234 * @param key current key code (peer ID, not used)
2235 * @param value value in the hash map ('struct ValidationEntry*')
2236 * @return GNUNET_YES (we should continue to iterate)
2239 remove_session_validations (void *cls, const GNUNET_HashCode * key, void *value)
2241 struct Session *session = cls;
2242 struct ValidationEntry *ve = value;
2244 if (session == ve->session)
2251 * We've been disconnected from the other peer (for some
2252 * connection-oriented transport). Either quickly
2253 * re-establish the connection or signal the disconnect
2256 * Only signal CORE level disconnect if ALL addresses
2257 * for the peer are exhausted.
2259 * @param p overall plugin context
2260 * @param nl neighbour that was disconnected
2263 try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl)
2265 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2266 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "try_fast_reconnect not implemented!\n");
2267 /* Note: the idea here is to hide problems with transports (or
2268 * switching between plugins) from the core to eliminate the need to
2269 * re-negotiate session keys and the like; OTOH, we should tell core
2270 * quickly (much faster than timeout) `if a connection was lost and
2271 * could not be re-established (i.e. other peer went down or is
2272 * unable / refuses to communicate);
2274 * So we should consider:
2275 * 1) ideally: our own willingness / need to connect
2276 * 2) prior failures to connect to this peer (by plugin)
2277 * 3) ideally: reasons why other peer terminated (as far as knowable)
2279 * Most importantly, it must be POSSIBLE for another peer to terminate
2280 * a connection for a while (without us instantly re-establishing it).
2281 * Similarly, if another peer is gone we should quickly notify CORE.
2282 * OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2283 * on the other end), we should reconnect in such a way that BOTH CORE
2284 * services never even notice.
2285 * Furthermore, the same mechanism (or small variation) could be used
2286 * to switch to a better-performing plugin (ATS).
2288 * Finally, this needs to be tested throughly... */
2291 * GNUNET_NO in the call below makes transport disconnect the peer,
2292 * even if only a single address (out of say, six) went away. This
2293 * function must be careful to ONLY disconnect if the peer is gone,
2294 * not just a specific address.
2296 * More specifically, half the places it was used had it WRONG.
2299 /* No reconnect, signal disconnect instead! */
2302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2303 GNUNET_i2s (&nl->id), "try_fast_reconnect");
2305 GNUNET_STATISTICS_update (stats,
2307 ("# disconnects due to try_fast_reconnect"), 1,
2310 disconnect_neighbour (nl, GNUNET_YES);
2316 * Function that will be called whenever the plugin internally
2317 * cleans up a session pointer and hence the service needs to
2318 * discard all of those sessions as well. Plugins that do not
2319 * use sessions can simply omit calling this function and always
2320 * use NULL wherever a session pointer is needed.
2322 * @param cls closure
2323 * @param peer which peer was the session for
2324 * @param session which session is being destoyed
2327 plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
2328 struct Session *session)
2330 struct TransportPlugin *p = cls;
2331 struct NeighbourMapEntry *nl;
2332 struct ReadyList *rl;
2333 struct ForeignAddressList *pos;
2334 struct ForeignAddressList *prev;
2337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session ended with peer `%4s', %s\n",
2338 GNUNET_i2s (peer), "plugin_env_session_end");
2340 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2341 &remove_session_validations, session);
2342 nl = find_neighbour (peer);
2346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2347 "No neighbour record found for peer `%4s'\n",
2350 return; /* was never marked as connected */
2355 if (rl->plugin == p)
2362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2363 "Plugin was associated with peer `%4s'\n", GNUNET_i2s (peer));
2365 GNUNET_STATISTICS_update (stats,
2366 gettext_noop ("# disconnects due to session end"),
2368 disconnect_neighbour (nl, GNUNET_YES);
2372 pos = rl->addresses;
2373 while ((pos != NULL) && (pos->session != session))
2381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2382 "Session was never marked as ready for peer `%4s'\n",
2386 int validations_pending =
2387 GNUNET_CONTAINER_multihashmap_contains (validation_map,
2390 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2391 if (validations_pending == GNUNET_YES)
2394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395 "Not disconnecting from peer `%4s due to pending address validations\n",
2401 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2402 GNUNET_STATISTICS_update (stats,
2404 ("# disconnects due to unready session"), 1,
2407 disconnect_neighbour (nl, GNUNET_YES);
2408 return; /* was never marked as connected */
2410 pos->session = NULL;
2411 if (GNUNET_YES == pos->connected)
2413 pos->connected = GNUNET_NO;
2414 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2417 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2419 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2420 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2423 if (pos->addrlen != 0)
2425 if (nl->received_pong != GNUNET_NO)
2427 GNUNET_STATISTICS_update (stats,
2429 ("# try_fast_reconnect thanks to plugin_env_session_end"),
2431 if (GNUNET_YES == pos->connected)
2432 try_fast_reconnect (p, nl);
2436 GNUNET_STATISTICS_update (stats,
2438 ("# disconnects due to missing pong"), 1,
2440 /* FIXME this is never true?! See: line 2416 */
2441 if (GNUNET_YES == pos->connected)
2442 disconnect_neighbour (nl, GNUNET_YES);
2447 /* was inbound connection, free 'pos' */
2449 rl->addresses = pos->next;
2451 prev->next = pos->next;
2452 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2454 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2455 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2457 GNUNET_free_non_null (pos->ressources);
2458 GNUNET_free_non_null (pos->quality);
2460 ats_modify_problem_state (ats, ATS_MODIFIED);
2462 if (GNUNET_YES != pos->connected)
2464 /* nothing else to do, connection was never up... */
2468 pos->connected = GNUNET_NO;
2469 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2473 if (nl->received_pong == GNUNET_NO)
2475 GNUNET_STATISTICS_update (stats,
2476 gettext_noop ("# disconnects due to NO pong"), 1,
2478 disconnect_neighbour (nl, GNUNET_YES);
2479 return; /* nothing to do, never connected... */
2481 /* check if we have any validated addresses left */
2482 pos = rl->addresses;
2485 if (GNUNET_YES == pos->validated)
2487 GNUNET_STATISTICS_update (stats,
2489 ("# try_fast_reconnect thanks to validated_address"),
2491 try_fast_reconnect (p, nl);
2496 /* no valid addresses left, signal disconnect! */
2499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2500 GNUNET_i2s (peer), "plugin_env_session_end");
2502 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2503 * it means there aren't any left for this PLUGIN/PEER combination! So
2504 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2505 * when it isn't necessary. Using GNUNET_YES at least checks to see
2506 * if there are any addresses that work first, so as not to overdo it.
2509 GNUNET_STATISTICS_update (stats,
2511 ("# disconnects due to plugin_env_session_end"), 1,
2513 disconnect_neighbour (nl, GNUNET_YES);
2518 * Function that must be called by each plugin to notify the
2519 * transport service about the addresses under which the transport
2520 * provided by the plugin can be reached.
2522 * @param cls closure
2523 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2524 * @param addr one of the addresses of the host, NULL for the last address
2525 * the specific address format depends on the transport
2526 * @param addrlen length of the address
2529 plugin_env_notify_address (void *cls, int add_remove, const void *addr,
2532 struct TransportPlugin *p = cls;
2533 struct OwnAddressList *al;
2534 struct OwnAddressList *prev;
2536 GNUNET_assert (p->api != NULL);
2538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2540 GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" :
2541 "Removing `%s':%s from the set of our addresses\n",
2542 a2s (p->short_name, addr, addrlen), p->short_name);
2544 GNUNET_assert (addr != NULL);
2545 if (GNUNET_NO == add_remove)
2551 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2554 p->addresses = al->next;
2556 prev->next = al->next;
2567 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2568 al->next = p->addresses;
2570 al->addrlen = addrlen;
2571 memcpy (&al[1], addr, addrlen);
2577 * Notify all of our clients about a peer connecting.
2580 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2581 struct GNUNET_TIME_Relative latency, uint32_t distance)
2583 struct ConnectInfoMessage *cim;
2584 struct TransportClient *cpos;
2588 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2595 "Notifying clients about connection with `%s'\n",
2598 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), 1,
2603 sizeof (struct ConnectInfoMessage) +
2604 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2605 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2606 cim = GNUNET_malloc (size);
2607 cim->header.size = htons (size);
2608 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2609 cim->ats_count = htonl (2);
2610 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2611 (&cim->ats)[0].value = htonl (distance);
2612 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2613 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2614 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2615 (&cim->ats)[2].value = htonl (0);
2616 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2618 /* notify ats about connecting peer */
2619 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2622 ats_modify_problem_state (ats, ATS_MODIFIED);
2623 ats_calculate_bandwidth_distribution (ats);
2627 while (cpos != NULL)
2629 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2637 * Notify all of our clients about a peer disconnecting.
2640 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2642 struct DisconnectInfoMessage dim;
2643 struct TransportClient *cpos;
2645 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652 "Notifying clients about lost connection to `%s'\n",
2655 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), -1,
2657 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2658 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2659 dim.reserved = htonl (0);
2660 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2662 /* notify ats about connecting peer */
2663 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2666 ats_modify_problem_state (ats, ATS_MODIFIED);
2667 ats_calculate_bandwidth_distribution (ats);
2672 while (cpos != NULL)
2674 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2681 * Find a ForeignAddressList entry for the given neighbour
2682 * that matches the given address and transport.
2684 * @param neighbour which peer we care about
2685 * @param tname name of the transport plugin
2686 * @param session session to look for, NULL for 'any'; otherwise
2687 * can be used for the service to "learn" this session ID
2689 * @param addr binary address
2690 * @param addrlen length of addr
2691 * @return NULL if no such entry exists
2693 static struct ForeignAddressList *
2694 find_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2695 struct Session *session, const char *addr, uint16_t addrlen)
2697 struct ReadyList *head;
2698 struct ForeignAddressList *pos;
2700 head = neighbour->plugins;
2701 while (head != NULL)
2703 if (0 == strcmp (tname, head->plugin->short_name))
2709 pos = head->addresses;
2710 while ((pos != NULL) &&
2711 ((pos->addrlen != addrlen) ||
2712 (memcmp (pos->addr, addr, addrlen) != 0)))
2714 if ((session != NULL) && (pos->session == session))
2718 if ((session != NULL) && (pos != NULL))
2719 pos->session = session; /* learn it! */
2725 * Get the peer address struct for the given neighbour and
2726 * address. If it doesn't yet exist, create it.
2728 * @param neighbour which peer we care about
2729 * @param tname name of the transport plugin
2730 * @param session session of the plugin, or NULL for none
2731 * @param addr binary address
2732 * @param addrlen length of addr
2733 * @return NULL if we do not have a transport plugin for 'tname'
2735 static struct ForeignAddressList *
2736 add_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2737 struct Session *session, const char *addr, uint16_t addrlen)
2739 struct ReadyList *head;
2740 struct ForeignAddressList *ret;
2743 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2746 head = neighbour->plugins;
2748 while (head != NULL)
2750 if (0 == strcmp (tname, head->plugin->short_name))
2756 ret = GNUNET_malloc (sizeof (struct ForeignAddressList) + addrlen);
2757 ret->session = session;
2758 if ((addrlen > 0) && (addr != NULL))
2760 ret->addr = (const char *) &ret[1];
2761 memcpy (&ret[1], addr, addrlen);
2769 GNUNET_malloc (available_ressources *
2770 sizeof (struct ATS_ressource_entry));
2771 for (c = 0; c < available_ressources; c++)
2773 struct ATS_ressource_entry *r = ret->ressources;
2776 r[c].atis_index = ressources[c].atis_index;
2777 if (0 == strcmp (neighbour->plugins->plugin->short_name, "unix"))
2779 r[c].c = ressources[c].c_unix;
2781 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "udp"))
2783 r[c].c = ressources[c].c_udp;
2785 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "tcp"))
2787 r[c].c = ressources[c].c_tcp;
2789 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "http"))
2791 r[c].c = ressources[c].c_http;
2793 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "https"))
2795 r[c].c = ressources[c].c_https;
2797 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "wlan"))
2799 r[c].c = ressources[c].c_wlan;
2803 r[c].c = ressources[c].c_default;
2804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2805 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2806 GNUNET_i2s (&neighbour->id),
2807 neighbour->plugins->plugin->short_name);
2812 GNUNET_malloc (available_quality_metrics *
2813 sizeof (struct ATS_quality_entry));
2814 ret->addrlen = addrlen;
2816 GNUNET_TIME_relative_to_absolute
2817 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2818 ret->latency = GNUNET_TIME_relative_get_forever ();
2821 GNUNET_TIME_relative_to_absolute
2822 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2823 ret->ready_list = head;
2824 ret->next = head->addresses;
2825 head->addresses = ret;
2831 * Closure for 'add_validated_address'.
2833 struct AddValidatedAddressContext
2836 * Entry that has been validated.
2838 const struct ValidationEntry *ve;
2841 * Flag set after we have added the address so
2842 * that we terminate the iteration next time.
2849 * Callback function used to fill a buffer of max bytes with a list of
2850 * addresses in the format used by HELLOs. Should use
2851 * "GNUNET_HELLO_add_address" as a helper function.
2853 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2854 * @param max maximum number of bytes that can be written to buf
2855 * @param buf where to write the address information
2856 * @return number of bytes written, 0 to signal the
2857 * end of the iteration.
2860 add_validated_address (void *cls, size_t max, void *buf)
2862 struct AddValidatedAddressContext *avac = cls;
2863 const struct ValidationEntry *ve = avac->ve;
2865 if (GNUNET_YES == avac->done)
2867 avac->done = GNUNET_YES;
2868 return GNUNET_HELLO_add_address (ve->transport_name,
2869 GNUNET_TIME_relative_to_absolute
2870 (HELLO_ADDRESS_EXPIRATION), ve->addr,
2871 ve->addrlen, buf, max);
2877 * Closure for 'check_address_exists'.
2879 struct CheckAddressExistsClosure
2882 * Address to check for.
2887 * Name of the transport.
2894 struct Session *session;
2897 * Set to GNUNET_YES if the address exists.
2910 * Iterator over hash map entries. Checks if the given
2911 * validation entry is for the same address as what is given
2914 * @param cls the 'struct CheckAddressExistsClosure*'
2915 * @param key current key code (ignored)
2916 * @param value value in the hash map ('struct ValidationEntry')
2917 * @return GNUNET_YES if we should continue to
2918 * iterate (mismatch), GNUNET_NO if not (entry matched)
2921 check_address_exists (void *cls, const GNUNET_HashCode * key, void *value)
2923 struct CheckAddressExistsClosure *caec = cls;
2924 struct ValidationEntry *ve = value;
2926 if ((0 == strcmp (caec->tname, ve->transport_name)) &&
2927 (caec->addrlen == ve->addrlen) &&
2928 (0 == memcmp (caec->addr, ve->addr, caec->addrlen)))
2930 caec->exists = GNUNET_YES;
2933 if ((ve->session != NULL) && (caec->session == ve->session))
2935 caec->exists = GNUNET_YES;
2943 neighbour_timeout_task (void *cls,
2944 const struct GNUNET_SCHEDULER_TaskContext *tc)
2946 struct NeighbourMapEntry *n = cls;
2949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2950 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2952 GNUNET_STATISTICS_update (stats,
2953 gettext_noop ("# disconnects due to timeout"), 1,
2955 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2956 disconnect_neighbour (n, GNUNET_NO);
2961 * Schedule the job that will cause us to send a PING to the
2962 * foreign address to evaluate its validity and latency.
2964 * @param fal address to PING
2967 schedule_next_ping (struct ForeignAddressList *fal);
2971 * Add the given address to the list of foreign addresses
2972 * available for the given peer (check for duplicates).
2974 * @param cls the respective 'struct NeighbourMapEntry' to update
2975 * @param tname name of the transport
2976 * @param expiration expiration time
2977 * @param addr the address
2978 * @param addrlen length of the address
2979 * @return GNUNET_OK (always)
2982 add_to_foreign_address_list (void *cls, const char *tname,
2983 struct GNUNET_TIME_Absolute expiration,
2984 const void *addr, uint16_t addrlen)
2986 struct NeighbourMapEntry *n = cls;
2987 struct ForeignAddressList *fal;
2990 GNUNET_STATISTICS_update (stats,
2992 ("# valid peer addresses returned by PEERINFO"), 1,
2995 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2998 #if DEBUG_TRANSPORT_HELLO
2999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3000 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3001 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&n->id),
3002 expiration.abs_value);
3004 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3007 GNUNET_STATISTICS_update (stats,
3009 ("# previously validated addresses lacking transport"),
3014 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3015 schedule_next_ping (fal);
3021 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3027 "Failed to add new address for `%4s'\n", GNUNET_i2s (&n->id));
3031 if (fal->validated == GNUNET_NO)
3033 fal->validated = GNUNET_YES;
3034 GNUNET_STATISTICS_update (stats,
3036 ("# peer addresses considered valid"), 1,
3039 if (try == GNUNET_YES)
3042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3043 "Have new addresses, will try to trigger transmissions.\n");
3045 try_transmission_to_peer (n);
3052 * Add addresses in validated HELLO "h" to the set of addresses
3053 * we have for this peer.
3055 * @param cls closure ('struct NeighbourMapEntry*')
3056 * @param peer id of the peer, NULL for last call
3057 * @param h hello message for the peer (can be NULL)
3058 * @param err_msg NULL if successful, otherwise contains error message
3061 add_hello_for_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
3062 const struct GNUNET_HELLO_Message *h, const char *err_msg)
3064 struct NeighbourMapEntry *n = cls;
3066 if (err_msg != NULL)
3069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3070 _("Error in communication with PEERINFO service: %s\n"),
3077 GNUNET_STATISTICS_update (stats,
3079 ("# outstanding peerinfo iterate requests"), -1,
3085 return; /* no HELLO available */
3087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3088 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3089 "HELLO", GNUNET_i2s (peer));
3091 if (GNUNET_YES != n->public_key_valid)
3093 GNUNET_HELLO_get_key (h, &n->publicKey);
3094 n->public_key_valid = GNUNET_YES;
3096 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
3102 * Create a fresh entry in our neighbour list for the given peer.
3103 * Will try to transmit our current HELLO to the new neighbour.
3104 * Do not call this function directly, use 'setup_peer_check_blacklist.
3106 * @param peer the peer for which we create the entry
3107 * @param do_hello should we schedule transmitting a HELLO
3108 * @return the new neighbour list entry
3110 static struct NeighbourMapEntry *
3111 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer, int do_hello)
3113 struct NeighbourMapEntry *n;
3114 struct TransportPlugin *tp;
3115 struct ReadyList *rl;
3118 memcmp (peer, &my_identity,
3119 sizeof (struct GNUNET_PeerIdentity)));
3121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up state for neighbour `%4s'\n",
3124 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), 1,
3126 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3129 GNUNET_TIME_relative_to_absolute
3130 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3131 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3132 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3133 MAX_BANDWIDTH_CARRY_S);
3137 if ((tp->api->send != NULL) && (!is_blacklisted (peer, tp)))
3139 rl = GNUNET_malloc (sizeof (struct ReadyList));
3141 rl->next = n->plugins;
3144 rl->addresses = NULL;
3148 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3151 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3152 &neighbour_timeout_task, n);
3153 GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n,
3154 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3157 GNUNET_STATISTICS_update (stats,
3159 ("# peerinfo new neighbor iterate requests"), 1,
3161 GNUNET_STATISTICS_update (stats,
3163 ("# outstanding peerinfo iterate requests"), 1,
3166 GNUNET_PEERINFO_iterate (peerinfo, peer, GNUNET_TIME_UNIT_FOREVER_REL,
3167 &add_hello_for_peer, n);
3169 GNUNET_STATISTICS_update (stats,
3170 gettext_noop ("# HELLO's sent to new neighbors"),
3172 if (NULL != our_hello)
3173 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
3174 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
3182 * Function called after we have checked if communicating
3183 * with a given peer is acceptable.
3185 * @param cls closure
3186 * @param n NULL if communication is not acceptable
3188 typedef void (*SetupContinuation) (void *cls, struct NeighbourMapEntry * n);
3192 * Information kept for each client registered to perform
3198 * This is a linked list.
3200 struct Blacklisters *next;
3203 * This is a linked list.
3205 struct Blacklisters *prev;
3208 * Client responsible for this entry.
3210 struct GNUNET_SERVER_Client *client;
3213 * Blacklist check that we're currently performing.
3215 struct BlacklistCheck *bc;
3221 * Head of DLL of blacklisting clients.
3223 static struct Blacklisters *bl_head;
3226 * Tail of DLL of blacklisting clients.
3228 static struct Blacklisters *bl_tail;
3232 * Context we use when performing a blacklist check.
3234 struct BlacklistCheck
3238 * This is a linked list.
3240 struct BlacklistCheck *next;
3243 * This is a linked list.
3245 struct BlacklistCheck *prev;
3248 * Peer being checked.
3250 struct GNUNET_PeerIdentity peer;
3253 * Option for setup neighbour afterwards.
3258 * Continuation to call with the result.
3260 SetupContinuation cont;
3268 * Current transmission request handle for this client, or NULL if no
3269 * request is pending.
3271 struct GNUNET_CONNECTION_TransmitHandle *th;
3274 * Our current position in the blacklisters list.
3276 struct Blacklisters *bl_pos;
3279 * Current task performing the check.
3281 GNUNET_SCHEDULER_TaskIdentifier task;
3286 * Head of DLL of active blacklisting queries.
3288 static struct BlacklistCheck *bc_head;
3291 * Tail of DLL of active blacklisting queries.
3293 static struct BlacklistCheck *bc_tail;
3297 * Perform next action in the blacklist check.
3299 * @param cls the 'struct BlacklistCheck*'
3303 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3306 * Transmit blacklist query to the client.
3308 * @param cls the 'struct BlacklistCheck'
3309 * @param size number of bytes allowed
3310 * @param buf where to copy the message
3311 * @return number of bytes copied to buf
3314 transmit_blacklist_message (void *cls, size_t size, void *buf)
3316 struct BlacklistCheck *bc = cls;
3317 struct Blacklisters *bl;
3318 struct BlacklistMessage bm;
3323 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3324 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3325 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3326 "Failed to send blacklist test for peer `%s' to client\n",
3327 GNUNET_i2s (&bc->peer));
3331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3332 "Sending blacklist test for peer `%s' to client\n",
3333 GNUNET_i2s (&bc->peer));
3336 bm.header.size = htons (sizeof (struct BlacklistMessage));
3337 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3338 bm.is_allowed = htonl (0);
3340 memcpy (buf, &bm, sizeof (bm));
3341 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3347 * Perform next action in the blacklist check.
3349 * @param cls the 'struct BlacklistCheck*'
3353 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3355 struct BlacklistCheck *bc = cls;
3356 struct Blacklisters *bl;
3358 bc->task = GNUNET_SCHEDULER_NO_TASK;
3363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3364 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3365 GNUNET_i2s (&bc->peer));
3367 bc->cont (bc->cont_cls, setup_new_neighbour (&bc->peer, bc->do_hello));
3375 GNUNET_SERVER_notify_transmit_ready (bl->client,
3376 sizeof (struct BlacklistMessage),
3377 GNUNET_TIME_UNIT_FOREVER_REL,
3378 &transmit_blacklist_message, bc);
3384 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3385 * does not yet exist, check the blacklist. If the blacklist says creating
3386 * one is acceptable, create one and call the continuation; otherwise
3387 * call the continuation with NULL.
3389 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3390 * @param do_hello should we also schedule sending our HELLO to the peer
3391 * if this is a new record
3392 * @param cont function to call with the 'struct NeigbhbourList*'
3393 * @param cont_cls closure for cont
3396 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3397 int do_hello, SetupContinuation cont,
3400 struct NeighbourMapEntry *n;
3401 struct BlacklistCheck *bc;
3403 n = find_neighbour (peer);
3407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3408 "Neighbour record exists for peer `%s'\n", GNUNET_i2s (peer));
3414 if (bl_head == NULL)
3417 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3419 setup_new_neighbour (peer, do_hello);
3422 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3423 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3425 bc->do_hello = do_hello;
3427 bc->cont_cls = cont_cls;
3428 bc->bl_pos = bl_head;
3429 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3434 * Function called with the result of querying a new blacklister about
3435 * it being allowed (or not) to continue to talk to an existing neighbour.
3437 * @param cls the original 'struct NeighbourMapEntry'
3438 * @param n NULL if we need to disconnect
3441 confirm_or_drop_neighbour (void *cls, struct NeighbourMapEntry *n)
3443 struct NeighbourMapEntry *orig = cls;
3448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
3449 GNUNET_i2s (&orig->id), "confirm_or_drop_neighboUr");
3451 GNUNET_STATISTICS_update (stats,
3452 gettext_noop ("# disconnects due to blacklist"),
3454 disconnect_neighbour (orig, GNUNET_NO);
3459 struct TestConnectionContext
3463 struct Blacklisters *bl;
3468 test_connection_ok (void *cls, const GNUNET_HashCode * key, void *value)
3470 struct TestConnectionContext *tcc = cls;
3471 struct NeighbourMapEntry *n = value;
3472 struct BlacklistCheck *bc;
3475 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3476 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3478 bc->do_hello = GNUNET_NO;
3479 bc->cont = &confirm_or_drop_neighbour;
3481 bc->bl_pos = tcc->bl;
3482 if (GNUNET_YES == tcc->first)
3484 /* all would wait for the same client, no need to
3485 * create more than just the first task right now */
3486 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3487 tcc->first = GNUNET_NO;
3494 * Handle a request to start a blacklist.
3496 * @param cls closure (always NULL)
3497 * @param client identification of the client
3498 * @param message the actual message
3501 handle_blacklist_init (void *cls, struct GNUNET_SERVER_Client *client,
3502 const struct GNUNET_MessageHeader *message)
3504 struct Blacklisters *bl;
3505 struct TestConnectionContext tcc;
3510 if (bl->client == client)
3513 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3518 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3519 bl->client = client;
3520 GNUNET_SERVER_client_keep (client);
3521 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3522 /* confirm that all existing connections are OK! */
3524 tcc.first = GNUNET_YES;
3525 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &test_connection_ok, &tcc);
3530 * Handle a request to blacklist a peer.
3532 * @param cls closure (always NULL)
3533 * @param client identification of the client
3534 * @param message the actual message
3537 handle_blacklist_reply (void *cls, struct GNUNET_SERVER_Client *client,
3538 const struct GNUNET_MessageHeader *message)
3540 const struct BlacklistMessage *msg =
3541 (const struct BlacklistMessage *) message;
3542 struct Blacklisters *bl;
3543 struct BlacklistCheck *bc;
3546 while ((bl != NULL) && (bl->client != client))
3551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
3553 /* FIXME: other error handling here!? */
3554 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3559 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3563 "Blacklist check failed, peer not allowed\n");
3565 bc->cont (bc->cont_cls, NULL);
3566 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3573 "Blacklist check succeeded, continuing with checks\n");
3575 bc->bl_pos = bc->bl_pos->next;
3576 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3578 /* check if any other bc's are waiting for this blacklister */
3582 if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
3583 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3590 * Send periodic PING messages to a given foreign address.
3592 * @param cls our 'struct PeriodicValidationContext*'
3593 * @param tc task context
3596 send_periodic_ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3598 struct ForeignAddressList *peer_address = cls;
3599 struct TransportPlugin *tp;
3600 struct ValidationEntry *va;
3601 struct NeighbourMapEntry *neighbour;
3602 struct TransportPingMessage ping;
3603 struct CheckAddressExistsClosure caec;
3605 uint16_t hello_size;
3609 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3610 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3612 GNUNET_assert (peer_address != NULL);
3613 tp = peer_address->ready_list->plugin;
3614 neighbour = peer_address->ready_list->neighbour;
3615 if (GNUNET_YES != neighbour->public_key_valid)
3617 /* no public key yet, try again later */
3618 schedule_next_ping (peer_address);
3621 caec.addr = peer_address->addr;
3622 caec.addrlen = peer_address->addrlen;
3623 caec.tname = tp->short_name;
3624 caec.session = peer_address->session;
3625 caec.exists = GNUNET_NO;
3627 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
3629 if (caec.exists == GNUNET_YES)
3631 /* During validation attempts we will likely trigger the other
3632 * peer trying to validate our address which in turn will cause
3633 * it to send us its HELLO, so we expect to hit this case rather
3634 * frequently. Only print something if we are very verbose. */
3635 #if DEBUG_TRANSPORT > 1
3636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3637 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3638 (peer_address->addr != NULL) ? a2s (tp->short_name,
3640 peer_address->addrlen) :
3641 "<inbound>", tp->short_name, GNUNET_i2s (&neighbour->id));
3643 schedule_next_ping (peer_address);
3646 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3647 va->transport_name = GNUNET_strdup (tp->short_name);
3649 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
3650 va->send_time = GNUNET_TIME_absolute_get ();
3651 va->session = peer_address->session;
3652 if (peer_address->addr != NULL)
3654 va->addr = (const void *) &va[1];
3655 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3656 va->addrlen = peer_address->addrlen;
3658 memcpy (&va->publicKey, &neighbour->publicKey,
3659 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3662 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3663 &timeout_hello_validation, va);
3664 GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->id.hashPubKey,
3666 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3668 if (peer_address->validated != GNUNET_YES)
3669 hello_size = GNUNET_HELLO_size (our_hello);
3673 tsize = sizeof (struct TransportPingMessage) + hello_size;
3675 if (peer_address->addr != NULL)
3677 slen = strlen (tp->short_name) + 1;
3678 tsize += slen + peer_address->addrlen;
3682 slen = 0; /* make gcc happy */
3684 message_buf = GNUNET_malloc (tsize);
3685 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3686 ping.challenge = htonl (va->challenge);
3687 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
3688 if (peer_address->validated != GNUNET_YES)
3690 memcpy (message_buf, our_hello, hello_size);
3693 if (peer_address->addr != NULL)
3696 htons (sizeof (struct TransportPingMessage) + peer_address->addrlen +
3698 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3699 tp->short_name, slen);
3700 memcpy (&message_buf
3701 [hello_size + sizeof (struct TransportPingMessage) + slen],
3702 peer_address->addr, peer_address->addrlen);
3706 ping.header.size = htons (sizeof (struct TransportPingMessage));
3709 memcpy (&message_buf[hello_size], &ping,
3710 sizeof (struct TransportPingMessage));
3712 #if DEBUG_TRANSPORT_REVALIDATION
3713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3714 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3715 (peer_address->addr !=
3716 NULL) ? a2s (peer_address->plugin->short_name,
3718 peer_address->addrlen) : "<inbound>",
3719 tp->short_name, GNUNET_i2s (&neighbour->id), "HELLO", hello_size,
3722 if (peer_address->validated != GNUNET_YES)
3723 GNUNET_STATISTICS_update (stats,
3724 gettext_noop ("# PING with HELLO messages sent"),
3727 GNUNET_STATISTICS_update (stats,
3729 ("# PING without HELLO messages sent"), 1,
3731 GNUNET_STATISTICS_update (stats,
3733 ("# PING messages sent for re-validation"), 1,
3735 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3736 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
3738 GNUNET_free (message_buf);
3739 schedule_next_ping (peer_address);
3744 * Schedule the job that will cause us to send a PING to the
3745 * foreign address to evaluate its validity and latency.
3747 * @param fal address to PING
3750 schedule_next_ping (struct ForeignAddressList *fal)
3752 struct GNUNET_TIME_Relative delay;
3754 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3756 GNUNET_SCHEDULER_cancel (fal->revalidate_task);
3757 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3759 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3760 delay.rel_value /= 2; /* do before expiration */
3761 delay = GNUNET_TIME_relative_min (delay, LATENCY_EVALUATION_MAX_DELAY);
3762 if (GNUNET_YES != fal->estimated)
3764 delay = GNUNET_TIME_UNIT_ZERO;
3765 fal->estimated = GNUNET_YES;
3768 if (GNUNET_YES == fal->connected)
3771 GNUNET_TIME_relative_min (delay,
3772 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3774 /* FIXME: also adjust delay based on how close the last
3775 * observed latency is to the latency of the best alternative */
3776 /* bound how fast we can go */
3777 delay = GNUNET_TIME_relative_max (delay, GNUNET_TIME_UNIT_SECONDS);
3778 /* randomize a bit (to avoid doing all at the same time) */
3780 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3782 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3783 fal->revalidate_task =
3784 GNUNET_SCHEDULER_add_delayed (delay, &send_periodic_ping, fal);
3791 * Function that will be called if we receive some payload
3792 * from another peer.
3794 * @param message the payload
3795 * @param n peer who claimed to be the sender
3798 handle_payload_message (const struct GNUNET_MessageHeader *message,
3799 struct NeighbourMapEntry *n)
3801 struct InboundMessage *im;
3802 struct TransportClient *cpos;
3805 msize = ntohs (message->size);
3806 if (n->received_pong == GNUNET_NO)
3809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3810 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3811 ntohs (message->type), ntohs (message->size),
3812 GNUNET_i2s (&n->id));
3814 GNUNET_free_non_null (n->pre_connect_message_buffer);
3815 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3816 memcpy (n->pre_connect_message_buffer, message, msize);
3821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3822 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3823 ntohs (message->type), ntohs (message->size),
3824 GNUNET_i2s (&n->id));
3827 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, (ssize_t) msize))
3829 n->quota_violation_count++;
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3833 n->in_tracker.available_bytes_per_s__,
3834 n->quota_violation_count);
3836 /* Discount 32k per violation */
3837 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
3841 if (n->quota_violation_count > 0)
3843 /* try to add 32k back */
3844 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
3845 n->quota_violation_count--;
3848 GNUNET_STATISTICS_update (stats,
3850 ("# payload received from other peers"), msize,
3852 /* transmit message to all clients */
3853 uint32_t ats_count = 2;
3855 sizeof (struct InboundMessage) +
3856 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3857 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3860 im = GNUNET_malloc (size);
3861 im->header.size = htons (size);
3862 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3864 im->ats_count = htonl (ats_count);
3865 /* Setting ATS data */
3866 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3867 (&(im->ats))[0].value = htonl (n->distance);
3868 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3869 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3870 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3871 (&(im->ats))[ats_count].value = htonl (0);
3873 memcpy (&((&(im->ats))[ats_count + 1]), message, msize);
3875 while (cpos != NULL)
3877 transmit_to_client (cpos, &im->header, GNUNET_YES);
3885 * Iterator over hash map entries. Checks if the given validation
3886 * entry is for the same challenge as what is given in the PONG.
3888 * @param cls the 'struct TransportPongMessage*'
3889 * @param key peer identity
3890 * @param value value in the hash map ('struct ValidationEntry')
3891 * @return GNUNET_YES if we should continue to
3892 * iterate (mismatch), GNUNET_NO if not (entry matched)
3895 check_pending_validation (void *cls, const GNUNET_HashCode * key, void *value)
3897 const struct TransportPongMessage *pong = cls;
3898 struct ValidationEntry *ve = value;
3899 struct AddValidatedAddressContext avac;
3900 unsigned int challenge = ntohl (pong->challenge);
3901 struct GNUNET_HELLO_Message *hello;
3902 struct GNUNET_PeerIdentity target;
3903 struct NeighbourMapEntry *n;
3904 struct ForeignAddressList *fal;
3905 struct OwnAddressList *oal;
3906 struct TransportPlugin *tp;
3907 struct GNUNET_MessageHeader *prem;
3913 ps = ntohs (pong->header.size);
3914 if (ps < sizeof (struct TransportPongMessage))
3916 GNUNET_break_op (0);
3919 addr = (const char *) &pong[1];
3920 slen = strlen (ve->transport_name) + 1;
3921 if ((ps - sizeof (struct TransportPongMessage) < slen) ||
3922 (ve->challenge != challenge) || (addr[slen - 1] != '\0') ||
3923 (0 != strcmp (addr, ve->transport_name)) ||
3924 (ntohl (pong->purpose.size) !=
3925 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) +
3926 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3927 sizeof (struct GNUNET_PeerIdentity) + ps -
3928 sizeof (struct TransportPongMessage)))
3933 alen = ps - sizeof (struct TransportPongMessage) - slen;
3934 switch (ntohl (pong->purpose.purpose))
3936 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3937 if ((ve->addrlen + slen != ntohl (pong->addrlen)) ||
3938 (0 != memcmp (&addr[slen], ve->addr, ve->addrlen)))
3940 return GNUNET_YES; /* different entry, keep trying! */
3942 if (0 != memcmp (&pong->pid, key, sizeof (struct GNUNET_PeerIdentity)))
3944 GNUNET_break_op (0);
3948 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3949 &pong->purpose, &pong->signature,
3952 GNUNET_break_op (0);
3957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3958 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3959 GNUNET_h2s (key), a2s (ve->transport_name,
3960 (const struct sockaddr *) ve->addr,
3961 ve->addrlen), ve->transport_name);
3964 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3966 memcmp (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
3970 GNUNET_asprintf (&peer, "%s", GNUNET_i2s (&pong->pid));
3972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3973 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
3974 GNUNET_i2s (&my_identity), peer);
3979 if (ve->addrlen != 0)
3981 /* must have been for a different validation entry */
3984 tp = find_transport (ve->transport_name);
3990 oal = tp->addresses;
3993 if ((oal->addrlen == alen) && (0 == memcmp (&oal[1], &addr[slen], alen)))
3999 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4001 ("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4002 GNUNET_i2s (&pong->pid), a2s (ve->transport_name, &addr[slen],
4004 /* FIXME: since the sender of the PONG currently uses the
4005 * wrong address (see FIMXE there!), we cannot run a
4006 * proper check here... */
4012 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4013 &pong->purpose, &pong->signature,
4016 GNUNET_break_op (0);
4021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4022 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4023 GNUNET_h2s (key), a2s (ve->transport_name, &addr[slen], alen),
4024 ve->transport_name);
4028 GNUNET_break_op (0);
4031 if (GNUNET_TIME_absolute_get_remaining
4032 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4034 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4035 _("Received expired signature. Check system time.\n"));
4038 GNUNET_STATISTICS_update (stats,
4039 gettext_noop ("# address validation successes"), 1,
4041 /* create the updated HELLO */
4042 GNUNET_CRYPTO_hash (&ve->publicKey,
4043 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4044 &target.hashPubKey);
4045 if (ve->addr != NULL)
4047 avac.done = GNUNET_NO;
4049 hello = GNUNET_HELLO_create (&ve->publicKey, &add_validated_address, &avac);
4050 GNUNET_PEERINFO_add_peer (peerinfo, hello);
4051 GNUNET_free (hello);
4053 n = find_neighbour (&target);
4056 n->publicKey = ve->publicKey;
4057 n->public_key_valid = GNUNET_YES;
4059 add_peer_address (n, ve->transport_name, ve->session, ve->addr,
4061 GNUNET_assert (fal != NULL);
4062 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4063 fal->validated = GNUNET_YES;
4064 mark_address_connected (fal);
4065 GNUNET_STATISTICS_update (stats,
4067 ("# peer addresses considered valid"), 1,
4069 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4070 update_addr_value (fal,
4071 GNUNET_TIME_absolute_get_duration (ve->
4072 send_time).rel_value,
4073 GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4075 schedule_next_ping (fal);
4076 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4077 n->latency = fal->latency;
4079 n->latency.rel_value =
4080 (fal->latency.rel_value + n->latency.rel_value) / 2;
4082 n->distance = fal->distance;
4083 if (GNUNET_NO == n->received_pong)
4085 n->received_pong = GNUNET_YES;
4086 notify_clients_connect (&target, n->latency, n->distance);
4087 if (NULL != (prem = n->pre_connect_message_buffer))
4089 n->pre_connect_message_buffer = NULL;
4090 handle_payload_message (prem, n);
4094 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4096 GNUNET_SCHEDULER_cancel (n->retry_task);
4097 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4098 try_transmission_to_peer (n);
4102 /* clean up validation entry */
4103 GNUNET_assert (GNUNET_YES ==
4104 GNUNET_CONTAINER_multihashmap_remove (validation_map, key,
4106 abort_validation (NULL, NULL, ve);
4112 * Function that will be called if we receive a validation
4113 * of an address challenge that we transmitted to another
4114 * peer. Note that the validation should only be considered
4115 * acceptable if the challenge matches AND if the sender
4116 * address is at least a plausible address for this peer
4117 * (otherwise we may be seeing a MiM attack).
4119 * @param cls closure
4120 * @param message the pong message
4121 * @param peer who responded to our challenge
4122 * @param sender_address string describing our sender address (as observed
4123 * by the other peer in binary format)
4124 * @param sender_address_len number of bytes in 'sender_address'
4127 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4128 const struct GNUNET_PeerIdentity *peer, const char *sender_address,
4129 size_t sender_address_len)
4131 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4133 /* PONG send to self, ignore */
4134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from myself\n",
4138 #if DEBUG_TRANSPORT > 1
4139 /* we get tons of these that just get discarded, only log
4140 * if we are quite verbose */
4141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from `%4s'.\n",
4142 "PONG", GNUNET_i2s (peer));
4144 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), 1,
4146 if (GNUNET_SYSERR !=
4147 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4149 &check_pending_validation,
4152 /* This is *expected* to happen a lot since we send
4153 * PONGs to *all* known addresses of the sender of
4154 * the PING, so most likely we get multiple PONGs
4155 * per PING, and all but the first PONG will end up
4156 * here. So really we should not print anything here
4157 * unless we want to be very, very verbose... */
4158 #if DEBUG_TRANSPORT > 2
4159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4160 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4161 "PONG", GNUNET_i2s (peer), "PING");
4170 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4172 * @param cls the 'struct ValidationEntry*'
4173 * @param neighbour neighbour to validate, NULL if validation failed
4176 transmit_hello_and_ping (void *cls, struct NeighbourMapEntry *neighbour)
4178 struct ValidationEntry *va = cls;
4179 struct ForeignAddressList *peer_address;
4180 struct TransportPingMessage ping;
4181 uint16_t hello_size;
4184 struct GNUNET_PeerIdentity id;
4187 GNUNET_CRYPTO_hash (&va->publicKey,
4188 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4190 if (neighbour == NULL)
4192 /* FIXME: stats... */
4193 GNUNET_break (GNUNET_OK ==
4194 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4195 &id.hashPubKey, va));
4196 abort_validation (NULL, NULL, va);
4199 neighbour->publicKey = va->publicKey;
4200 neighbour->public_key_valid = GNUNET_YES;
4202 add_peer_address (neighbour, va->transport_name, NULL,
4203 (const void *) &va[1], va->addrlen);
4204 if (peer_address == NULL)
4206 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4207 "Failed to add peer `%4s' for plugin `%s'\n",
4208 GNUNET_i2s (&neighbour->id), va->transport_name);
4209 GNUNET_break (GNUNET_OK ==
4210 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4211 &id.hashPubKey, va));
4212 abort_validation (NULL, NULL, va);
4215 if (NULL == our_hello)
4216 refresh_hello_task (NULL, NULL);
4217 hello_size = GNUNET_HELLO_size (our_hello);
4218 slen = strlen (va->transport_name) + 1;
4220 sizeof (struct TransportPingMessage) + hello_size + va->addrlen + slen;
4221 message_buf = GNUNET_malloc (tsize);
4222 ping.challenge = htonl (va->challenge);
4224 htons (sizeof (struct TransportPingMessage) + slen + va->addrlen);
4225 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4226 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
4227 memcpy (message_buf, our_hello, hello_size);
4228 memcpy (&message_buf[hello_size], &ping,
4229 sizeof (struct TransportPingMessage));
4230 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4231 va->transport_name, slen);
4232 memcpy (&message_buf
4233 [hello_size + sizeof (struct TransportPingMessage) + slen], &va[1],
4236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4237 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4238 (va->addrlen == 0) ? "<inbound>" : a2s (va->transport_name,
4239 (const void *) &va[1],
4241 va->transport_name, GNUNET_i2s (&neighbour->id), "HELLO",
4243 sizeof (struct TransportPingMessage) + va->addrlen + slen);
4246 GNUNET_STATISTICS_update (stats,
4248 ("# PING messages sent for initial validation"), 1,
4250 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4251 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
4253 GNUNET_free (message_buf);
4258 * Check if the given address is already being validated; if not,
4259 * append the given address to the list of entries that are being be
4260 * validated and initiate validation.
4262 * @param cls closure ('struct CheckHelloValidatedContext *')
4263 * @param tname name of the transport
4264 * @param expiration expiration time
4265 * @param addr the address
4266 * @param addrlen length of the address
4267 * @return GNUNET_OK (always)
4270 run_validation (void *cls, const char *tname,
4271 struct GNUNET_TIME_Absolute expiration, const void *addr,
4274 struct CheckHelloValidatedContext *chvc = cls;
4275 struct GNUNET_PeerIdentity id;
4276 struct TransportPlugin *tp;
4277 struct ValidationEntry *va;
4278 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4279 struct CheckAddressExistsClosure caec;
4280 struct OwnAddressList *oal;
4282 GNUNET_assert (addr != NULL);
4284 GNUNET_STATISTICS_update (stats,
4286 ("# peer addresses scheduled for validation"), 1,
4288 tp = find_transport (tname);
4291 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
4293 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4295 GNUNET_STATISTICS_update (stats,
4297 ("# peer addresses not validated (plugin not available)"),
4301 /* check if this is one of our own addresses */
4302 oal = tp->addresses;
4305 if ((oal->addrlen == addrlen) && (0 == memcmp (&oal[1], addr, addrlen)))
4307 /* not plausible, this address is equivalent to our own address! */
4308 GNUNET_STATISTICS_update (stats,
4310 ("# peer addresses not validated (loopback)"),
4316 GNUNET_HELLO_get_key (chvc->hello, &pk);
4317 GNUNET_CRYPTO_hash (&pk,
4318 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4321 if (is_blacklisted (&id, tp))
4324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4325 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4326 GNUNET_i2s (&id), tname);
4332 caec.addrlen = addrlen;
4333 caec.session = NULL;
4335 caec.exists = GNUNET_NO;
4336 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
4338 if (caec.exists == GNUNET_YES)
4340 /* During validation attempts we will likely trigger the other
4341 * peer trying to validate our address which in turn will cause
4342 * it to send us its HELLO, so we expect to hit this case rather
4343 * frequently. Only print something if we are very verbose. */
4344 #if DEBUG_TRANSPORT > 1
4345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4346 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4347 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id));
4349 GNUNET_STATISTICS_update (stats,
4351 ("# peer addresses not validated (in progress)"),
4355 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4358 va->transport_name = GNUNET_strdup (tname);
4360 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
4361 va->send_time = GNUNET_TIME_absolute_get ();
4362 va->addr = (const void *) &va[1];
4363 memcpy (&va[1], addr, addrlen);
4364 va->addrlen = addrlen;
4365 GNUNET_HELLO_get_key (chvc->hello, &va->publicKey);
4367 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4368 &timeout_hello_validation, va);
4369 GNUNET_CONTAINER_multihashmap_put (validation_map, &id.hashPubKey, va,
4370 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4371 setup_peer_check_blacklist (&id, GNUNET_NO, &transmit_hello_and_ping, va);
4377 * Check if addresses in validated hello "h" overlap with
4378 * those in "chvc->hello" and validate the rest.
4380 * @param cls closure
4381 * @param peer id of the peer, NULL for last call
4382 * @param h hello message for the peer (can be NULL)
4383 * @param err_msg NULL if successful, otherwise contains error message
4386 check_hello_validated (void *cls, const struct GNUNET_PeerIdentity *peer,
4387 const struct GNUNET_HELLO_Message *h,
4388 const char *err_msg)
4390 struct CheckHelloValidatedContext *chvc = cls;
4391 struct GNUNET_HELLO_Message *plain_hello;
4392 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4393 struct GNUNET_PeerIdentity target;
4394 struct NeighbourMapEntry *n;
4396 if (err_msg != NULL)
4399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4400 _("Error in communication with PEERINFO service: %s\n"),
4408 GNUNET_STATISTICS_update (stats,
4410 ("# outstanding peerinfo iterate requests"), -1,
4413 if (GNUNET_NO == chvc->hello_known)
4415 /* notify PEERINFO about the peer now, so that we at least
4416 * have the public key if some other component needs it */
4417 GNUNET_HELLO_get_key (chvc->hello, &pk);
4418 GNUNET_CRYPTO_hash (&pk,
4420 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4421 &target.hashPubKey);
4422 plain_hello = GNUNET_HELLO_create (&pk, NULL, NULL);
4423 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4424 GNUNET_free (plain_hello);
4425 #if DEBUG_TRANSPORT_HELLO
4426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4427 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4428 "HELLO", GNUNET_i2s (&target));
4430 GNUNET_STATISTICS_update (stats,
4432 ("# new HELLOs requiring full validation"), 1,
4434 GNUNET_HELLO_iterate_addresses (chvc->hello, GNUNET_NO, &run_validation,
4439 GNUNET_STATISTICS_update (stats,
4440 gettext_noop ("# duplicate HELLO (peer known)"),
4444 if (chvc->ve_count == 0)
4446 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
4453 #if DEBUG_TRANSPORT_HELLO
4454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4455 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4456 "HELLO", GNUNET_i2s (peer));
4458 chvc->hello_known = GNUNET_YES;
4459 n = find_neighbour (peer);
4462 #if DEBUG_TRANSPORT_HELLO
4463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4464 "Calling hello_iterate_addresses for %s!\n", GNUNET_i2s (peer));
4466 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
4468 try_transmission_to_peer (n);
4472 #if DEBUG_TRANSPORT_HELLO
4473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4474 "No existing neighbor record for %s!\n", GNUNET_i2s (peer));
4476 GNUNET_STATISTICS_update (stats,
4478 ("# no existing neighbour record (validating HELLO)"),
4481 GNUNET_STATISTICS_update (stats,
4482 gettext_noop ("# HELLO validations (update case)"),
4484 GNUNET_HELLO_iterate_new_addresses (chvc->hello, h,
4485 GNUNET_TIME_relative_to_absolute
4486 (HELLO_REVALIDATION_START_TIME),
4487 &run_validation, chvc);
4492 * Process HELLO-message.
4494 * @param plugin transport involved, may be NULL
4495 * @param message the actual message
4496 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4499 process_hello (struct TransportPlugin *plugin,
4500 const struct GNUNET_MessageHeader *message)
4503 struct GNUNET_PeerIdentity target;
4504 const struct GNUNET_HELLO_Message *hello;
4505 struct CheckHelloValidatedContext *chvc;
4506 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4507 struct NeighbourMapEntry *n;
4509 #if DEBUG_TRANSPORT_HELLO > 2
4513 hsize = ntohs (message->size);
4514 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4515 (hsize < sizeof (struct GNUNET_MessageHeader)))
4518 return GNUNET_SYSERR;
4520 GNUNET_STATISTICS_update (stats,
4521 gettext_noop ("# HELLOs received for validation"),
4524 hello = (const struct GNUNET_HELLO_Message *) message;
4525 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4527 #if DEBUG_TRANSPORT_HELLO
4528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4529 "Unable to get public key from `%s' for `%4s'!\n", "HELLO",
4530 GNUNET_i2s (&target));
4532 GNUNET_break_op (0);
4533 return GNUNET_SYSERR;
4535 GNUNET_CRYPTO_hash (&publicKey,
4536 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4537 &target.hashPubKey);
4539 #if DEBUG_TRANSPORT_HELLO
4540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for `%4s'\n",
4541 "HELLO", GNUNET_i2s (&target));
4543 if (0 == memcmp (&my_identity, &target, sizeof (struct GNUNET_PeerIdentity)))
4545 GNUNET_STATISTICS_update (stats,
4547 ("# HELLOs ignored for validation (is my own HELLO)"),
4551 n = find_neighbour (&target);
4552 if ((NULL != n) && (!n->public_key_valid))
4554 GNUNET_HELLO_get_key (hello, &n->publicKey);
4555 n->public_key_valid = GNUNET_YES;
4558 /* check if load is too high before doing expensive stuff */
4559 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) >
4562 GNUNET_STATISTICS_update (stats,
4564 ("# HELLOs ignored due to high load"), 1,
4566 #if DEBUG_TRANSPORT_HELLO
4567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4568 "Ignoring `%s' for `%4s', load too high.\n", "HELLO",
4569 GNUNET_i2s (&target));
4576 while (NULL != chvc)
4578 if (GNUNET_HELLO_equals
4579 (hello, chvc->hello, GNUNET_TIME_absolute_get ()).abs_value > 0)
4581 #if DEBUG_TRANSPORT_HELLO > 2
4582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4583 "Received duplicate `%s' message for `%4s'; ignored\n",
4584 "HELLO", GNUNET_i2s (&target));
4586 return GNUNET_OK; /* validation already pending */
4588 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4590 memcmp (hello, chvc->hello, GNUNET_HELLO_size (hello)));
4595 struct NeighbourMapEntry *temp_neighbor = find_neighbour (&target);
4597 if ((NULL != temp_neighbor))
4599 fprintf (stderr, "Already know peer, ignoring hello\n");
4604 #if DEBUG_TRANSPORT_HELLO > 2
4608 my_id = GNUNET_strdup (GNUNET_i2s (plugin->env.my_identity));
4609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4610 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4611 my_id, "HELLO", GNUNET_i2s (&target), plugin->short_name,
4612 GNUNET_HELLO_size (hello));
4613 GNUNET_free (my_id);
4617 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4619 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4620 memcpy (&chvc[1], hello, hsize);
4621 GNUNET_CONTAINER_DLL_insert (chvc_head, chvc_tail, chvc);
4622 /* finally, check if HELLO was previously validated
4623 * (continuation will then schedule actual validation) */
4624 GNUNET_STATISTICS_update (stats,
4626 ("# peerinfo process hello iterate requests"), 1,
4628 GNUNET_STATISTICS_update (stats,
4630 ("# outstanding peerinfo iterate requests"), 1,
4633 GNUNET_PEERINFO_iterate (peerinfo, &target, HELLO_VERIFICATION_TIMEOUT,
4634 &check_hello_validated, chvc);
4640 * The peer specified by the given neighbour has timed-out or a plugin
4641 * has disconnected. We may either need to do nothing (other plugins
4642 * still up), or trigger a full disconnect and clean up. This
4643 * function updates our state and does the necessary notifications.
4644 * Also notifies our clients that the neighbour is now officially
4647 * @param n the neighbour list entry for the peer
4648 * @param check GNUNET_YES to check if ALL addresses for this peer
4649 * are gone, GNUNET_NO to force a disconnect of the peer
4650 * regardless of whether other addresses exist.
4653 disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4655 struct ReadyList *rpos;
4656 struct MessageQueue *mq;
4657 struct ForeignAddressList *peer_addresses;
4658 struct ForeignAddressList *peer_pos;
4660 if (GNUNET_YES == n->in_disconnect)
4662 if (GNUNET_YES == check)
4665 while (NULL != rpos)
4667 peer_addresses = rpos->addresses;
4668 while (peer_addresses != NULL)
4670 /* Do not disconnect if: an address is connected or an inbound address exists */
4671 if ((GNUNET_YES == peer_addresses->connected) ||
4672 (peer_addresses->addrlen == 0))
4675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4676 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4677 GNUNET_i2s (&n->id),
4678 a2s (peer_addresses->ready_list->plugin->short_name,
4679 peer_addresses->addr, peer_addresses->addrlen));
4681 return; /* still connected */
4683 peer_addresses = peer_addresses->next;
4689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4690 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
4692 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4694 /* notify all clients about disconnect */
4695 if (GNUNET_YES == n->received_pong)
4697 n->received_pong = GNUNET_NO;
4698 notify_clients_disconnect (&n->id);
4701 ats_modify_problem_state (ats, ATS_MODIFIED);
4703 /* clean up all plugins, cancel connections and pending transmissions */
4704 while (NULL != (rpos = n->plugins))
4706 n->plugins = rpos->next;
4707 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4708 while (rpos->addresses != NULL)
4710 peer_pos = rpos->addresses;
4711 rpos->addresses = peer_pos->next;
4712 if (peer_pos->connected == GNUNET_YES)
4714 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
4716 peer_pos->connected = GNUNET_NO;
4718 if (GNUNET_YES == peer_pos->validated)
4719 GNUNET_STATISTICS_update (stats,
4721 ("# peer addresses considered valid"), -1,
4723 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4725 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4726 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4728 GNUNET_free (peer_pos->ressources);
4729 peer_pos->ressources = NULL;
4730 GNUNET_free (peer_pos->quality);
4731 peer_pos->ressources = NULL;
4732 GNUNET_free (peer_pos);
4737 /* free all messages on the queue */
4738 while (NULL != (mq = n->messages_head))
4740 GNUNET_STATISTICS_update (stats,
4742 ("# bytes in message queue for other peers"),
4743 -(int64_t) mq->message_buf_size, GNUNET_NO);
4744 GNUNET_STATISTICS_update (stats,
4746 ("# bytes discarded due to disconnect"),
4747 mq->message_buf_size, GNUNET_NO);
4748 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
4750 memcmp (&mq->neighbour_id, &n->id,
4751 sizeof (struct GNUNET_PeerIdentity)));
4755 while (NULL != (mq = n->cont_head))
4758 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
4760 memcmp (&mq->neighbour_id, &n->id,
4761 sizeof (struct GNUNET_PeerIdentity)));
4765 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4767 GNUNET_SCHEDULER_cancel (n->timeout_task);
4768 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4770 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4772 GNUNET_SCHEDULER_cancel (n->retry_task);
4773 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4775 if (n->piter != NULL)
4777 GNUNET_PEERINFO_iterate_cancel (n->piter);
4778 GNUNET_STATISTICS_update (stats,
4780 ("# outstanding peerinfo iterate requests"), -1,
4785 GNUNET_assert (GNUNET_OK ==
4786 GNUNET_CONTAINER_multihashmap_remove (neighbours,
4787 &n->id.hashPubKey, n));
4788 /* finally, free n itself */
4789 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), -1,
4791 GNUNET_free_non_null (n->pre_connect_message_buffer);
4797 * We have received a PING message from someone. Need to send a PONG message
4798 * in response to the peer by any means necessary.
4801 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4802 const struct GNUNET_PeerIdentity *peer, struct Session *session,
4803 const char *sender_address, uint16_t sender_address_len)
4805 struct TransportPlugin *plugin = cls;
4806 struct SessionHeader *session_header = (struct SessionHeader *) session;
4807 struct TransportPingMessage *ping;
4808 struct TransportPongMessage *pong;
4809 struct NeighbourMapEntry *n;
4810 struct ReadyList *rl;
4811 struct ForeignAddressList *fal;
4812 struct OwnAddressList *oal;
4818 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4820 GNUNET_break_op (0);
4821 return GNUNET_SYSERR;
4824 ping = (struct TransportPingMessage *) message;
4826 memcmp (&ping->target, plugin->env.my_identity,
4827 sizeof (struct GNUNET_PeerIdentity)))
4830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4832 ("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4833 "PING", (sender_address != NULL) ? a2s (plugin->short_name,
4834 (const struct sockaddr
4836 sender_address_len) :
4837 "<inbound>", GNUNET_i2s (&ping->target));
4839 return GNUNET_SYSERR;
4842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4843 "Processing `%s' from `%s'\n", "PING",
4844 (sender_address != NULL) ? a2s (plugin->short_name,
4845 (const struct sockaddr *)
4847 sender_address_len) :
4850 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), 1,
4852 addr = (const char *) &ping[1];
4853 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4854 slen = strlen (plugin->short_name) + 1;
4857 /* peer wants to confirm that we have an outbound connection to him */
4858 if (session == NULL)
4860 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4862 ("Refusing to create PONG since I do not have a session with `%s'.\n"),
4864 return GNUNET_SYSERR;
4866 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4867 * 1) it is NULL when we need to have a real value
4868 * 2) it is documented to be the address of the sender (source-IP), where
4869 * what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4873 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4874 a2s (plugin->short_name, sender_address, sender_address_len),
4878 GNUNET_malloc (sizeof (struct TransportPongMessage) +
4879 sender_address_len + slen);
4881 htons (sizeof (struct TransportPongMessage) + sender_address_len +
4883 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4884 pong->purpose.size =
4885 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4886 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4887 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4888 pong->purpose.purpose =
4889 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4890 pong->challenge = ping->challenge;
4891 pong->addrlen = htonl (sender_address_len + slen);
4892 memcpy (&pong->pid, peer, sizeof (struct GNUNET_PeerIdentity));
4893 memcpy (&pong[1], plugin->short_name, slen);
4894 if ((sender_address != NULL) && (sender_address_len > 0))
4895 memcpy (&((char *) &pong[1])[slen], sender_address, sender_address_len);
4896 if (GNUNET_TIME_absolute_get_remaining
4897 (session_header->pong_sig_expires).rel_value <
4898 PONG_SIGNATURE_LIFETIME.rel_value / 4)
4900 /* create / update cached sig */
4902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4903 "Creating PONG signature to indicate active connection.\n");
4905 session_header->pong_sig_expires =
4906 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4908 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4909 GNUNET_assert (GNUNET_OK ==
4910 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4911 &session_header->pong_signature));
4916 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4918 memcpy (&pong->signature, &session_header->pong_signature,
4919 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4925 /* peer wants to confirm that this is one of our addresses */
4928 if (GNUNET_OK != plugin->api->check_address (plugin->api->cls, addr, alen))
4930 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4932 ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4933 a2s (plugin->short_name, addr, alen));
4936 oal = plugin->addresses;
4939 if ((oal->addrlen == alen) && (0 == memcmp (addr, &oal[1], alen)))
4943 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4945 htons (sizeof (struct TransportPongMessage) + alen + slen);
4946 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4947 pong->purpose.size =
4948 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4949 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4950 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4951 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4952 pong->challenge = ping->challenge;
4953 pong->addrlen = htonl (alen + slen);
4954 memcpy (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity));
4955 memcpy (&pong[1], plugin->short_name, slen);
4956 memcpy (&((char *) &pong[1])[slen], addr, alen);
4957 if ((oal != NULL) &&
4958 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value <
4959 PONG_SIGNATURE_LIFETIME.rel_value / 4))
4961 /* create / update cached sig */
4963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4964 "Creating PONG signature to indicate ownership.\n");
4966 oal->pong_sig_expires =
4967 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4968 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4969 GNUNET_assert (GNUNET_OK ==
4970 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4971 &oal->pong_signature));
4972 memcpy (&pong->signature, &oal->pong_signature,
4973 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4975 else if (oal == NULL)
4977 /* not using cache (typically DV-only) */
4979 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
4980 (PONG_SIGNATURE_LIFETIME));
4981 GNUNET_assert (GNUNET_OK ==
4982 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4987 /* can used cached version */
4988 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4989 memcpy (&pong->signature, &oal->pong_signature,
4990 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4993 n = find_neighbour (peer);
4994 GNUNET_assert (n != NULL);
4995 did_pong = GNUNET_NO;
4996 /* first try reliable response transmission */
5000 fal = rl->addresses;
5004 rl->plugin->api->send (rl->plugin->api->cls, peer,
5005 (const char *) pong, ntohs (pong->header.size),
5006 TRANSPORT_PONG_PRIORITY,
5007 HELLO_VERIFICATION_TIMEOUT, fal->session,
5008 fal->addr, fal->addrlen, GNUNET_SYSERR, NULL,
5011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5012 "Transmitted PONG to `%s' via reliable mechanism\n",
5015 GNUNET_STATISTICS_update (stats,
5017 ("# PONGs unicast via reliable transport"), 1,
5022 did_pong = GNUNET_YES;
5027 /* no reliable method found, do multicast */
5028 GNUNET_STATISTICS_update (stats,
5030 ("# PONGs multicast to all available addresses"), 1,
5035 fal = rl->addresses;
5038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5039 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5040 GNUNET_i2s (peer), a2s (rl->plugin->short_name, fal->addr,
5042 rl->plugin->short_name);
5043 transmit_to_peer (NULL, fal, TRANSPORT_PONG_PRIORITY,
5044 HELLO_VERIFICATION_TIMEOUT, (const char *) pong,
5045 ntohs (pong->header.size), GNUNET_YES, n);
5046 did_pong = GNUNET_YES;
5052 if (GNUNET_YES != did_pong)
5053 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5054 _("Could not send PONG to `%s': no address available\n"),
5061 * Function called by the plugin for each received message. Update
5062 * data volumes, possibly notify plugins about reducing the rate at
5063 * which they read from the socket and generally forward to our
5066 * @param cls the "struct TransportPlugin *" we gave to the plugin
5067 * @param peer (claimed) identity of the other peer
5068 * @param message the message, NULL if we only care about
5069 * learning about the delay until we should receive again
5070 * @param ats_data information for automatic transport selection
5071 * @param ats_count number of elements in ats not including 0-terminator
5072 * @param session identifier used for this session (can be NULL)
5073 * @param sender_address binary address of the sender (if observed)
5074 * @param sender_address_len number of bytes in sender_address
5075 * @return how long in ms the plugin should wait until receiving more data
5076 * (plugins that do not support this, can ignore the return value)
5078 static struct GNUNET_TIME_Relative
5079 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5080 const struct GNUNET_MessageHeader *message,
5081 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5082 uint32_t ats_count, struct Session *session,
5083 const char *sender_address, uint16_t sender_address_len)
5085 struct TransportPlugin *plugin = cls;
5086 struct ReadyList *service_context;
5087 struct ForeignAddressList *peer_address;
5089 struct NeighbourMapEntry *n;
5090 struct GNUNET_TIME_Relative ret;
5094 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
5096 /* refuse to receive from myself */
5098 return GNUNET_TIME_UNIT_FOREVER_REL;
5100 if (is_blacklisted (peer, plugin))
5101 return GNUNET_TIME_UNIT_FOREVER_REL;
5102 n = find_neighbour (peer);
5104 n = setup_new_neighbour (peer, GNUNET_YES);
5105 service_context = n->plugins;
5106 while ((service_context != NULL) && (plugin != service_context->plugin))
5107 service_context = service_context->next;
5108 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5109 peer_address = NULL;
5112 for (c = 0; c < ats_count; c++)
5113 if (ntohl (ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5114 distance = ntohl (ats_data[c].value);
5117 if (message != NULL)
5119 if ((session != NULL) || (sender_address != NULL))
5121 add_peer_address (n, plugin->short_name, session, sender_address,
5122 sender_address_len);
5123 if (peer_address != NULL)
5125 update_addr_ats (peer_address, ats_data, ats_count);
5126 update_addr_value (peer_address, distance,
5127 GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5129 peer_address->distance = distance;
5130 if (GNUNET_YES == peer_address->validated)
5132 mark_address_connected (peer_address);
5133 schedule_next_ping (peer_address);
5138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5139 "New address is unvalidated, trying to validate it now\n");
5141 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5143 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5144 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5146 peer_address->revalidate_task =
5147 GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5150 peer_address->timeout =
5151 GNUNET_TIME_relative_to_absolute
5152 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5154 /* update traffic received amount ... */
5155 msize = ntohs (message->size);
5157 GNUNET_STATISTICS_update (stats,
5159 ("# bytes received from other peers"), msize,
5161 n->distance = distance;
5163 GNUNET_TIME_relative_to_absolute
5164 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5165 GNUNET_SCHEDULER_cancel (n->timeout_task);
5167 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5168 &neighbour_timeout_task, n);
5169 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5171 /* dropping message due to frequent inbound volume violations! */
5172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
5174 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5175 n->in_tracker.available_bytes_per_s__,
5176 n->quota_violation_count);
5177 GNUNET_STATISTICS_update (stats,
5179 ("# bandwidth quota violations by other peers"),
5181 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5183 if ((ntohs (message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5184 (ntohs (message->size) ==
5185 (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5188 uint32_t value = ntohl (*((uint32_t *) & message[1]));
5190 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5191 /* Force ressource and quality update */
5192 if ((value == 4) && (ats != NULL))
5193 ats_modify_problem_state (ats, ATS_QUALITY_COST_UPDATED);
5194 /* Force cost update */
5195 if ((value == 3) && (ats != NULL))
5196 ats_modify_problem_state (ats, ATS_COST_UPDATED);
5197 /* Force quality update */
5198 if ((value == 2) && (ats != NULL))
5199 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
5200 /* Force full rebuild */
5201 if ((value == 1) && (ats != NULL))
5202 ats_modify_problem_state (ats, ATS_MODIFIED);
5207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5208 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5209 ntohs (message->type), ntohs (message->size),
5212 switch (ntohs (message->type))
5214 case GNUNET_MESSAGE_TYPE_HELLO:
5215 GNUNET_STATISTICS_update (stats,
5217 ("# HELLO messages received from other peers"),
5219 process_hello (plugin, message);
5221 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5222 handle_ping (plugin, message, peer, session, sender_address,
5223 sender_address_len);
5224 if (GNUNET_YES != n->received_pong)
5225 transmit_plain_ping (n);
5227 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5228 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5230 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5233 handle_payload_message (message, n);
5237 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5238 if (ret.rel_value > 0)
5241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5242 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5243 (unsigned long long) n->
5244 in_tracker.consumption_since_last_update__,
5245 (unsigned int) n->in_tracker.available_bytes_per_s__,
5246 (unsigned long long) ret.rel_value);
5248 GNUNET_STATISTICS_update (stats, gettext_noop ("# ms throttling suggested"),
5249 (int64_t) ret.rel_value, GNUNET_NO);
5256 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
5259 struct TransportClient *c = cls;
5260 struct NeighbourMapEntry *n = value;
5261 struct ConnectInfoMessage *cim;
5265 if (GNUNET_YES != n->received_pong)
5270 sizeof (struct ConnectInfoMessage) +
5271 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5272 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5273 cim = GNUNET_malloc (size);
5274 cim->header.size = htons (size);
5275 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5276 cim->ats_count = htonl (ats_count);
5277 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5278 (&(cim->ats))[2].value = htonl (0);
5279 if (GNUNET_YES == n->received_pong)
5281 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5282 (&cim->ats)[0].value = htonl (n->distance);
5283 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5284 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5286 transmit_to_client (c, &cim->header, GNUNET_NO);
5294 * Handle START-message. This is the first message sent to us
5295 * by any client which causes us to add it to our list.
5297 * @param cls closure (always NULL)
5298 * @param client identification of the client
5299 * @param message the actual message
5302 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
5303 const struct GNUNET_MessageHeader *message)
5305 const struct StartMessage *start;
5306 struct TransportClient *c;
5308 start = (const struct StartMessage *) message;
5310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n",
5316 if (c->client == client)
5318 /* client already on our list! */
5320 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5325 if ((GNUNET_NO != ntohl (start->do_check)) &&
5327 memcmp (&start->self, &my_identity,
5328 sizeof (struct GNUNET_PeerIdentity))))
5330 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5332 ("Rejecting control connection from peer `%s', which is not me!\n"),
5333 GNUNET_i2s (&start->self));
5334 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5337 c = GNUNET_malloc (sizeof (struct TransportClient));
5341 if (our_hello != NULL)
5344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending our own `%s' to new client\n",
5347 transmit_to_client (c, (const struct GNUNET_MessageHeader *) our_hello,
5349 /* tell new client about all existing connections */
5350 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5351 ¬ify_client_about_neighbour, c);
5355 #if DEBUG_TRANSPORT_HELLO
5356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5357 "No HELLO created yet, will transmit HELLO to client later!\n");
5361 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5366 * Handle HELLO-message.
5368 * @param cls closure (always NULL)
5369 * @param client identification of the client
5370 * @param message the actual message
5373 handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
5374 const struct GNUNET_MessageHeader *message)
5378 GNUNET_STATISTICS_update (stats,
5379 gettext_noop ("# HELLOs received from clients"), 1,
5381 ret = process_hello (NULL, message);
5382 GNUNET_SERVER_receive_done (client, ret);
5387 * Closure for 'transmit_client_message'; followed by
5388 * 'msize' bytes of the actual message.
5390 struct TransmitClientMessageContext
5393 * Client on whom's behalf we are sending.
5395 struct GNUNET_SERVER_Client *client;
5398 * Timeout for the transmission.
5400 struct GNUNET_TIME_Absolute timeout;
5408 * Size of the message in bytes.
5415 * Schedule transmission of a message we got from a client to a peer.
5417 * @param cls the 'struct TransmitClientMessageContext*'
5418 * @param n destination, or NULL on error (in that case, drop the message)
5421 transmit_client_message (void *cls, struct NeighbourMapEntry *n)
5423 struct TransmitClientMessageContext *tcmc = cls;
5424 struct TransportClient *tc;
5427 while ((tc != NULL) && (tc->client != tcmc->client))
5432 transmit_to_peer (tc, NULL, tcmc->priority,
5433 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5434 (char *) &tcmc[1], tcmc->msize, GNUNET_NO, n);
5436 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5437 GNUNET_SERVER_client_drop (tcmc->client);
5443 * Handle SEND-message.
5445 * @param cls closure (always NULL)
5446 * @param client identification of the client
5447 * @param message the actual message
5450 handle_send (void *cls, struct GNUNET_SERVER_Client *client,
5451 const struct GNUNET_MessageHeader *message)
5453 const struct OutboundMessage *obm;
5454 const struct GNUNET_MessageHeader *obmm;
5455 struct TransmitClientMessageContext *tcmc;
5459 size = ntohs (message->size);
5461 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5464 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5467 GNUNET_STATISTICS_update (stats,
5468 gettext_noop ("# payload received for other peers"),
5470 obm = (const struct OutboundMessage *) message;
5471 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5472 msize = size - sizeof (struct OutboundMessage);
5474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5475 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5476 "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
5478 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5479 tcmc->client = client;
5480 tcmc->priority = ntohl (obm->priority);
5482 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh
5484 tcmc->msize = msize;
5485 /* FIXME: this memcpy can be up to 7% of our total runtime */
5486 memcpy (&tcmc[1], obmm, msize);
5487 GNUNET_SERVER_client_keep (client);
5488 setup_peer_check_blacklist (&obm->peer, GNUNET_YES, &transmit_client_message,
5494 * Handle request connect message
5496 * @param cls closure (always NULL)
5497 * @param client identification of the client
5498 * @param message the actual message
5501 handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
5502 const struct GNUNET_MessageHeader *message)
5504 const struct TransportRequestConnectMessage *trcm =
5505 (const struct TransportRequestConnectMessage *) message;
5507 GNUNET_STATISTICS_update (stats,
5509 ("# REQUEST CONNECT messages received"), 1,
5512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5513 "Received a request connect message for peer `%s'\n",
5514 GNUNET_i2s (&trcm->peer));
5516 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES, NULL, NULL);
5517 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5522 * Handle SET_QUOTA-message.
5524 * @param cls closure (always NULL)
5525 * @param client identification of the client
5526 * @param message the actual message
5529 handle_set_quota (void *cls, struct GNUNET_SERVER_Client *client,
5530 const struct GNUNET_MessageHeader *message)
5532 const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message;
5533 struct NeighbourMapEntry *n;
5535 GNUNET_STATISTICS_update (stats,
5536 gettext_noop ("# SET QUOTA messages received"), 1,
5538 n = find_neighbour (&qsm->peer);
5541 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5542 GNUNET_STATISTICS_update (stats,
5544 ("# SET QUOTA messages ignored (no such peer)"),
5549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5550 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5551 "SET_QUOTA", (unsigned int) ntohl (qsm->quota.value__),
5552 (unsigned int) n->in_tracker.available_bytes_per_s__,
5553 GNUNET_i2s (&qsm->peer));
5555 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, qsm->quota);
5556 if (0 == ntohl (qsm->quota.value__))
5559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
5560 GNUNET_i2s (&n->id), "SET_QUOTA");
5562 GNUNET_STATISTICS_update (stats,
5563 gettext_noop ("# disconnects due to quota of 0"),
5565 disconnect_neighbour (n, GNUNET_NO);
5567 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5572 * Take the given address and append it to the set of results sent back to
5575 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5576 * @param address the resolved name, NULL to indicate the last response
5579 transmit_address_to_client (void *cls, const char *address)
5581 struct GNUNET_SERVER_TransmitContext *tc = cls;
5584 if (NULL != address)
5586 slen = strlen (address) + 1;
5587 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5588 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5592 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5593 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5594 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5600 * Handle AddressLookup-message.
5602 * @param cls closure (always NULL)
5603 * @param client identification of the client
5604 * @param message the actual message
5607 handle_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5608 const struct GNUNET_MessageHeader *message)
5610 const struct AddressLookupMessage *alum;
5611 struct TransportPlugin *lsPlugin;
5612 const char *nameTransport;
5613 const char *address;
5615 struct GNUNET_SERVER_TransmitContext *tc;
5616 struct GNUNET_TIME_Relative rtimeout;
5619 size = ntohs (message->size);
5620 if (size < sizeof (struct AddressLookupMessage))
5622 GNUNET_break_op (0);
5623 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5626 alum = (const struct AddressLookupMessage *) message;
5627 uint32_t addressLen = ntohl (alum->addrlen);
5629 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5631 GNUNET_break_op (0);
5632 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5635 address = (const char *) &alum[1];
5636 nameTransport = (const char *) &address[addressLen];
5638 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5640 GNUNET_break_op (0);
5641 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5644 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5645 numeric = ntohl (alum->numeric_only);
5646 lsPlugin = find_transport (nameTransport);
5647 if (NULL == lsPlugin)
5649 tc = GNUNET_SERVER_transmit_context_create (client);
5650 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5651 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5652 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5655 GNUNET_SERVER_disable_receive_done_warning (client);
5656 tc = GNUNET_SERVER_transmit_context_create (client);
5657 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls, nameTransport,
5658 address, addressLen, numeric, rtimeout,
5659 &transmit_address_to_client, tc);
5663 * Handle PeerAddressLookupMessage.
5665 * @param cls closure (always NULL)
5666 * @param client identification of the client
5667 * @param message the actual message
5670 handle_peer_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5671 const struct GNUNET_MessageHeader *message)
5673 const struct PeerAddressLookupMessage *peer_address_lookup;
5674 struct NeighbourMapEntry *neighbor_iterator;
5675 struct ReadyList *ready_iterator;
5676 struct ForeignAddressList *foreign_address_iterator;
5677 struct TransportPlugin *transport_plugin;
5680 struct GNUNET_SERVER_TransmitContext *tc;
5681 struct GNUNET_TIME_Relative rtimeout;
5684 size = ntohs (message->size);
5685 if (size < sizeof (struct PeerAddressLookupMessage))
5687 GNUNET_break_op (0);
5688 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5691 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5693 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5695 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5697 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5698 if (neighbor_iterator == NULL)
5701 tc = GNUNET_SERVER_transmit_context_create (client);
5702 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5703 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5704 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5708 ready_iterator = neighbor_iterator->plugins;
5709 GNUNET_SERVER_disable_receive_done_warning (client);
5710 tc = GNUNET_SERVER_transmit_context_create (client);
5711 while (ready_iterator != NULL)
5713 foreign_address_iterator = ready_iterator->addresses;
5714 while (foreign_address_iterator != NULL)
5716 transport_plugin = foreign_address_iterator->ready_list->plugin;
5717 if (foreign_address_iterator->addr != NULL)
5719 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
5720 a2s (transport_plugin->short_name,
5721 foreign_address_iterator->addr,
5722 foreign_address_iterator->addrlen),
5723 (foreign_address_iterator->connected ==
5724 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5725 (foreign_address_iterator->validated ==
5726 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5727 transmit_address_to_client (tc, addr_buf);
5728 GNUNET_free (addr_buf);
5730 else if (foreign_address_iterator->addrlen == 0)
5732 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5733 (foreign_address_iterator->connected ==
5734 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5735 (foreign_address_iterator->validated ==
5736 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5737 transmit_address_to_client (tc, addr_buf);
5738 GNUNET_free (addr_buf);
5741 foreign_address_iterator = foreign_address_iterator->next;
5743 ready_iterator = ready_iterator->next;
5745 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5746 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5747 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5753 output_addresses (void *cls, const GNUNET_HashCode * key, void *value)
5755 struct GNUNET_SERVER_TransmitContext *tc = cls;
5756 struct NeighbourMapEntry *neighbor_iterator = value;
5757 struct ForeignAddressList *foreign_address_iterator;
5758 struct TransportPlugin *transport_plugin;
5759 struct ReadyList *ready_iterator;
5762 ready_iterator = neighbor_iterator->plugins;
5763 while (ready_iterator != NULL)
5765 foreign_address_iterator = ready_iterator->addresses;
5766 while (foreign_address_iterator != NULL)
5768 transport_plugin = foreign_address_iterator->ready_list->plugin;
5769 if (foreign_address_iterator->addr != NULL)
5771 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5772 GNUNET_i2s (&neighbor_iterator->id),
5773 a2s (transport_plugin->short_name,
5774 foreign_address_iterator->addr,
5775 foreign_address_iterator->addrlen),
5776 (foreign_address_iterator->connected ==
5777 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5778 (foreign_address_iterator->validated ==
5779 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5780 transmit_address_to_client (tc, addr_buf);
5781 GNUNET_free (addr_buf);
5783 else if (foreign_address_iterator->addrlen == 0)
5785 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5786 GNUNET_i2s (&neighbor_iterator->id), "<inbound>",
5787 (foreign_address_iterator->connected ==
5788 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5789 (foreign_address_iterator->validated ==
5790 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5791 transmit_address_to_client (tc, addr_buf);
5792 GNUNET_free (addr_buf);
5795 foreign_address_iterator = foreign_address_iterator->next;
5797 ready_iterator = ready_iterator->next;
5804 * Handle AddressIterateMessage
5806 * @param cls closure (always NULL)
5807 * @param client identification of the client
5808 * @param message the actual message
5811 handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
5812 const struct GNUNET_MessageHeader *message)
5814 struct GNUNET_SERVER_TransmitContext *tc;
5817 size = ntohs (message->size);
5818 if (size < sizeof (struct AddressIterateMessage))
5820 GNUNET_break_op (0);
5821 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5824 GNUNET_SERVER_disable_receive_done_warning (client);
5825 tc = GNUNET_SERVER_transmit_context_create (client);
5826 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &output_addresses, tc);
5827 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5828 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5829 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5833 static const struct GNUNET_MessageHeader *
5836 return (const struct GNUNET_MessageHeader *) our_hello;
5841 * Setup the environment for this plugin.
5844 create_environment (struct TransportPlugin *plug)
5846 plug->env.cfg = cfg;
5847 plug->env.my_identity = &my_identity;
5848 plug->env.get_our_hello = &do_get_our_hello;
5849 plug->env.cls = plug;
5850 plug->env.receive = &plugin_env_receive;
5851 plug->env.notify_address = &plugin_env_notify_address;
5852 plug->env.session_end = &plugin_env_session_end;
5853 plug->env.max_connections = max_connect_per_transport;
5854 plug->env.stats = stats;
5859 * Start the specified transport (load the plugin).
5862 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
5864 struct TransportPlugin *plug;
5867 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
5869 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5870 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5871 create_environment (plug);
5872 plug->short_name = GNUNET_strdup (name);
5873 plug->lib_name = libname;
5874 plug->next = plugins;
5876 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5877 if (plug->api == NULL)
5879 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5880 _("Failed to load transport plugin for `%s'\n"), name);
5881 GNUNET_free (plug->short_name);
5882 plugins = plug->next;
5883 GNUNET_free (libname);
5890 null_mq_client_pointers (void *cls, const GNUNET_HashCode * key, void *value)
5892 struct TransportClient *pos = cls;
5893 struct NeighbourMapEntry *n = value;
5894 struct MessageQueue *mq;
5896 for (mq = n->messages_head; mq != NULL; mq = mq->next)
5898 if (mq->client == pos)
5899 mq->client = NULL; /* do not use anymore! */
5906 * Called whenever a client is disconnected. Frees our
5907 * resources associated with that client.
5909 * @param cls closure
5910 * @param client identification of the client
5913 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
5915 struct TransportClient *pos;
5916 struct TransportClient *prev;
5917 struct ClientMessageQueueEntry *mqe;
5918 struct Blacklisters *bl;
5919 struct BlacklistCheck *bc;
5924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5925 "Client disconnected, cleaning up.\n");
5927 /* clean up blacklister */
5931 if (bl->client == client)
5936 if (bc->bl_pos == bl)
5938 bc->bl_pos = bl->next;
5941 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5944 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5945 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
5950 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
5951 GNUNET_SERVER_client_drop (bl->client);
5957 /* clean up 'normal' clients */
5960 while ((pos != NULL) && (pos->client != client))
5967 while (NULL != (mqe = pos->message_queue_head))
5969 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5970 pos->message_queue_tail, mqe);
5971 pos->message_count--;
5974 if (NULL != neighbours)
5975 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &null_mq_client_pointers,
5978 clients = pos->next;
5980 prev->next = pos->next;
5981 if (GNUNET_YES == pos->tcs_pending)
5986 if (pos->th != NULL)
5988 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5991 GNUNET_break (0 == pos->message_count);
5997 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
5999 struct NeighbourMapEntry *n = value;
6002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
6003 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
6005 disconnect_neighbour (n, GNUNET_NO);
6011 * Function called when the service shuts down. Unloads our plugins
6012 * and cancels pending validations.
6014 * @param cls closure, unused
6015 * @param tc task context (unused)
6018 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6020 struct TransportPlugin *plug;
6021 struct OwnAddressList *al;
6022 struct CheckHelloValidatedContext *chvc;
6024 shutdown_in_progress = GNUNET_YES;
6025 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
6028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6029 "Transport service is unloading plugins...\n");
6031 while (NULL != (plug = plugins))
6033 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6035 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6036 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6038 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6039 GNUNET_free (plug->lib_name);
6040 GNUNET_free (plug->short_name);
6041 while (NULL != (al = plug->addresses))
6043 plug->addresses = al->next;
6046 plugins = plug->next;
6049 if (my_private_key != NULL)
6050 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6051 GNUNET_free_non_null (our_hello);
6053 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &abort_validation,
6055 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6056 validation_map = NULL;
6059 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6061 GNUNET_SCHEDULER_cancel (ats_task);
6062 ats_task = GNUNET_SCHEDULER_NO_TASK;
6069 /* free 'chvc' data structure */
6070 while (NULL != (chvc = chvc_head))
6072 chvc_head = chvc->next;
6073 if (chvc->piter != NULL)
6075 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6076 GNUNET_STATISTICS_update (stats,
6078 ("# outstanding peerinfo iterate requests"), -1,
6084 GNUNET_assert (chvc->ve_count == 0);
6091 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6094 if (peerinfo != NULL)
6096 GNUNET_PEERINFO_disconnect (peerinfo);
6099 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6101 GNUNET_SCHEDULER_cancel (hello_task);
6102 hello_task = GNUNET_SCHEDULER_NO_TASK;
6104 /* Can we assume those are gone by now, or do we need to clean up
6106 GNUNET_break (bl_head == NULL);
6107 GNUNET_break (bc_head == NULL);
6108 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS Result callback\n");
6121 struct AtsBuildContext
6123 struct ATS_mechanism *mechanisms;
6124 struct ATS_peer *peers;
6131 find_and_count_addresses (void *cls, const GNUNET_HashCode * key, void *value)
6133 struct AtsBuildContext *abc = cls;
6134 struct NeighbourMapEntry *next = value;
6135 int found_addresses = GNUNET_NO;
6137 struct ReadyList *r_next = next->plugins;
6139 while (r_next != NULL)
6141 struct ForeignAddressList *a_next = r_next->addresses;
6143 while (a_next != NULL)
6146 found_addresses = GNUNET_YES;
6147 a_next = a_next->next;
6149 r_next = r_next->next;
6151 if (found_addresses)
6158 setup_ats_problem (void *cls, const GNUNET_HashCode * key, void *value)
6160 struct AtsBuildContext *abc = cls;
6161 struct NeighbourMapEntry *next = value;
6163 int found_addresses = GNUNET_NO;
6164 struct ReadyList *r_next = next->plugins;
6166 while (r_next != NULL)
6168 struct ForeignAddressList *a_next = r_next->addresses;
6170 while (a_next != NULL)
6172 if (found_addresses == GNUNET_NO)
6174 abc->peers[abc->c_peers].peer = next->id;
6175 abc->peers[abc->c_peers].m_head = NULL;
6176 abc->peers[abc->c_peers].m_tail = NULL;
6177 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6179 abc->mechanisms[abc->c_mechs].addr = a_next;
6180 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6181 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6182 abc->mechanisms[abc->c_mechs].next = NULL;
6183 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6184 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6185 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6186 GNUNET_CONTAINER_DLL_insert_tail (abc->peers[abc->c_peers].m_head,
6187 abc->peers[abc->c_peers].m_tail,
6188 &abc->mechanisms[abc->c_mechs]);
6189 found_addresses = GNUNET_YES;
6191 a_next = a_next->next;
6193 r_next = r_next->next;
6195 if (found_addresses == GNUNET_YES)
6202 create_ats_information (struct ATS_peer **p, int *c_p, struct ATS_mechanism **m,
6205 struct AtsBuildContext abc;
6208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6209 "ATS requires clean address information\n");
6213 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &find_and_count_addresses,
6216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6217 "Found %u peers with % u transport mechanisms\n", c_peers,
6221 if ((abc.c_peers == 0) && (abc.c_mechs == 0))
6231 GNUNET_malloc ((1 + abc.c_mechs) * sizeof (struct ATS_mechanism));
6232 abc.peers = GNUNET_malloc ((1 + abc.c_peers) * sizeof (struct ATS_peer));
6235 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &setup_ats_problem, &abc);
6238 (*c_m) = abc.c_mechs;
6239 (*c_p) = abc.c_peers;
6241 (*m) = abc.mechanisms;
6246 schedule_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6248 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6253 ats_task = GNUNET_SCHEDULER_NO_TASK;
6254 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6257 if (shutdown_in_progress == GNUNET_YES)
6260 struct GNUNET_TIME_Relative delta =
6261 GNUNET_TIME_absolute_get_difference (last_ats_execution,
6262 GNUNET_TIME_absolute_get ());
6264 if (delta.rel_value < ats_minimum_interval.rel_value)
6267 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6268 "Minimum time between cycles not reached\n");
6274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6277 ats_calculate_bandwidth_distribution (ats);
6279 last_ats_execution = GNUNET_TIME_absolute_get ();
6282 GNUNET_SCHEDULER_add_delayed (ats_regular_interval, &schedule_ats, ats);
6287 struct ForeignAddressList *
6288 get_preferred_ats_address (struct NeighbourMapEntry *n)
6290 // TODO get ATS prefered address
6291 return find_ready_address (n);
6295 * Initiate transport service.
6297 * @param cls closure
6298 * @param server the initialized server
6299 * @param c configuration to use
6302 run (void *cls, struct GNUNET_SERVER_Handle *server,
6303 const struct GNUNET_CONFIGURATION_Handle *c)
6305 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6306 {&handle_start, NULL,
6307 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6308 {&handle_hello, NULL,
6309 GNUNET_MESSAGE_TYPE_HELLO, 0},
6310 {&handle_send, NULL,
6311 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6312 {&handle_request_connect, NULL,
6313 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
6314 sizeof (struct TransportRequestConnectMessage)},
6315 {&handle_set_quota, NULL,
6316 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6317 {&handle_address_lookup, NULL,
6318 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6320 {&handle_peer_address_lookup, NULL,
6321 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6323 {&handle_address_iterate, NULL,
6324 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6326 {&handle_blacklist_init, NULL,
6327 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
6328 sizeof (struct GNUNET_MessageHeader)},
6329 {&handle_blacklist_reply, NULL,
6330 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
6331 sizeof (struct BlacklistMessage)},
6337 unsigned long long tneigh;
6340 shutdown_in_progress = GNUNET_NO;
6342 stats = GNUNET_STATISTICS_create ("transport", cfg);
6343 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6344 neighbours = GNUNET_CONTAINER_multihashmap_create (256);
6345 /* parse configuration */
6347 GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT", "NEIGHBOUR_LIMIT",
6350 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
6353 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6355 ("Transport service is lacking key configuration settings. Exiting.\n"));
6356 GNUNET_SCHEDULER_shutdown ();
6359 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6362 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6363 validation_map = NULL;
6364 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6369 max_connect_per_transport = (uint32_t) tneigh;
6370 peerinfo = GNUNET_PEERINFO_connect (cfg);
6371 if (peerinfo == NULL)
6373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6374 _("Could not access PEERINFO service. Exiting.\n"));
6375 GNUNET_SCHEDULER_shutdown ();
6378 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6381 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6382 validation_map = NULL;
6383 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6385 GNUNET_free (keyfile);
6388 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6389 GNUNET_free (keyfile);
6390 if (my_private_key == NULL)
6392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6393 _("Transport service could not access hostkey. Exiting.\n"));
6394 GNUNET_SCHEDULER_shutdown ();
6397 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6400 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6401 validation_map = NULL;
6402 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6406 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6407 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
6408 &my_identity.hashPubKey);
6409 /* setup notification */
6410 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
6412 /* load plugins... */
6415 GNUNET_CONFIGURATION_get_value_string (c, "TRANSPORT", "PLUGINS", &plugs))
6417 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
6419 pos = strtok (plugs, " ");
6422 start_transport (server, pos);
6424 pos = strtok (NULL, " ");
6426 GNUNET_free (plugs);
6428 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
6433 /* Initializing ATS */
6436 unsigned long long value;
6442 int v_b_min = 64000;
6446 ats_minimum_interval = ATS_MIN_INTERVAL;
6447 ats_regular_interval = ATS_EXEC_INTERVAL;
6449 /* loading cost ressources */
6450 for (co = 0; co < available_ressources; co++)
6452 GNUNET_asprintf (§ion, "%s_UP", ressources[co].cfg_param);
6453 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6456 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6460 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6461 "Found ressource cost: [%s] = %llu\n", section, value);
6463 ressources[co].c_max = value;
6466 GNUNET_free (section);
6467 GNUNET_asprintf (§ion, "%s_DOWN", ressources[co].cfg_param);
6468 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6471 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6475 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6476 "Found ressource cost: [%s] = %llu\n", section, value);
6478 ressources[co].c_min = value;
6481 GNUNET_free (section);
6485 ats_init (D, U, R, v_b_min, v_n_min, ATS_MAX_ITERATIONS,
6486 ATS_MAX_EXEC_DURATION, &create_ats_information, ats_result_cb);
6487 ats_set_logging_options (ats, stats, cfg);
6488 GNUNET_break (GNUNET_OK ==
6489 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6490 "ATS_EXEC_INTERVAL",
6491 &ats_regular_interval));
6492 GNUNET_break (GNUNET_OK ==
6493 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6495 &ats_minimum_interval));
6497 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6502 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6504 /* If we have a blacklist file, read from it */
6505 read_blacklist_file (cfg);
6506 /* process client requests */
6507 GNUNET_SERVER_add_handlers (server, handlers);
6512 * The main function for the transport service.
6514 * @param argc number of arguments from the command line
6515 * @param argv command line arguments
6516 * @return 0 ok, 1 on error
6519 main (int argc, char *const *argv)
6521 a2s (NULL, NULL, 0); /* make compiler happy */
6522 return (GNUNET_OK ==
6523 GNUNET_SERVICE_run (argc, argv, "transport",
6524 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
6527 /* end of gnunet-service-transport.c */