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 "transport.h"
45 #define DEBUG_BLACKLIST GNUNET_YES
47 #define DEBUG_PING_PONG GNUNET_YES
49 #define DEBUG_TRANSPORT_HELLO GNUNET_YES
52 #define DEBUG_ATS GNUNET_YES
55 #define DEBUG_ATS GNUNET_YES
59 * Should we do some additional checks (to validate behavior
62 #define EXTRA_CHECKS GNUNET_YES
65 * How many messages can we have pending for a given client process
66 * before we start to drop incoming messages? We typically should
67 * have only one client and so this would be the primary buffer for
68 * messages, so the number should be chosen rather generously.
70 * The expectation here is that most of the time the queue is large
71 * enough so that a drop is virtually never required. Note that
72 * this value must be about as large as 'TOTAL_MSGS' in the
73 * 'test_transport_api_reliability.c', otherwise that testcase may
76 #define MAX_PENDING (128 * 1024)
79 * Size of the per-transport blacklist hash maps.
81 #define TRANSPORT_BLACKLIST_HT_SIZE 16
84 * How often should we try to reconnect to a peer using a particular
85 * transport plugin before giving up? Note that the plugin may be
86 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
88 #define MAX_CONNECT_RETRY 3
91 * Limit on the number of ready-to-run tasks when validating
92 * HELLOs. If more tasks are ready to run, we will drop
93 * HELLOs instead of validating them.
95 #define MAX_HELLO_LOAD 4
98 * How often must a peer violate bandwidth quotas before we start
99 * to simply drop its messages?
101 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
104 * How long until a HELLO verification attempt should time out?
105 * Must be rather small, otherwise a partially successful HELLO
106 * validation (some addresses working) might not be available
107 * before a client's request for a connection fails for good.
108 * Besides, if a single request to an address takes a long time,
109 * then the peer is unlikely worthwhile anyway.
111 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
114 * How long is a PONG signature valid? We'll recycle a signature until
115 * 1/4 of this time is remaining. PONGs should expire so that if our
116 * external addresses change an adversary cannot replay them indefinitely.
117 * OTOH, we don't want to spend too much time generating PONG signatures,
118 * so they must have some lifetime to reduce our CPU usage.
120 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
123 * Priority to use for PONG messages.
125 #define TRANSPORT_PONG_PRIORITY 4
128 * How often do we re-add (cheaper) plugins to our list of plugins
129 * to try for a given connected peer?
131 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
134 * After how long do we expire an address in a HELLO that we just
135 * validated? This value is also used for our own addresses when we
138 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
142 * How long before an existing address expires should we again try to
143 * validate it? Must be (significantly) smaller than
144 * HELLO_ADDRESS_EXPIRATION.
146 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
149 * Maximum frequency for re-evaluating latencies for all transport addresses.
151 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
154 * Maximum frequency for re-evaluating latencies for connected addresses.
156 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
160 * List of addresses of other peers
162 struct ForeignAddressList
165 * This is a linked list.
167 struct ForeignAddressList *next;
170 * Which ready list does this entry belong to.
172 struct ReadyList *ready_list;
175 * How long until we auto-expire this address (unless it is
176 * re-confirmed by the transport)?
178 struct GNUNET_TIME_Absolute expires;
181 * Task used to re-validate addresses, updates latencies and
184 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
192 * Session (or NULL if no valid session currently exists or if the
193 * plugin does not use sessions).
195 struct Session *session;
198 * What was the last latency observed for this address, plugin and peer?
200 struct GNUNET_TIME_Relative latency;
203 * If we did not successfully transmit a message to the given peer
204 * via this connection during the specified time, we should consider
205 * the connection to be dead. This is used in the case that a TCP
206 * transport simply stalls writing to the stream but does not
207 * formerly get a signal that the other peer died.
209 struct GNUNET_TIME_Absolute timeout;
212 * How often have we tried to connect using this plugin? Used to
213 * discriminate against addresses that do not work well.
214 * FIXME: not yet used, but should be!
216 unsigned int connect_attempts;
219 * DV distance to this peer (1 if no DV is used).
220 * FIXME: need to set this from transport plugins!
230 * Have we ever estimated the latency of this address? Used to
231 * ensure that the first time we add an address, we immediately
237 * Are we currently connected via this address? The first time we
238 * successfully transmit or receive data to a peer via a particular
239 * address, we set this to GNUNET_YES. If we later get an error
240 * (disconnect notification, transmission failure, timeout), we set
241 * it back to GNUNET_NO.
246 * Is this plugin currently busy transmitting to the specific target?
247 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
248 * messages do not count as 'in transmit'.
253 * Has this address been validated yet?
261 * Entry in linked list of network addresses for ourselves. Also
262 * includes a cached signature for 'struct TransportPongMessage's.
264 struct OwnAddressList
267 * This is a linked list.
269 struct OwnAddressList *next;
272 * How long until we actually auto-expire this address (unless it is
273 * re-confirmed by the transport)?
275 struct GNUNET_TIME_Absolute expires;
278 * How long until the current signature expires? (ZERO if the
279 * signature was never created).
281 struct GNUNET_TIME_Absolute pong_sig_expires;
284 * Signature for a 'struct TransportPongMessage' for this address.
286 struct GNUNET_CRYPTO_RsaSignature pong_signature;
297 * Entry in linked list of all of our plugins.
299 struct TransportPlugin
303 * This is a linked list.
305 struct TransportPlugin *next;
308 * API of the transport as returned by the plugin's
309 * initialization function.
311 struct GNUNET_TRANSPORT_PluginFunctions *api;
314 * Short name for the plugin (i.e. "tcp").
319 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
324 * List of our known addresses for this transport.
326 struct OwnAddressList *addresses;
329 * Environment this transport service is using
332 struct GNUNET_TRANSPORT_PluginEnvironment env;
335 * ID of task that is used to clean up expired addresses.
337 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
340 * Set to GNUNET_YES if we need to scrap the existing list of
341 * "addresses" and start fresh when we receive the next address
342 * update from a transport. Set to GNUNET_NO if we should just add
343 * the new address to the list and wait for the commit call.
348 * Hashmap of blacklisted peers for this particular transport.
350 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
353 struct NeighbourList;
356 * For each neighbour we keep a list of messages
357 * that we still want to transmit to the neighbour.
363 * This is a doubly linked list.
365 struct MessageQueue *next;
368 * This is a doubly linked list.
370 struct MessageQueue *prev;
373 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
374 * stuck together in memory. Allocated at the end of this struct.
376 const char *message_buf;
379 * Size of the message buf
381 size_t message_buf_size;
384 * Client responsible for queueing the message;
385 * used to check that a client has no two messages
386 * pending for the same target. Can be NULL.
388 struct TransportClient *client;
391 * Using which specific address should we send this message?
393 struct ForeignAddressList *specific_address;
396 * Peer ID of the Neighbour this entry belongs to.
398 struct GNUNET_PeerIdentity neighbour_id;
401 * Plugin that we used for the transmission.
402 * NULL until we scheduled a transmission.
404 struct TransportPlugin *plugin;
407 * At what time should we fail?
409 struct GNUNET_TIME_Absolute timeout;
412 * Internal message of the transport system that should not be
413 * included in the usual SEND-SEND_OK transmission confirmation
414 * traffic management scheme. Typically, "internal_msg" will
415 * be set whenever "client" is NULL (but it is not strictly
421 * How important is the message?
423 unsigned int priority;
429 * For a given Neighbour, which plugins are available
430 * to talk to this peer and what are their costs?
435 * This is a linked list.
437 struct ReadyList *next;
440 * Which of our transport plugins does this entry
443 struct TransportPlugin *plugin;
446 * Transport addresses, latency, and readiness for
447 * this particular plugin.
449 struct ForeignAddressList *addresses;
452 * To which neighbour does this ready list belong to?
454 struct NeighbourList *neighbour;
460 * Entry in linked list of all of our current neighbours.
466 * This is a linked list.
468 struct NeighbourList *next;
471 * Which of our transports is connected to this peer
472 * and what is their status?
474 struct ReadyList *plugins;
477 * Head of list of messages we would like to send to this peer;
478 * must contain at most one message per client.
480 struct MessageQueue *messages_head;
483 * Tail of list of messages we would like to send to this peer; must
484 * contain at most one message per client.
486 struct MessageQueue *messages_tail;
489 * Buffer for at most one payload message used when we receive
490 * payload data before our PING-PONG has succeeded. We then
491 * store such messages in this intermediary buffer until the
492 * connection is fully up.
494 struct GNUNET_MessageHeader *pre_connect_message_buffer;
497 * Context for peerinfo iteration.
498 * NULL after we are done processing peerinfo's information.
500 struct GNUNET_PEERINFO_IteratorContext *piter;
503 * Public key for this peer. Valid only if the respective flag is set below.
505 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
508 * Identity of this neighbour.
510 struct GNUNET_PeerIdentity id;
513 * ID of task scheduled to run when this peer is about to
514 * time out (will free resources associated with the peer).
516 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
519 * ID of task scheduled to run when we should retry transmitting
520 * the head of the message queue. Actually triggered when the
521 * transmission is timing out (we trigger instantly when we have
522 * a chance of success).
524 GNUNET_SCHEDULER_TaskIdentifier retry_task;
527 * How long until we should consider this peer dead
528 * (if we don't receive another message in the
531 struct GNUNET_TIME_Absolute peer_timeout;
534 * Tracker for inbound bandwidth.
536 struct GNUNET_BANDWIDTH_Tracker in_tracker;
539 * The latency we have seen for this particular address for
540 * this particular peer. This latency may have been calculated
541 * over multiple transports. This value reflects how long it took
542 * us to receive a response when SENDING via this particular
543 * transport/neighbour/address combination!
545 * FIXME: we need to periodically send PINGs to update this
546 * latency (at least more often than the current "huge" (11h?)
549 struct GNUNET_TIME_Relative latency;
552 * How often has the other peer (recently) violated the
553 * inbound traffic limit? Incremented by 10 per violation,
554 * decremented by 1 per non-violation (for each
557 unsigned int quota_violation_count;
560 * DV distance to this peer (1 if no DV is used).
565 * Have we seen an PONG from this neighbour in the past (and
566 * not had a disconnect since)?
571 * Do we have a valid public key for this neighbour?
573 int public_key_valid;
576 * Performance data for the peer.
578 struct GNUNET_TRANSPORT_ATS_Information *ats;
581 * Identity of the neighbour.
583 struct GNUNET_PeerIdentity peer;
588 * Message used to ask a peer to validate receipt (to check an address
589 * from a HELLO). Followed by the address we are trying to validate,
590 * or an empty address if we are just sending a PING to confirm that a
591 * connection which the receiver (of the PING) initiated is still valid.
593 struct TransportPingMessage
597 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
599 struct GNUNET_MessageHeader header;
602 * Challenge code (to ensure fresh reply).
604 uint32_t challenge GNUNET_PACKED;
607 * Who is the intended recipient?
609 struct GNUNET_PeerIdentity target;
615 * Message used to validate a HELLO. The challenge is included in the
616 * confirmation to make matching of replies to requests possible. The
617 * signature signs our public key, an expiration time and our address.<p>
619 * This message is followed by our transport address that the PING tried
620 * to confirm (if we liked it). The address can be empty (zero bytes)
621 * if the PING had not address either (and we received the request via
622 * a connection that we initiated).
624 struct TransportPongMessage
628 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
630 struct GNUNET_MessageHeader header;
633 * Challenge code from PING (showing freshness). Not part of what
634 * is signed so that we can re-use signatures.
636 uint32_t challenge GNUNET_PACKED;
641 struct GNUNET_CRYPTO_RsaSignature signature;
644 * What are we signing and why? Two possible reason codes can be here:
645 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
646 * plausible address for this peer (pid is set to identity of signer); or
647 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
648 * an address we used to connect to the peer with the given pid.
650 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
653 * When does this signature expire?
655 struct GNUNET_TIME_AbsoluteNBO expiration;
658 * Either the identity of the peer Who signed this message, or the
659 * identity of the peer that we're connected to using the given
660 * address (depending on purpose.type).
662 struct GNUNET_PeerIdentity pid;
665 * Size of address appended to this message (part of what is
666 * being signed, hence not redundant).
674 * Linked list of messages to be transmitted to the client. Each
675 * entry is followed by the actual message.
677 struct ClientMessageQueueEntry
680 * This is a doubly-linked list.
682 struct ClientMessageQueueEntry *next;
685 * This is a doubly-linked list.
687 struct ClientMessageQueueEntry *prev;
692 * Client connected to the transport service.
694 struct TransportClient
698 * This is a linked list.
700 struct TransportClient *next;
703 * Handle to the client.
705 struct GNUNET_SERVER_Client *client;
708 * Linked list of messages yet to be transmitted to
711 struct ClientMessageQueueEntry *message_queue_head;
714 * Tail of linked list of messages yet to be transmitted to the
717 struct ClientMessageQueueEntry *message_queue_tail;
720 * Current transmit request handle.
722 struct GNUNET_CONNECTION_TransmitHandle *th;
725 * Is a call to "transmit_send_continuation" pending? If so, we
726 * must not free this struct (even if the corresponding client
727 * disconnects) and instead only remove it from the linked list and
728 * set the "client" field to NULL.
733 * Length of the list of messages pending for this client.
735 unsigned int message_count;
741 * Context of currently active requests to peerinfo
742 * for validation of HELLOs.
744 struct CheckHelloValidatedContext;
748 * Entry in map of all HELLOs awaiting validation.
750 struct ValidationEntry
754 * NULL if this entry is not part of a larger HELLO validation.
756 struct CheckHelloValidatedContext *chvc;
759 * The address, actually a pointer to the end
760 * of this struct. Do not free!
765 * Name of the transport.
767 char *transport_name;
770 * The public key of the peer.
772 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
775 * ID of task that will clean up this entry if we don't succeed
776 * with the validation first.
778 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
781 * At what time did we send this validation?
783 struct GNUNET_TIME_Absolute send_time;
786 * Session being validated (or NULL for none).
788 struct Session *session;
791 * Challenge number we used.
804 * Context of currently active requests to peerinfo
805 * for validation of HELLOs.
807 struct CheckHelloValidatedContext
811 * This is a doubly-linked list.
813 struct CheckHelloValidatedContext *next;
816 * This is a doubly-linked list.
818 struct CheckHelloValidatedContext *prev;
821 * Hello that we are validating.
823 const struct GNUNET_HELLO_Message *hello;
826 * Context for peerinfo iteration.
827 * NULL after we are done processing peerinfo's information.
829 struct GNUNET_PEERINFO_IteratorContext *piter;
832 * Was a HELLO known for this peer to peerinfo?
837 * Number of validation entries currently referring to this
840 unsigned int ve_count;
848 static struct GNUNET_HELLO_Message *our_hello;
853 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
858 static struct GNUNET_PeerIdentity my_identity;
863 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
868 const struct GNUNET_CONFIGURATION_Handle *cfg;
871 * Linked list of all clients to this service.
873 static struct TransportClient *clients;
876 * All loaded plugins.
878 static struct TransportPlugin *plugins;
881 * Handle to peerinfo service.
883 static struct GNUNET_PEERINFO_Handle *peerinfo;
886 * All known neighbours and their HELLOs.
888 static struct NeighbourList *neighbours;
891 * Number of neighbours we'd like to have.
893 static uint32_t max_connect_per_transport;
896 * Head of linked list.
898 static struct CheckHelloValidatedContext *chvc_head;
901 * Tail of linked list.
903 static struct CheckHelloValidatedContext *chvc_tail;
906 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
907 * of the given peer that we are currently validating).
909 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
912 * Handle for reporting statistics.
914 static struct GNUNET_STATISTICS_Handle *stats;
917 * Handle for ats information
919 static struct ATS_info *ats;
922 * The peer specified by the given neighbour has timed-out or a plugin
923 * has disconnected. We may either need to do nothing (other plugins
924 * still up), or trigger a full disconnect and clean up. This
925 * function updates our state and do the necessary notifications.
926 * Also notifies our clients that the neighbour is now officially
929 * @param n the neighbour list entry for the peer
930 * @param check should we just check if all plugins
931 * disconnected or must we ask all plugins to
934 static void disconnect_neighbour (struct NeighbourList *n, int check);
937 * Check the ready list for the given neighbour and if a plugin is
938 * ready for transmission (and if we have a message), do so!
940 * @param neighbour target peer for which to transmit
942 static void try_transmission_to_peer (struct NeighbourList *n);
945 struct ATS_info * ats_init ();
947 void ats_shutdown (struct ATS_info * ats);
949 void ats_notify_peer_connect (struct ATS_info * ats,
950 const struct GNUNET_PeerIdentity *peer,
951 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
953 void ats_notify_peer_disconnect (struct ATS_info * ats,
954 const struct GNUNET_PeerIdentity *peer);
956 void ats_notify_ats_data (struct ATS_info * ats,
957 const struct GNUNET_PeerIdentity *peer,
958 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
960 struct ForeignAddressList * ats_get_preferred_address (struct ATS_info * ats,
961 struct NeighbourList *n);
964 * Find an entry in the neighbour list for a particular peer.
966 * @return NULL if not found.
968 static struct NeighbourList *
969 find_neighbour (const struct GNUNET_PeerIdentity *key)
971 struct NeighbourList *head = neighbours;
973 while ((head != NULL) &&
974 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
981 * Find an entry in the transport list for a particular transport.
983 * @return NULL if not found.
985 static struct TransportPlugin *
986 find_transport (const char *short_name)
988 struct TransportPlugin *head = plugins;
989 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
995 * Is a particular peer blacklisted for a particular transport?
997 * @param peer the peer to check for
998 * @param plugin the plugin used to connect to the peer
1000 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1003 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1006 if (plugin->blacklist != NULL)
1008 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012 "Peer `%s:%s' is blacklisted!\n",
1013 plugin->short_name, GNUNET_i2s (peer));
1016 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1026 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1028 struct TransportPlugin *plugin;
1030 plugin = find_transport(transport_name);
1031 if (plugin == NULL) /* Nothing to do */
1033 if (plugin->blacklist == NULL)
1034 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1035 GNUNET_assert(plugin->blacklist != NULL);
1036 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1038 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1043 * Read the blacklist file, containing transport:peer entries.
1044 * Provided the transport is loaded, set up hashmap with these
1045 * entries to blacklist peers by transport.
1049 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1056 struct GNUNET_PeerIdentity pid;
1058 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1059 unsigned int entries_found;
1060 char *transport_name;
1063 GNUNET_CONFIGURATION_get_value_filename (cfg,
1069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1070 "Option `%s' in section `%s' not specified!\n",
1076 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1077 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1078 | GNUNET_DISK_PERM_USER_WRITE);
1079 if (0 != STAT (fn, &frstat))
1081 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1082 _("Could not read blacklist file `%s'\n"), fn);
1086 if (frstat.st_size == 0)
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090 _("Blacklist file `%s' is empty.\n"),
1096 /* FIXME: use mmap */
1097 data = GNUNET_malloc_large (frstat.st_size);
1098 GNUNET_assert(data != NULL);
1099 if (frstat.st_size !=
1100 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1103 _("Failed to read blacklist from `%s'\n"), fn);
1110 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1112 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1113 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1116 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1119 if (colon_pos >= frstat.st_size)
1121 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1122 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1123 (unsigned long long) colon_pos);
1129 if (isspace( (unsigned char) data[colon_pos]))
1131 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1132 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1133 (unsigned long long) colon_pos);
1135 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1139 tsize = colon_pos - pos;
1140 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1142 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1143 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1144 (unsigned long long) colon_pos);
1153 transport_name = GNUNET_malloc(tsize + 1);
1154 memcpy(transport_name, &data[pos], tsize);
1155 pos = colon_pos + 1;
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 "Read transport name %s in blacklist file.\n",
1161 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1162 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1165 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1166 (unsigned long long) pos);
1168 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1170 GNUNET_free_non_null(transport_name);
1173 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1174 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1176 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1177 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1178 (unsigned long long) pos,
1183 if (0 != memcmp (&pid,
1185 sizeof (struct GNUNET_PeerIdentity)))
1188 add_peer_to_blacklist (&pid,
1193 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1194 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1198 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1199 GNUNET_free_non_null(transport_name);
1200 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1203 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1210 * Function called to notify a client about the socket being ready to
1211 * queue more data. "buf" will be NULL and "size" zero if the socket
1212 * was closed for writing in the meantime.
1214 * @param cls closure
1215 * @param size number of bytes available in buf
1216 * @param buf where the callee should write the message
1217 * @return number of bytes written to buf
1220 transmit_to_client_callback (void *cls, size_t size, void *buf)
1222 struct TransportClient *client = cls;
1223 struct ClientMessageQueueEntry *q;
1226 const struct GNUNET_MessageHeader *msg;
1233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1234 "Transmission to client failed, closing connection.\n");
1236 /* fatal error with client, free message queue! */
1237 while (NULL != (q = client->message_queue_head))
1239 GNUNET_STATISTICS_update (stats,
1240 gettext_noop ("# bytes discarded (could not transmit to client)"),
1241 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1243 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1244 client->message_queue_tail,
1248 client->message_count = 0;
1253 while (NULL != (q = client->message_queue_head))
1255 msg = (const struct GNUNET_MessageHeader *) &q[1];
1256 msize = ntohs (msg->size);
1257 if (msize + tsize > size)
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1261 "Transmitting message of type %u to client.\n",
1264 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1265 client->message_queue_tail,
1267 memcpy (&cbuf[tsize], msg, msize);
1270 client->message_count--;
1274 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1275 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1277 GNUNET_TIME_UNIT_FOREVER_REL,
1278 &transmit_to_client_callback,
1280 GNUNET_assert (client->th != NULL);
1287 * Convert an address to a string.
1289 * @param plugin name of the plugin responsible for the address
1290 * @param addr binary address
1291 * @param addr_len number of bytes in addr
1292 * @return NULL on error, otherwise address string
1295 a2s (const char *plugin,
1299 struct TransportPlugin *p;
1303 p = find_transport (plugin);
1306 return p->api->address_to_string (p->api->cls,
1313 * Mark the given FAL entry as 'connected' (and hence preferred for
1314 * sending); also mark all others for the same peer as 'not connected'
1315 * (since only one can be preferred).
1317 * @param fal address to set to 'connected'
1320 mark_address_connected (struct ForeignAddressList *fal)
1322 struct ForeignAddressList *pos;
1325 GNUNET_assert (GNUNET_YES == fal->validated);
1326 if (fal->connected == GNUNET_YES)
1327 return; /* nothing to do */
1329 pos = fal->ready_list->addresses;
1332 if (GNUNET_YES == pos->connected)
1335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1336 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1337 a2s (pos->ready_list->plugin->short_name,
1341 GNUNET_break (cnt == GNUNET_YES);
1343 pos->connected = GNUNET_NO;
1344 GNUNET_STATISTICS_update (stats,
1345 gettext_noop ("# connected addresses"),
1351 fal->connected = GNUNET_YES;
1352 if (GNUNET_YES == cnt)
1354 GNUNET_STATISTICS_update (stats,
1355 gettext_noop ("# connected addresses"),
1363 * Send the specified message to the specified client. Since multiple
1364 * messages may be pending for the same client at a time, this code
1365 * makes sure that no message is lost.
1367 * @param client client to transmit the message to
1368 * @param msg the message to send
1369 * @param may_drop can this message be dropped if the
1370 * message queue for this client is getting far too large?
1373 transmit_to_client (struct TransportClient *client,
1374 const struct GNUNET_MessageHeader *msg, int may_drop)
1376 struct ClientMessageQueueEntry *q;
1379 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1383 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1386 client->message_count,
1388 GNUNET_STATISTICS_update (stats,
1389 gettext_noop ("# messages dropped due to slow client"),
1394 msize = ntohs (msg->size);
1395 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1396 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1397 memcpy (&q[1], msg, msize);
1398 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1399 client->message_queue_tail,
1400 client->message_queue_tail,
1402 client->message_count++;
1403 if (client->th == NULL)
1405 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1407 GNUNET_TIME_UNIT_FOREVER_REL,
1408 &transmit_to_client_callback,
1410 GNUNET_assert (client->th != NULL);
1416 * Transmit a 'SEND_OK' notification to the given client for the
1419 * @param client who to notify
1420 * @param n neighbour to notify about, can be NULL (on failure)
1421 * @param target target of the transmission
1422 * @param result status code for the transmission request
1425 transmit_send_ok (struct TransportClient *client,
1426 struct NeighbourList *n,
1427 const struct GNUNET_PeerIdentity *target,
1430 struct SendOkMessage send_ok_msg;
1432 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1433 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1434 send_ok_msg.success = htonl (result);
1436 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1438 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1439 send_ok_msg.peer = *target;
1440 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1445 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1446 * upon "completion" of a send request. This tells the API
1447 * that it is now legal to send another message to the given
1450 * @param cls closure, identifies the entry on the
1451 * message queue that was transmitted and the
1452 * client responsible for queuing the message
1453 * @param target the peer receiving the message
1454 * @param result GNUNET_OK on success, if the transmission
1455 * failed, we should not tell the client to transmit
1459 transmit_send_continuation (void *cls,
1460 const struct GNUNET_PeerIdentity *target,
1463 struct MessageQueue *mq = cls;
1464 struct NeighbourList *n;
1466 GNUNET_STATISTICS_update (stats,
1467 gettext_noop ("# bytes pending with plugins"),
1468 - (int64_t) mq->message_buf_size,
1470 if (result == GNUNET_OK)
1472 GNUNET_STATISTICS_update (stats,
1473 gettext_noop ("# bytes successfully transmitted by plugins"),
1474 mq->message_buf_size,
1479 GNUNET_STATISTICS_update (stats,
1480 gettext_noop ("# bytes with transmission failure by plugins"),
1481 mq->message_buf_size,
1484 if (mq->specific_address != NULL)
1486 if (result == GNUNET_OK)
1488 mq->specific_address->timeout =
1489 GNUNET_TIME_relative_to_absolute
1490 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1491 if (mq->specific_address->validated == GNUNET_YES)
1492 mark_address_connected (mq->specific_address);
1496 if (mq->specific_address->connected != GNUNET_NO)
1499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1500 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1501 a2s (mq->specific_address->ready_list->plugin->short_name,
1502 mq->specific_address->addr,
1503 mq->specific_address->addrlen));
1505 GNUNET_STATISTICS_update (stats,
1506 gettext_noop ("# connected addresses"),
1509 mq->specific_address->connected = GNUNET_NO;
1512 if (! mq->internal_msg)
1513 mq->specific_address->in_transmit = GNUNET_NO;
1515 n = find_neighbour(&mq->neighbour_id);
1516 if (mq->client != NULL)
1517 transmit_send_ok (mq->client, n, target, result);
1520 try_transmission_to_peer (n);
1525 * Find an address in any of the available transports for
1526 * the given neighbour that would be good for message
1527 * transmission. This is essentially the transport selection
1530 * @param neighbour for whom to select an address
1531 * @return selected address, NULL if we have none
1533 struct ForeignAddressList *
1534 find_ready_address(struct NeighbourList *neighbour)
1536 struct ReadyList *head = neighbour->plugins;
1537 struct ForeignAddressList *addresses;
1538 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1539 struct ForeignAddressList *best_address;
1541 /* Hack to prefer unix domain sockets */
1542 struct ForeignAddressList *unix_address = NULL;
1544 best_address = NULL;
1545 while (head != NULL)
1547 addresses = head->addresses;
1548 while (addresses != NULL)
1550 if ( (addresses->timeout.abs_value < now.abs_value) &&
1551 (addresses->connected == GNUNET_YES) )
1554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1555 "Marking long-time inactive connection to `%4s' as down.\n",
1556 GNUNET_i2s (&neighbour->id));
1558 GNUNET_STATISTICS_update (stats,
1559 gettext_noop ("# connected addresses"),
1562 addresses->connected = GNUNET_NO;
1564 addresses = addresses->next;
1567 addresses = head->addresses;
1568 while (addresses != NULL)
1570 #if DEBUG_TRANSPORT > 1
1571 if (addresses->addr != NULL)
1572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1573 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1574 a2s (head->plugin->short_name,
1576 addresses->addrlen),
1577 GNUNET_i2s (&neighbour->id),
1578 addresses->connected,
1579 addresses->in_transmit,
1580 addresses->validated,
1581 addresses->connect_attempts,
1582 (unsigned long long) addresses->timeout.abs_value,
1583 (unsigned int) addresses->distance);
1585 if (0==strcmp(head->plugin->short_name,"unix"))
1587 if ((unix_address == NULL) || ((unix_address != NULL) &&
1588 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1589 unix_address = addresses;
1591 if ( ( (best_address == NULL) ||
1592 (addresses->connected == GNUNET_YES) ||
1593 (best_address->connected == GNUNET_NO) ) &&
1594 (addresses->in_transmit == GNUNET_NO) &&
1595 ( (best_address == NULL) ||
1596 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1597 best_address = addresses;
1598 /* FIXME: also give lower-latency addresses that are not
1599 connected a chance some times... */
1600 addresses = addresses->next;
1602 if (unix_address != NULL)
1606 if (unix_address != NULL)
1608 best_address = unix_address;
1610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1613 if (best_address != NULL)
1617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1618 "Best address found (`%s') has latency of %llu ms.\n",
1619 (best_address->addrlen > 0)
1620 ? a2s (best_address->ready_list->plugin->short_name,
1622 best_address->addrlen)
1624 best_address->latency.rel_value);
1629 GNUNET_STATISTICS_update (stats,
1630 gettext_noop ("# transmission attempts failed (no address)"),
1635 return best_address;
1641 * We should re-try transmitting to the given peer,
1642 * hopefully we've learned something in the meantime.
1645 retry_transmission_task (void *cls,
1646 const struct GNUNET_SCHEDULER_TaskContext *tc)
1648 struct NeighbourList *n = cls;
1650 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1651 try_transmission_to_peer (n);
1656 * Check the ready list for the given neighbour and if a plugin is
1657 * ready for transmission (and if we have a message), do so!
1659 * @param neighbour target peer for which to transmit
1662 try_transmission_to_peer (struct NeighbourList *n)
1664 struct ReadyList *rl;
1665 struct MessageQueue *mq;
1666 struct GNUNET_TIME_Relative timeout;
1670 if (n->messages_head == NULL)
1673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1674 "Transmission queue for `%4s' is empty\n",
1675 GNUNET_i2s (&neighbour->id));
1677 return; /* nothing to do */
1680 mq = n->messages_head;
1681 force_address = GNUNET_YES;
1682 if (mq->specific_address == NULL)
1685 mq->specific_address = ats_get_preferred_address(ats, n);
1686 GNUNET_STATISTICS_update (stats,
1687 gettext_noop ("# transport selected peer address freely"),
1690 force_address = GNUNET_NO;
1692 if (mq->specific_address == NULL)
1694 GNUNET_STATISTICS_update (stats,
1695 gettext_noop ("# transport failed to selected peer address"),
1698 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1699 if (timeout.rel_value == 0)
1702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1703 "No destination address available to transmit message of size %u to peer `%4s'\n",
1704 mq->message_buf_size,
1705 GNUNET_i2s (&mq->neighbour_id));
1707 GNUNET_STATISTICS_update (stats,
1708 gettext_noop ("# bytes in message queue for other peers"),
1709 - (int64_t) mq->message_buf_size,
1711 GNUNET_STATISTICS_update (stats,
1712 gettext_noop ("# bytes discarded (no destination address available)"),
1713 mq->message_buf_size,
1715 if (mq->client != NULL)
1716 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1717 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1721 return; /* nobody ready */
1723 GNUNET_STATISTICS_update (stats,
1724 gettext_noop ("# message delivery deferred (no address)"),
1727 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1728 GNUNET_SCHEDULER_cancel (n->retry_task);
1729 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1730 &retry_transmission_task,
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1735 mq->message_buf_size,
1736 GNUNET_i2s (&mq->neighbour_id),
1739 /* FIXME: might want to trigger peerinfo lookup here
1740 (unless that's already pending...) */
1743 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1746 if (mq->specific_address->connected == GNUNET_NO)
1747 mq->specific_address->connect_attempts++;
1748 rl = mq->specific_address->ready_list;
1749 mq->plugin = rl->plugin;
1750 if (!mq->internal_msg)
1751 mq->specific_address->in_transmit = GNUNET_YES;
1753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1754 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1755 mq->message_buf_size,
1756 GNUNET_i2s (&neighbour->id),
1757 (mq->specific_address->addr != NULL)
1758 ? a2s (mq->plugin->short_name,
1759 mq->specific_address->addr,
1760 mq->specific_address->addrlen)
1762 rl->plugin->short_name);
1764 GNUNET_STATISTICS_update (stats,
1765 gettext_noop ("# bytes in message queue for other peers"),
1766 - (int64_t) mq->message_buf_size,
1768 GNUNET_STATISTICS_update (stats,
1769 gettext_noop ("# bytes pending with plugins"),
1770 mq->message_buf_size,
1772 ret = rl->plugin->api->send (rl->plugin->api->cls,
1775 mq->message_buf_size,
1777 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1778 mq->specific_address->session,
1779 mq->specific_address->addr,
1780 mq->specific_address->addrlen,
1782 &transmit_send_continuation, mq);
1785 /* failure, but 'send' would not call continuation in this case,
1786 so we need to do it here! */
1787 transmit_send_continuation (mq,
1795 * Send the specified message to the specified peer.
1797 * @param client source of the transmission request (can be NULL)
1798 * @param peer_address ForeignAddressList where we should send this message
1799 * @param priority how important is the message
1800 * @param timeout how long do we have to transmit?
1801 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1802 * @param message_buf_size total size of all messages in message_buf
1803 * @param is_internal is this an internal message; these are pre-pended and
1804 * also do not count for plugins being "ready" to transmit
1805 * @param neighbour handle to the neighbour for transmission
1808 transmit_to_peer (struct TransportClient *client,
1809 struct ForeignAddressList *peer_address,
1810 unsigned int priority,
1811 struct GNUNET_TIME_Relative timeout,
1812 const char *message_buf,
1813 size_t message_buf_size,
1814 int is_internal, struct NeighbourList *neighbour)
1816 struct MessageQueue *mq;
1821 /* check for duplicate submission */
1822 mq = neighbour->messages_head;
1825 if (mq->client == client)
1827 /* client transmitted to same peer twice
1828 before getting SEND_OK! */
1836 GNUNET_STATISTICS_update (stats,
1837 gettext_noop ("# bytes in message queue for other peers"),
1840 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1841 mq->specific_address = peer_address;
1842 mq->client = client;
1843 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1844 memcpy (&mq[1], message_buf, message_buf_size);
1845 mq->message_buf = (const char*) &mq[1];
1846 mq->message_buf_size = message_buf_size;
1847 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1848 mq->internal_msg = is_internal;
1849 mq->priority = priority;
1850 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1852 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1853 neighbour->messages_tail,
1856 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1857 neighbour->messages_tail,
1858 neighbour->messages_tail,
1860 try_transmission_to_peer (neighbour);
1867 struct GeneratorContext
1869 struct TransportPlugin *plug_pos;
1870 struct OwnAddressList *addr_pos;
1871 struct GNUNET_TIME_Absolute expiration;
1879 address_generator (void *cls, size_t max, void *buf)
1881 struct GeneratorContext *gc = cls;
1884 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1886 gc->plug_pos = gc->plug_pos->next;
1887 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1889 if (NULL == gc->plug_pos)
1894 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1897 gc->addr_pos->addrlen, buf, max);
1898 gc->addr_pos = gc->addr_pos->next;
1904 * Construct our HELLO message from all of the addresses of
1905 * all of the transports.
1910 struct GNUNET_HELLO_Message *hello;
1911 struct TransportClient *cpos;
1912 struct NeighbourList *npos;
1913 struct GeneratorContext gc;
1915 gc.plug_pos = plugins;
1916 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1917 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1918 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1921 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1923 GNUNET_STATISTICS_update (stats,
1924 gettext_noop ("# refreshed my HELLO"),
1928 while (cpos != NULL)
1930 transmit_to_client (cpos,
1931 (const struct GNUNET_MessageHeader *) hello,
1936 GNUNET_free_non_null (our_hello);
1938 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1940 while (npos != NULL)
1943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1944 "Transmitting updated `%s' to neighbour `%4s'\n",
1945 "HELLO", GNUNET_i2s (&npos->id));
1947 GNUNET_STATISTICS_update (stats,
1948 gettext_noop ("# transmitted my HELLO to other peers"),
1951 transmit_to_peer (NULL, NULL, 0,
1952 HELLO_ADDRESS_EXPIRATION,
1953 (const char *) our_hello,
1954 GNUNET_HELLO_size(our_hello),
1962 * Task used to clean up expired addresses for a plugin.
1964 * @param cls closure
1968 expire_address_task (void *cls,
1969 const struct GNUNET_SCHEDULER_TaskContext *tc);
1973 * Update the list of addresses for this plugin,
1974 * expiring those that are past their expiration date.
1976 * @param plugin addresses of which plugin should be recomputed?
1977 * @param fresh set to GNUNET_YES if a new address was added
1978 * and we need to regenerate the HELLO even if nobody
1982 update_addresses (struct TransportPlugin *plugin,
1985 static struct GNUNET_TIME_Absolute last_update;
1986 struct GNUNET_TIME_Relative min_remaining;
1987 struct GNUNET_TIME_Relative remaining;
1988 struct GNUNET_TIME_Absolute now;
1989 struct OwnAddressList *pos;
1990 struct OwnAddressList *prev;
1991 struct OwnAddressList *next;
1994 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1995 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1996 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1997 now = GNUNET_TIME_absolute_get ();
1998 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1999 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2001 pos = plugin->addresses;
2005 if (pos->expires.abs_value < now.abs_value)
2007 expired = GNUNET_YES;
2009 plugin->addresses = pos->next;
2011 prev->next = pos->next;
2016 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2017 if (remaining.rel_value < min_remaining.rel_value)
2018 min_remaining = remaining;
2024 if (expired || fresh)
2029 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2030 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2032 plugin->address_update_task
2033 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2034 &expire_address_task, plugin);
2039 * Task used to clean up expired addresses for a plugin.
2041 * @param cls closure
2045 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2047 struct TransportPlugin *plugin = cls;
2049 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2050 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2051 update_addresses (plugin, GNUNET_NO);
2056 * Iterator over hash map entries that NULLs the session of validation
2057 * entries that match the given session.
2059 * @param cls closure (the 'struct Session*' to match against)
2060 * @param key current key code (peer ID, not used)
2061 * @param value value in the hash map ('struct ValidationEntry*')
2062 * @return GNUNET_YES (we should continue to iterate)
2065 remove_session_validations (void *cls,
2066 const GNUNET_HashCode * key,
2069 struct Session *session = cls;
2070 struct ValidationEntry *ve = value;
2072 if (session == ve->session)
2079 * We've been disconnected from the other peer (for some
2080 * connection-oriented transport). Either quickly
2081 * re-establish the connection or signal the disconnect
2084 * Only signal CORE level disconnect if ALL addresses
2085 * for the peer are exhausted.
2087 * @param p overall plugin context
2088 * @param nl neighbour that was disconnected
2091 try_fast_reconnect (struct TransportPlugin *p,
2092 struct NeighbourList *nl)
2094 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2095 /* Note: the idea here is to hide problems with transports (or
2096 switching between plugins) from the core to eliminate the need to
2097 re-negotiate session keys and the like; OTOH, we should tell core
2098 quickly (much faster than timeout) `if a connection was lost and
2099 could not be re-established (i.e. other peer went down or is
2100 unable / refuses to communicate);
2102 So we should consider:
2103 1) ideally: our own willingness / need to connect
2104 2) prior failures to connect to this peer (by plugin)
2105 3) ideally: reasons why other peer terminated (as far as knowable)
2107 Most importantly, it must be POSSIBLE for another peer to terminate
2108 a connection for a while (without us instantly re-establishing it).
2109 Similarly, if another peer is gone we should quickly notify CORE.
2110 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2111 on the other end), we should reconnect in such a way that BOTH CORE
2112 services never even notice.
2113 Furthermore, the same mechanism (or small variation) could be used
2114 to switch to a better-performing plugin (ATS).
2116 Finally, this needs to be tested throughly... */
2119 * GNUNET_NO in the call below makes transport disconnect the peer,
2120 * even if only a single address (out of say, six) went away. This
2121 * function must be careful to ONLY disconnect if the peer is gone,
2122 * not just a specifi address.
2124 * More specifically, half the places it was used had it WRONG.
2127 /* No reconnect, signal disconnect instead! */
2128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2129 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2130 "try_fast_reconnect");
2131 disconnect_neighbour (nl, GNUNET_YES);
2136 * Function that will be called whenever the plugin internally
2137 * cleans up a session pointer and hence the service needs to
2138 * discard all of those sessions as well. Plugins that do not
2139 * use sessions can simply omit calling this function and always
2140 * use NULL wherever a session pointer is needed.
2142 * @param cls closure
2143 * @param peer which peer was the session for
2144 * @param session which session is being destoyed
2147 plugin_env_session_end (void *cls,
2148 const struct GNUNET_PeerIdentity *peer,
2149 struct Session *session)
2151 struct TransportPlugin *p = cls;
2152 struct NeighbourList *nl;
2153 struct ReadyList *rl;
2154 struct ForeignAddressList *pos;
2155 struct ForeignAddressList *prev;
2157 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2158 &remove_session_validations,
2160 nl = find_neighbour (peer);
2162 return; /* was never marked as connected */
2166 if (rl->plugin == p)
2171 return; /* was never marked as connected */
2173 pos = rl->addresses;
2174 while ( (pos != NULL) &&
2175 (pos->session != session) )
2181 return; /* was never marked as connected */
2182 pos->session = NULL;
2183 if (pos->addrlen != 0)
2185 if (nl->received_pong != GNUNET_NO)
2186 try_fast_reconnect (p, nl);
2189 /* was inbound connection, free 'pos' */
2191 rl->addresses = pos->next;
2193 prev->next = pos->next;
2194 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2196 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2197 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2200 if (nl->received_pong == GNUNET_NO)
2201 return; /* nothing to do, never connected... */
2202 /* check if we have any validated addresses left */
2203 pos = rl->addresses;
2208 try_fast_reconnect (p, nl);
2213 /* no valid addresses left, signal disconnect! */
2215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2217 "plugin_env_session_end");
2218 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2219 * it means there aren't any left for this PLUGIN/PEER combination! So
2220 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2221 * when it isn't necessary. Using GNUNET_YES at least checks to see
2222 * if there are any addresses that work first, so as not to overdo it.
2225 disconnect_neighbour (nl, GNUNET_YES);
2230 * Function that must be called by each plugin to notify the
2231 * transport service about the addresses under which the transport
2232 * provided by the plugin can be reached.
2234 * @param cls closure
2235 * @param name name of the transport that generated the address
2236 * @param addr one of the addresses of the host, NULL for the last address
2237 * the specific address format depends on the transport
2238 * @param addrlen length of the address
2239 * @param expires when should this address automatically expire?
2242 plugin_env_notify_address (void *cls,
2246 struct GNUNET_TIME_Relative expires)
2248 struct TransportPlugin *p = cls;
2249 struct OwnAddressList *al;
2250 struct GNUNET_TIME_Absolute abex;
2252 GNUNET_assert (addr != NULL);
2253 abex = GNUNET_TIME_relative_to_absolute (expires);
2254 GNUNET_assert (p == find_transport (name));
2258 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2261 update_addresses (p, GNUNET_NO);
2267 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2268 al->next = p->addresses;
2271 al->addrlen = addrlen;
2272 memcpy (&al[1], addr, addrlen);
2273 update_addresses (p, GNUNET_YES);
2278 * Notify all of our clients about a peer connecting.
2281 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2282 struct GNUNET_TIME_Relative latency,
2285 struct ConnectInfoMessage * cim;
2286 struct TransportClient *cpos;
2291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2292 "Notifying clients about connection from `%s'\n",
2295 GNUNET_STATISTICS_update (stats,
2296 gettext_noop ("# peers connected"),
2301 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2302 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2306 cim = GNUNET_malloc (size);
2308 cim->header.size = htons (size);
2309 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2310 cim->ats_count = htonl(2);
2311 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2312 (&(cim->ats))[0].value = htonl (distance);
2313 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2314 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2315 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2316 (&(cim->ats))[2].value = htonl (0);
2317 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2319 /* notify ats about connecting peer */
2320 ats_notify_peer_connect(ats, peer, &(cim->ats));
2323 while (cpos != NULL)
2325 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2334 * Notify all of our clients about a peer disconnecting.
2337 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2339 struct DisconnectInfoMessage dim;
2340 struct TransportClient *cpos;
2343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2344 "Notifying clients about lost connection to `%s'\n",
2347 GNUNET_STATISTICS_update (stats,
2348 gettext_noop ("# peers connected"),
2351 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2352 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2353 dim.reserved = htonl (0);
2354 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2356 /* notify ats about connecting peer */
2357 ats_notify_peer_disconnect(ats, peer);
2360 while (cpos != NULL)
2362 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2369 * Find a ForeignAddressList entry for the given neighbour
2370 * that matches the given address and transport.
2372 * @param neighbour which peer we care about
2373 * @param tname name of the transport plugin
2374 * @param session session to look for, NULL for 'any'; otherwise
2375 * can be used for the service to "learn" this session ID
2377 * @param addr binary address
2378 * @param addrlen length of addr
2379 * @return NULL if no such entry exists
2381 static struct ForeignAddressList *
2382 find_peer_address(struct NeighbourList *neighbour,
2384 struct Session *session,
2388 struct ReadyList *head;
2389 struct ForeignAddressList *pos;
2391 head = neighbour->plugins;
2392 while (head != NULL)
2394 if (0 == strcmp (tname, head->plugin->short_name))
2400 pos = head->addresses;
2401 while ( (pos != NULL) &&
2402 ( (pos->addrlen != addrlen) ||
2403 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2405 if ( (session != NULL) &&
2406 (pos->session == session) )
2410 if ( (session != NULL) && (pos != NULL) )
2411 pos->session = session; /* learn it! */
2417 * Get the peer address struct for the given neighbour and
2418 * address. If it doesn't yet exist, create it.
2420 * @param neighbour which peer we care about
2421 * @param tname name of the transport plugin
2422 * @param session session of the plugin, or NULL for none
2423 * @param addr binary address
2424 * @param addrlen length of addr
2425 * @return NULL if we do not have a transport plugin for 'tname'
2427 static struct ForeignAddressList *
2428 add_peer_address (struct NeighbourList *neighbour,
2430 struct Session *session,
2434 struct ReadyList *head;
2435 struct ForeignAddressList *ret;
2437 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2440 head = neighbour->plugins;
2442 while (head != NULL)
2444 if (0 == strcmp (tname, head->plugin->short_name))
2450 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2451 ret->session = session;
2454 ret->addr = (const char*) &ret[1];
2455 memcpy (&ret[1], addr, addrlen);
2461 ret->addrlen = addrlen;
2462 ret->expires = GNUNET_TIME_relative_to_absolute
2463 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2464 ret->latency = GNUNET_TIME_relative_get_forever();
2466 ret->timeout = GNUNET_TIME_relative_to_absolute
2467 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2468 ret->ready_list = head;
2469 ret->next = head->addresses;
2470 head->addresses = ret;
2476 * Closure for 'add_validated_address'.
2478 struct AddValidatedAddressContext
2481 * Entry that has been validated.
2483 const struct ValidationEntry *ve;
2486 * Flag set after we have added the address so
2487 * that we terminate the iteration next time.
2494 * Callback function used to fill a buffer of max bytes with a list of
2495 * addresses in the format used by HELLOs. Should use
2496 * "GNUNET_HELLO_add_address" as a helper function.
2498 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2499 * @param max maximum number of bytes that can be written to buf
2500 * @param buf where to write the address information
2501 * @return number of bytes written, 0 to signal the
2502 * end of the iteration.
2505 add_validated_address (void *cls,
2506 size_t max, void *buf)
2508 struct AddValidatedAddressContext *avac = cls;
2509 const struct ValidationEntry *ve = avac->ve;
2511 if (GNUNET_YES == avac->done)
2513 avac->done = GNUNET_YES;
2514 return GNUNET_HELLO_add_address (ve->transport_name,
2515 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2525 * Closure for 'check_address_exists'.
2527 struct CheckAddressExistsClosure
2530 * Address to check for.
2535 * Name of the transport.
2542 struct Session *session;
2545 * Set to GNUNET_YES if the address exists.
2558 * Iterator over hash map entries. Checks if the given
2559 * validation entry is for the same address as what is given
2562 * @param cls the 'struct CheckAddressExistsClosure*'
2563 * @param key current key code (ignored)
2564 * @param value value in the hash map ('struct ValidationEntry')
2565 * @return GNUNET_YES if we should continue to
2566 * iterate (mismatch), GNUNET_NO if not (entry matched)
2569 check_address_exists (void *cls,
2570 const GNUNET_HashCode * key,
2573 struct CheckAddressExistsClosure *caec = cls;
2574 struct ValidationEntry *ve = value;
2576 if ( (0 == strcmp (caec->tname,
2577 ve->transport_name)) &&
2578 (caec->addrlen == ve->addrlen) &&
2579 (0 == memcmp (caec->addr,
2583 caec->exists = GNUNET_YES;
2586 if ( (ve->session != NULL) &&
2587 (caec->session == ve->session) )
2589 caec->exists = GNUNET_YES;
2598 * Iterator to free entries in the validation_map.
2600 * @param cls closure (unused)
2601 * @param key current key code
2602 * @param value value in the hash map (validation to abort)
2603 * @return GNUNET_YES (always)
2606 abort_validation (void *cls,
2607 const GNUNET_HashCode * key,
2610 struct ValidationEntry *va = value;
2612 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2613 GNUNET_SCHEDULER_cancel (va->timeout_task);
2614 GNUNET_free (va->transport_name);
2615 if (va->chvc != NULL)
2617 va->chvc->ve_count--;
2618 if (va->chvc->ve_count == 0)
2620 GNUNET_CONTAINER_DLL_remove (chvc_head,
2623 GNUNET_free (va->chvc);
2633 * HELLO validation cleanup task (validation failed).
2635 * @param cls the 'struct ValidationEntry' that failed
2636 * @param tc scheduler context (unused)
2639 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2641 struct ValidationEntry *va = cls;
2642 struct GNUNET_PeerIdentity pid;
2644 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2645 GNUNET_STATISTICS_update (stats,
2646 gettext_noop ("# address validation timeouts"),
2649 GNUNET_CRYPTO_hash (&va->publicKey,
2651 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2653 GNUNET_break (GNUNET_OK ==
2654 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2657 abort_validation (NULL, NULL, va);
2662 neighbour_timeout_task (void *cls,
2663 const struct GNUNET_SCHEDULER_TaskContext *tc)
2665 struct NeighbourList *n = cls;
2668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2669 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2671 GNUNET_STATISTICS_update (stats,
2672 gettext_noop ("# disconnects due to timeout"),
2675 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2676 disconnect_neighbour (n, GNUNET_NO);
2681 * Schedule the job that will cause us to send a PING to the
2682 * foreign address to evaluate its validity and latency.
2684 * @param fal address to PING
2687 schedule_next_ping (struct ForeignAddressList *fal);
2691 * Add the given address to the list of foreign addresses
2692 * available for the given peer (check for duplicates).
2694 * @param cls the respective 'struct NeighbourList' to update
2695 * @param tname name of the transport
2696 * @param expiration expiration time
2697 * @param addr the address
2698 * @param addrlen length of the address
2699 * @return GNUNET_OK (always)
2702 add_to_foreign_address_list (void *cls,
2704 struct GNUNET_TIME_Absolute expiration,
2708 struct NeighbourList *n = cls;
2709 struct ForeignAddressList *fal;
2712 GNUNET_STATISTICS_update (stats,
2713 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2717 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2720 #if DEBUG_TRANSPORT_HELLO
2721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2722 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2723 a2s (tname, addr, addrlen),
2725 GNUNET_i2s (&n->id),
2726 expiration.abs_value);
2728 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2731 GNUNET_STATISTICS_update (stats,
2732 gettext_noop ("# previously validated addresses lacking transport"),
2738 fal->expires = GNUNET_TIME_absolute_max (expiration,
2740 schedule_next_ping (fal);
2746 fal->expires = GNUNET_TIME_absolute_max (expiration,
2751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752 "Failed to add new address for `%4s'\n",
2753 GNUNET_i2s (&n->id));
2756 if (fal->validated == GNUNET_NO)
2758 fal->validated = GNUNET_YES;
2759 GNUNET_STATISTICS_update (stats,
2760 gettext_noop ("# peer addresses considered valid"),
2764 if (try == GNUNET_YES)
2766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2767 "Have new addresses, will try to trigger transmissions.\n");
2768 try_transmission_to_peer (n);
2775 * Add addresses in validated HELLO "h" to the set of addresses
2776 * we have for this peer.
2778 * @param cls closure ('struct NeighbourList*')
2779 * @param peer id of the peer, NULL for last call
2780 * @param h hello message for the peer (can be NULL)
2781 * @param err_msg NULL if successful, otherwise contains error message
2784 add_hello_for_peer (void *cls,
2785 const struct GNUNET_PeerIdentity *peer,
2786 const struct GNUNET_HELLO_Message *h,
2787 const char *err_msg)
2789 struct NeighbourList *n = cls;
2791 if (err_msg != NULL)
2793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2794 _("Error in communication with PEERINFO service\n"));
2799 GNUNET_STATISTICS_update (stats,
2800 gettext_noop ("# outstanding peerinfo iterate requests"),
2807 return; /* no HELLO available */
2809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2810 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2814 if (GNUNET_YES != n->public_key_valid)
2816 GNUNET_HELLO_get_key (h, &n->publicKey);
2817 n->public_key_valid = GNUNET_YES;
2819 GNUNET_HELLO_iterate_addresses (h,
2821 &add_to_foreign_address_list,
2827 * Create a fresh entry in our neighbour list for the given peer.
2828 * Will try to transmit our current HELLO to the new neighbour.
2829 * Do not call this function directly, use 'setup_peer_check_blacklist.
2831 * @param peer the peer for which we create the entry
2832 * @param do_hello should we schedule transmitting a HELLO
2833 * @return the new neighbour list entry
2835 static struct NeighbourList *
2836 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2839 struct NeighbourList *n;
2840 struct TransportPlugin *tp;
2841 struct ReadyList *rl;
2844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2845 "Setting up state for neighbour `%4s'\n",
2848 GNUNET_assert (our_hello != NULL);
2849 GNUNET_STATISTICS_update (stats,
2850 gettext_noop ("# active neighbours"),
2853 n = GNUNET_malloc (sizeof (struct NeighbourList));
2854 n->next = neighbours;
2858 GNUNET_TIME_relative_to_absolute
2859 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2860 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2861 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2862 MAX_BANDWIDTH_CARRY_S);
2866 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2868 rl = GNUNET_malloc (sizeof (struct ReadyList));
2870 rl->next = n->plugins;
2873 rl->addresses = NULL;
2877 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2879 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2880 &neighbour_timeout_task, n);
2883 GNUNET_STATISTICS_update (stats,
2884 gettext_noop ("# peerinfo new neighbor iterate requests"),
2887 GNUNET_STATISTICS_update (stats,
2888 gettext_noop ("# outstanding peerinfo iterate requests"),
2891 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2892 GNUNET_TIME_UNIT_FOREVER_REL,
2893 &add_hello_for_peer, n);
2895 GNUNET_STATISTICS_update (stats,
2896 gettext_noop ("# HELLO's sent to new neighbors"),
2899 transmit_to_peer (NULL, NULL, 0,
2900 HELLO_ADDRESS_EXPIRATION,
2901 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2909 * Function called after we have checked if communicating
2910 * with a given peer is acceptable.
2912 * @param cls closure
2913 * @param n NULL if communication is not acceptable
2915 typedef void (*SetupContinuation)(void *cls,
2916 struct NeighbourList *n);
2920 * Information kept for each client registered to perform
2926 * This is a linked list.
2928 struct Blacklisters *next;
2931 * This is a linked list.
2933 struct Blacklisters *prev;
2936 * Client responsible for this entry.
2938 struct GNUNET_SERVER_Client *client;
2941 * Blacklist check that we're currently performing.
2943 struct BlacklistCheck *bc;
2949 * Head of DLL of blacklisting clients.
2951 static struct Blacklisters *bl_head;
2954 * Tail of DLL of blacklisting clients.
2956 static struct Blacklisters *bl_tail;
2960 * Context we use when performing a blacklist check.
2962 struct BlacklistCheck
2966 * This is a linked list.
2968 struct BlacklistCheck *next;
2971 * This is a linked list.
2973 struct BlacklistCheck *prev;
2976 * Peer being checked.
2978 struct GNUNET_PeerIdentity peer;
2981 * Option for setup neighbour afterwards.
2986 * Continuation to call with the result.
2988 SetupContinuation cont;
2996 * Current transmission request handle for this client, or NULL if no
2997 * request is pending.
2999 struct GNUNET_CONNECTION_TransmitHandle *th;
3002 * Our current position in the blacklisters list.
3004 struct Blacklisters *bl_pos;
3007 * Current task performing the check.
3009 GNUNET_SCHEDULER_TaskIdentifier task;
3014 * Head of DLL of active blacklisting queries.
3016 static struct BlacklistCheck *bc_head;
3019 * Tail of DLL of active blacklisting queries.
3021 static struct BlacklistCheck *bc_tail;
3025 * Perform next action in the blacklist check.
3027 * @param cls the 'struct BlacklistCheck*'
3031 do_blacklist_check (void *cls,
3032 const struct GNUNET_SCHEDULER_TaskContext *tc);
3035 * Transmit blacklist query to the client.
3037 * @param cls the 'struct BlacklistCheck'
3038 * @param size number of bytes allowed
3039 * @param buf where to copy the message
3040 * @return number of bytes copied to buf
3043 transmit_blacklist_message (void *cls,
3047 struct BlacklistCheck *bc = cls;
3048 struct Blacklisters *bl;
3049 struct BlacklistMessage bm;
3054 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3055 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3060 bm.header.size = htons (sizeof (struct BlacklistMessage));
3061 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3062 bm.is_allowed = htonl (0);
3064 memcpy (buf, &bm, sizeof (bm));
3065 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3071 * Perform next action in the blacklist check.
3073 * @param cls the 'struct BlacklistCheck*'
3077 do_blacklist_check (void *cls,
3078 const struct GNUNET_SCHEDULER_TaskContext *tc)
3080 struct BlacklistCheck *bc = cls;
3081 struct Blacklisters *bl;
3083 bc->task = GNUNET_SCHEDULER_NO_TASK;
3087 bc->cont (bc->cont_cls,
3088 setup_new_neighbour (&bc->peer, bc->do_hello));
3095 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3096 sizeof (struct BlacklistMessage),
3097 GNUNET_TIME_UNIT_FOREVER_REL,
3098 &transmit_blacklist_message,
3105 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3106 * does not yet exist, check the blacklist. If the blacklist says creating
3107 * one is acceptable, create one and call the continuation; otherwise
3108 * call the continuation with NULL.
3110 * @param peer peer to setup or look up a struct NeighbourList for
3111 * @param do_hello should we also schedule sending our HELLO to the peer
3112 * if this is a new record
3113 * @param cont function to call with the 'struct NeigbhbourList*'
3114 * @param cont_cls closure for cont
3117 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3119 SetupContinuation cont,
3122 struct NeighbourList *n;
3123 struct BlacklistCheck *bc;
3125 n = find_neighbour(peer);
3132 if (bl_head == NULL)
3135 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3137 setup_new_neighbour(peer, do_hello);
3140 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3141 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3143 bc->do_hello = do_hello;
3145 bc->cont_cls = cont_cls;
3146 bc->bl_pos = bl_head;
3147 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3153 * Function called with the result of querying a new blacklister about
3154 * it being allowed (or not) to continue to talk to an existing neighbour.
3156 * @param cls the original 'struct NeighbourList'
3157 * @param n NULL if we need to disconnect
3160 confirm_or_drop_neighbour (void *cls,
3161 struct NeighbourList *n)
3163 struct NeighbourList * orig = cls;
3167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3168 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3169 "confirm_or_drop_neighboUr");
3170 disconnect_neighbour (orig, GNUNET_NO);
3176 * Handle a request to start a blacklist.
3178 * @param cls closure (always NULL)
3179 * @param client identification of the client
3180 * @param message the actual message
3183 handle_blacklist_init (void *cls,
3184 struct GNUNET_SERVER_Client *client,
3185 const struct GNUNET_MessageHeader *message)
3187 struct Blacklisters *bl;
3188 struct BlacklistCheck *bc;
3189 struct NeighbourList *n;
3194 if (bl->client == client)
3197 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3202 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3203 bl->client = client;
3204 GNUNET_SERVER_client_keep (client);
3205 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3206 /* confirm that all existing connections are OK! */
3210 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3211 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3213 bc->do_hello = GNUNET_NO;
3214 bc->cont = &confirm_or_drop_neighbour;
3217 if (n == neighbours) /* all would wait for the same client, no need to
3218 create more than just the first task right now */
3219 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3227 * Handle a request to blacklist a peer.
3229 * @param cls closure (always NULL)
3230 * @param client identification of the client
3231 * @param message the actual message
3234 handle_blacklist_reply (void *cls,
3235 struct GNUNET_SERVER_Client *client,
3236 const struct GNUNET_MessageHeader *message)
3238 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3239 struct Blacklisters *bl;
3240 struct BlacklistCheck *bc;
3243 while ( (bl != NULL) &&
3244 (bl->client != client) )
3248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3253 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3255 bc->cont (bc->cont_cls, NULL);
3256 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3261 bc->bl_pos = bc->bl_pos->next;
3262 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3265 /* check if any other bc's are waiting for this blacklister */
3269 if ( (bc->bl_pos == bl) &&
3270 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3271 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3279 * Send periodic PING messages to a given foreign address.
3281 * @param cls our 'struct PeriodicValidationContext*'
3282 * @param tc task context
3285 send_periodic_ping (void *cls,
3286 const struct GNUNET_SCHEDULER_TaskContext *tc)
3288 struct ForeignAddressList *peer_address = cls;
3289 struct TransportPlugin *tp;
3290 struct ValidationEntry *va;
3291 struct NeighbourList *neighbour;
3292 struct TransportPingMessage ping;
3293 struct CheckAddressExistsClosure caec;
3295 uint16_t hello_size;
3299 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3300 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3302 tp = peer_address->ready_list->plugin;
3303 neighbour = peer_address->ready_list->neighbour;
3304 if (GNUNET_YES != neighbour->public_key_valid)
3306 /* no public key yet, try again later */
3307 schedule_next_ping (peer_address);
3310 caec.addr = peer_address->addr;
3311 caec.addrlen = peer_address->addrlen;
3312 caec.tname = tp->short_name;
3313 caec.session = peer_address->session;
3314 caec.exists = GNUNET_NO;
3315 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3316 &check_address_exists,
3318 if (caec.exists == GNUNET_YES)
3320 /* During validation attempts we will likely trigger the other
3321 peer trying to validate our address which in turn will cause
3322 it to send us its HELLO, so we expect to hit this case rather
3323 frequently. Only print something if we are very verbose. */
3324 #if DEBUG_TRANSPORT > 1
3325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3326 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3327 (peer_address->addr != NULL)
3328 ? a2s (tp->short_name,
3330 peer_address->addrlen)
3333 GNUNET_i2s (&neighbour->id));
3335 schedule_next_ping (peer_address);
3338 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3339 va->transport_name = GNUNET_strdup (tp->short_name);
3340 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3342 va->send_time = GNUNET_TIME_absolute_get();
3343 va->session = peer_address->session;
3344 if (peer_address->addr != NULL)
3346 va->addr = (const void*) &va[1];
3347 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3348 va->addrlen = peer_address->addrlen;
3350 memcpy(&va->publicKey,
3351 &neighbour->publicKey,
3352 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3354 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3355 &timeout_hello_validation,
3357 GNUNET_CONTAINER_multihashmap_put (validation_map,
3358 &neighbour->id.hashPubKey,
3360 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3362 if (peer_address->validated != GNUNET_YES)
3363 hello_size = GNUNET_HELLO_size(our_hello);
3367 tsize = sizeof(struct TransportPingMessage) + hello_size;
3369 if (peer_address->addr != NULL)
3371 slen = strlen (tp->short_name) + 1;
3372 tsize += slen + peer_address->addrlen;
3376 slen = 0; /* make gcc happy */
3378 message_buf = GNUNET_malloc(tsize);
3379 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3380 ping.challenge = htonl(va->challenge);
3381 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3382 if (peer_address->validated != GNUNET_YES)
3384 memcpy(message_buf, our_hello, hello_size);
3387 if (peer_address->addr != NULL)
3389 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3390 peer_address->addrlen +
3392 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3395 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3397 peer_address->addrlen);
3401 ping.header.size = htons(sizeof(struct TransportPingMessage));
3404 memcpy(&message_buf[hello_size],
3406 sizeof(struct TransportPingMessage));
3408 #if DEBUG_TRANSPORT_REVALIDATION
3409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3410 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3411 (peer_address->addr != NULL)
3412 ? a2s (peer_address->plugin->short_name,
3414 peer_address->addrlen)
3417 GNUNET_i2s (&neighbour->id),
3418 "HELLO", hello_size,
3421 if (peer_address->validated != GNUNET_YES)
3422 GNUNET_STATISTICS_update (stats,
3423 gettext_noop ("# PING with HELLO messages sent"),
3427 GNUNET_STATISTICS_update (stats,
3428 gettext_noop ("# PING without HELLO messages sent"),
3431 GNUNET_STATISTICS_update (stats,
3432 gettext_noop ("# PING messages sent for re-validation"),
3435 transmit_to_peer (NULL, peer_address,
3436 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3437 HELLO_VERIFICATION_TIMEOUT,
3439 GNUNET_YES, neighbour);
3440 GNUNET_free(message_buf);
3441 schedule_next_ping (peer_address);
3446 * Schedule the job that will cause us to send a PING to the
3447 * foreign address to evaluate its validity and latency.
3449 * @param fal address to PING
3452 schedule_next_ping (struct ForeignAddressList *fal)
3454 struct GNUNET_TIME_Relative delay;
3456 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3458 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3459 delay.rel_value /= 2; /* do before expiration */
3460 delay = GNUNET_TIME_relative_min (delay,
3461 LATENCY_EVALUATION_MAX_DELAY);
3462 if (GNUNET_YES != fal->estimated)
3464 delay = GNUNET_TIME_UNIT_ZERO;
3465 fal->estimated = GNUNET_YES;
3467 if (GNUNET_YES == fal->connected)
3469 delay = GNUNET_TIME_relative_min (delay,
3470 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3472 /* FIXME: also adjust delay based on how close the last
3473 observed latency is to the latency of the best alternative */
3474 /* bound how fast we can go */
3475 delay = GNUNET_TIME_relative_max (delay,
3476 GNUNET_TIME_UNIT_SECONDS);
3477 /* randomize a bit (to avoid doing all at the same time) */
3478 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3479 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3480 &send_periodic_ping,
3488 * Function that will be called if we receive some payload
3489 * from another peer.
3491 * @param message the payload
3492 * @param n peer who claimed to be the sender
3495 handle_payload_message (const struct GNUNET_MessageHeader *message,
3496 struct NeighbourList *n)
3498 struct InboundMessage *im;
3499 struct TransportClient *cpos;
3502 msize = ntohs (message->size);
3503 if (n->received_pong == GNUNET_NO)
3505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3506 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3507 ntohs (message->type),
3508 ntohs (message->size),
3509 GNUNET_i2s (&n->id));
3510 GNUNET_free_non_null (n->pre_connect_message_buffer);
3511 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3512 memcpy (n->pre_connect_message_buffer, message, msize);
3517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3518 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3519 ntohs (message->type),
3520 ntohs (message->size),
3521 GNUNET_i2s (&n->id));
3523 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3526 n->quota_violation_count++;
3528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3529 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3530 n->in_tracker.available_bytes_per_s__,
3531 n->quota_violation_count);
3533 /* Discount 32k per violation */
3534 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3539 if (n->quota_violation_count > 0)
3541 /* try to add 32k back */
3542 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3544 n->quota_violation_count--;
3547 GNUNET_STATISTICS_update (stats,
3548 gettext_noop ("# payload received from other peers"),
3551 /* transmit message to all clients */
3552 uint32_t ats_count = 2;
3553 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3554 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3557 im = GNUNET_malloc (size);
3558 im->header.size = htons (size);
3559 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3561 im->ats_count = htonl(ats_count);
3562 /* Setting ATS data */
3563 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3564 (&(im->ats))[0].value = htonl (n->distance);
3565 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3566 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3567 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3568 (&(im->ats))[ats_count].value = htonl (0);
3570 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3572 while (cpos != NULL)
3574 transmit_to_client (cpos, &im->header, GNUNET_YES);
3582 * Iterator over hash map entries. Checks if the given validation
3583 * entry is for the same challenge as what is given in the PONG.
3585 * @param cls the 'struct TransportPongMessage*'
3586 * @param key peer identity
3587 * @param value value in the hash map ('struct ValidationEntry')
3588 * @return GNUNET_YES if we should continue to
3589 * iterate (mismatch), GNUNET_NO if not (entry matched)
3592 check_pending_validation (void *cls,
3593 const GNUNET_HashCode * key,
3596 const struct TransportPongMessage *pong = cls;
3597 struct ValidationEntry *ve = value;
3598 struct AddValidatedAddressContext avac;
3599 unsigned int challenge = ntohl(pong->challenge);
3600 struct GNUNET_HELLO_Message *hello;
3601 struct GNUNET_PeerIdentity target;
3602 struct NeighbourList *n;
3603 struct ForeignAddressList *fal;
3604 struct OwnAddressList *oal;
3605 struct TransportPlugin *tp;
3606 struct GNUNET_MessageHeader *prem;
3612 ps = ntohs (pong->header.size);
3613 if (ps < sizeof (struct TransportPongMessage))
3615 GNUNET_break_op (0);
3618 addr = (const char*) &pong[1];
3619 slen = strlen (ve->transport_name) + 1;
3620 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3621 (ve->challenge != challenge) ||
3622 (addr[slen-1] != '\0') ||
3623 (0 != strcmp (addr, ve->transport_name)) ||
3624 (ntohl (pong->purpose.size)
3625 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3627 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3628 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3633 alen = ps - sizeof (struct TransportPongMessage) - slen;
3634 switch (ntohl (pong->purpose.purpose))
3636 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3637 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3638 (0 != memcmp (&addr[slen],
3642 return GNUNET_YES; /* different entry, keep trying! */
3644 if (0 != memcmp (&pong->pid,
3646 sizeof (struct GNUNET_PeerIdentity)))
3648 GNUNET_break_op (0);
3652 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3657 GNUNET_break_op (0);
3662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3663 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3665 a2s (ve->transport_name,
3666 (const struct sockaddr *) ve->addr,
3668 ve->transport_name);
3671 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3672 if (0 != memcmp (&pong->pid,
3674 sizeof (struct GNUNET_PeerIdentity)))
3676 GNUNET_break_op (0);
3679 if (ve->addrlen != 0)
3681 /* must have been for a different validation entry */
3684 tp = find_transport (ve->transport_name);
3690 oal = tp->addresses;
3693 if ( (oal->addrlen == alen) &&
3694 (0 == memcmp (&oal[1],
3702 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3703 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3704 a2s (ve->transport_name,
3710 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3715 GNUNET_break_op (0);
3720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3721 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3723 a2s (ve->transport_name,
3726 ve->transport_name);
3730 GNUNET_break_op (0);
3733 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3735 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3736 _("Received expired signature. Check system time.\n"));
3739 GNUNET_STATISTICS_update (stats,
3740 gettext_noop ("# address validation successes"),
3743 /* create the updated HELLO */
3744 GNUNET_CRYPTO_hash (&ve->publicKey,
3745 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3746 &target.hashPubKey);
3747 if (ve->addr != NULL)
3749 avac.done = GNUNET_NO;
3751 hello = GNUNET_HELLO_create (&ve->publicKey,
3752 &add_validated_address,
3754 GNUNET_PEERINFO_add_peer (peerinfo,
3756 GNUNET_free (hello);
3758 n = find_neighbour (&target);
3761 n->publicKey = ve->publicKey;
3762 n->public_key_valid = GNUNET_YES;
3763 fal = add_peer_address (n,
3768 GNUNET_assert (fal != NULL);
3769 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3770 fal->validated = GNUNET_YES;
3771 mark_address_connected (fal);
3772 GNUNET_STATISTICS_update (stats,
3773 gettext_noop ("# peer addresses considered valid"),
3776 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3777 schedule_next_ping (fal);
3778 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3779 n->latency = fal->latency;
3781 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3783 n->distance = fal->distance;
3784 if (GNUNET_NO == n->received_pong)
3786 n->received_pong = GNUNET_YES;
3788 notify_clients_connect (&target, n->latency, n->distance);
3789 if (NULL != (prem = n->pre_connect_message_buffer))
3791 n->pre_connect_message_buffer = NULL;
3792 handle_payload_message (prem, n);
3796 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3798 GNUNET_SCHEDULER_cancel (n->retry_task);
3799 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3800 try_transmission_to_peer (n);
3804 /* clean up validation entry */
3805 GNUNET_assert (GNUNET_YES ==
3806 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3809 abort_validation (NULL, NULL, ve);
3815 * Function that will be called if we receive a validation
3816 * of an address challenge that we transmitted to another
3817 * peer. Note that the validation should only be considered
3818 * acceptable if the challenge matches AND if the sender
3819 * address is at least a plausible address for this peer
3820 * (otherwise we may be seeing a MiM attack).
3822 * @param cls closure
3823 * @param message the pong message
3824 * @param peer who responded to our challenge
3825 * @param sender_address string describing our sender address (as observed
3826 * by the other peer in binary format)
3827 * @param sender_address_len number of bytes in 'sender_address'
3830 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3831 const struct GNUNET_PeerIdentity *peer,
3832 const char *sender_address,
3833 size_t sender_address_len)
3835 #if DEBUG_TRANSPORT > 1
3836 /* we get tons of these that just get discarded, only log
3837 if we are quite verbose */
3838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3839 "Receiving `%s' message from `%4s'.\n", "PONG",
3842 GNUNET_STATISTICS_update (stats,
3843 gettext_noop ("# PONG messages received"),
3846 if (GNUNET_SYSERR !=
3847 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3849 &check_pending_validation,
3852 /* This is *expected* to happen a lot since we send
3853 PONGs to *all* known addresses of the sender of
3854 the PING, so most likely we get multiple PONGs
3855 per PING, and all but the first PONG will end up
3856 here. So really we should not print anything here
3857 unless we want to be very, very verbose... */
3858 #if DEBUG_TRANSPORT > 2
3859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3860 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3872 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3874 * @param cls the 'struct ValidationEntry*'
3875 * @param neighbour neighbour to validate, NULL if validation failed
3878 transmit_hello_and_ping (void *cls,
3879 struct NeighbourList *neighbour)
3881 struct ValidationEntry *va = cls;
3882 struct ForeignAddressList *peer_address;
3883 struct TransportPingMessage ping;
3884 uint16_t hello_size;
3887 struct GNUNET_PeerIdentity id;
3890 GNUNET_CRYPTO_hash (&va->publicKey,
3891 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3893 if (neighbour == NULL)
3895 /* FIXME: stats... */
3896 GNUNET_break (GNUNET_OK ==
3897 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3900 abort_validation (NULL, NULL, va);
3903 neighbour->publicKey = va->publicKey;
3904 neighbour->public_key_valid = GNUNET_YES;
3905 peer_address = add_peer_address (neighbour,
3906 va->transport_name, NULL,
3907 (const void*) &va[1],
3909 if (peer_address == NULL)
3911 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3912 "Failed to add peer `%4s' for plugin `%s'\n",
3913 GNUNET_i2s (&neighbour->id),
3914 va->transport_name);
3915 GNUNET_break (GNUNET_OK ==
3916 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3919 abort_validation (NULL, NULL, va);
3922 hello_size = GNUNET_HELLO_size(our_hello);
3923 slen = strlen(va->transport_name) + 1;
3924 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3925 message_buf = GNUNET_malloc(tsize);
3926 ping.challenge = htonl(va->challenge);
3927 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3928 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3929 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3930 memcpy(message_buf, our_hello, hello_size);
3931 memcpy(&message_buf[hello_size],
3933 sizeof(struct TransportPingMessage));
3934 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3937 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3942 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3945 : a2s (va->transport_name,
3946 (const void*) &va[1], va->addrlen),
3948 GNUNET_i2s (&neighbour->id),
3949 "HELLO", hello_size,
3950 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3953 GNUNET_STATISTICS_update (stats,
3954 gettext_noop ("# PING messages sent for initial validation"),
3957 transmit_to_peer (NULL, peer_address,
3958 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3959 HELLO_VERIFICATION_TIMEOUT,
3961 GNUNET_YES, neighbour);
3962 GNUNET_free(message_buf);
3967 * Check if the given address is already being validated; if not,
3968 * append the given address to the list of entries that are being be
3969 * validated and initiate validation.
3971 * @param cls closure ('struct CheckHelloValidatedContext *')
3972 * @param tname name of the transport
3973 * @param expiration expiration time
3974 * @param addr the address
3975 * @param addrlen length of the address
3976 * @return GNUNET_OK (always)
3979 run_validation (void *cls,
3981 struct GNUNET_TIME_Absolute expiration,
3985 struct CheckHelloValidatedContext *chvc = cls;
3986 struct GNUNET_PeerIdentity id;
3987 struct TransportPlugin *tp;
3988 struct ValidationEntry *va;
3989 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3990 struct CheckAddressExistsClosure caec;
3991 struct OwnAddressList *oal;
3993 GNUNET_assert (addr != NULL);
3995 GNUNET_STATISTICS_update (stats,
3996 gettext_noop ("# peer addresses scheduled for validation"),
3999 tp = find_transport (tname);
4002 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4003 GNUNET_ERROR_TYPE_BULK,
4005 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4007 GNUNET_STATISTICS_update (stats,
4008 gettext_noop ("# peer addresses not validated (plugin not available)"),
4013 /* check if this is one of our own addresses */
4014 oal = tp->addresses;
4017 if ( (oal->addrlen == addrlen) &&
4018 (0 == memcmp (&oal[1],
4022 /* not plausible, this address is equivalent to our own address! */
4023 GNUNET_STATISTICS_update (stats,
4024 gettext_noop ("# peer addresses not validated (loopback)"),
4031 GNUNET_HELLO_get_key (chvc->hello, &pk);
4032 GNUNET_CRYPTO_hash (&pk,
4034 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4037 if (is_blacklisted(&id, tp))
4040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4041 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4049 caec.addrlen = addrlen;
4050 caec.session = NULL;
4052 caec.exists = GNUNET_NO;
4053 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4054 &check_address_exists,
4056 if (caec.exists == GNUNET_YES)
4058 /* During validation attempts we will likely trigger the other
4059 peer trying to validate our address which in turn will cause
4060 it to send us its HELLO, so we expect to hit this case rather
4061 frequently. Only print something if we are very verbose. */
4062 #if DEBUG_TRANSPORT > 1
4063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4064 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4065 a2s (tname, addr, addrlen),
4069 GNUNET_STATISTICS_update (stats,
4070 gettext_noop ("# peer addresses not validated (in progress)"),
4075 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4078 va->transport_name = GNUNET_strdup (tname);
4079 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4081 va->send_time = GNUNET_TIME_absolute_get();
4082 va->addr = (const void*) &va[1];
4083 memcpy (&va[1], addr, addrlen);
4084 va->addrlen = addrlen;
4085 GNUNET_HELLO_get_key (chvc->hello,
4087 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4088 &timeout_hello_validation,
4090 GNUNET_CONTAINER_multihashmap_put (validation_map,
4093 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4094 setup_peer_check_blacklist (&id, GNUNET_NO,
4095 &transmit_hello_and_ping,
4102 * Check if addresses in validated hello "h" overlap with
4103 * those in "chvc->hello" and validate the rest.
4105 * @param cls closure
4106 * @param peer id of the peer, NULL for last call
4107 * @param h hello message for the peer (can be NULL)
4108 * @param err_msg NULL if successful, otherwise contains error message
4111 check_hello_validated (void *cls,
4112 const struct GNUNET_PeerIdentity *peer,
4113 const struct GNUNET_HELLO_Message *h,
4114 const char *err_msg)
4116 struct CheckHelloValidatedContext *chvc = cls;
4117 struct GNUNET_HELLO_Message *plain_hello;
4118 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4119 struct GNUNET_PeerIdentity target;
4120 struct NeighbourList *n;
4122 if (err_msg != NULL)
4124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4125 _("Error in communication with PEERINFO service\n"));
4131 GNUNET_STATISTICS_update (stats,
4132 gettext_noop ("# outstanding peerinfo iterate requests"),
4136 if (GNUNET_NO == chvc->hello_known)
4138 /* notify PEERINFO about the peer now, so that we at least
4139 have the public key if some other component needs it */
4140 GNUNET_HELLO_get_key (chvc->hello, &pk);
4141 GNUNET_CRYPTO_hash (&pk,
4142 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4143 &target.hashPubKey);
4144 plain_hello = GNUNET_HELLO_create (&pk,
4147 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4148 GNUNET_free (plain_hello);
4149 #if DEBUG_TRANSPORT_HELLO
4150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4151 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4153 GNUNET_i2s (&target));
4155 GNUNET_STATISTICS_update (stats,
4156 gettext_noop ("# new HELLOs requiring full validation"),
4159 GNUNET_HELLO_iterate_addresses (chvc->hello,
4166 GNUNET_STATISTICS_update (stats,
4167 gettext_noop ("# duplicate HELLO (peer known)"),
4172 if (chvc->ve_count == 0)
4174 GNUNET_CONTAINER_DLL_remove (chvc_head,
4183 #if DEBUG_TRANSPORT_HELLO
4184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4185 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4189 chvc->hello_known = GNUNET_YES;
4190 n = find_neighbour (peer);
4193 #if DEBUG_TRANSPORT_HELLO
4194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4195 "Calling hello_iterate_addresses for %s!\n",
4198 GNUNET_HELLO_iterate_addresses (h,
4200 &add_to_foreign_address_list,
4202 try_transmission_to_peer (n);
4206 #if DEBUG_TRANSPORT_HELLO
4207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4208 "No existing neighbor record for %s!\n",
4211 GNUNET_STATISTICS_update (stats,
4212 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4216 GNUNET_STATISTICS_update (stats,
4217 gettext_noop ("# HELLO validations (update case)"),
4220 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4222 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4229 * Process HELLO-message.
4231 * @param plugin transport involved, may be NULL
4232 * @param message the actual message
4233 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4236 process_hello (struct TransportPlugin *plugin,
4237 const struct GNUNET_MessageHeader *message)
4240 struct GNUNET_PeerIdentity target;
4241 const struct GNUNET_HELLO_Message *hello;
4242 struct CheckHelloValidatedContext *chvc;
4243 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4244 #if DEBUG_TRANSPORT_HELLO > 2
4247 hsize = ntohs (message->size);
4248 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4249 (hsize < sizeof (struct GNUNET_MessageHeader)))
4252 return GNUNET_SYSERR;
4254 GNUNET_STATISTICS_update (stats,
4255 gettext_noop ("# HELLOs received for validation"),
4259 /* first, check if load is too high */
4260 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4262 GNUNET_STATISTICS_update (stats,
4263 gettext_noop ("# HELLOs ignored due to high load"),
4266 #if DEBUG_TRANSPORT_HELLO
4267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4268 "Ignoring `%s' for `%4s', load too high.\n",
4270 GNUNET_i2s (&target));
4274 hello = (const struct GNUNET_HELLO_Message *) message;
4275 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4277 #if DEBUG_TRANSPORT_HELLO
4278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4279 "Unable to get public key from `%s' for `%4s'!\n",
4281 GNUNET_i2s (&target));
4283 GNUNET_break_op (0);
4284 return GNUNET_SYSERR;
4287 GNUNET_CRYPTO_hash (&publicKey,
4288 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4289 &target.hashPubKey);
4291 #if DEBUG_TRANSPORT_HELLO
4292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4293 "Received `%s' message for `%4s'\n",
4295 GNUNET_i2s (&target));
4298 if (0 == memcmp (&my_identity,
4300 sizeof (struct GNUNET_PeerIdentity)))
4302 GNUNET_STATISTICS_update (stats,
4303 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4309 while (NULL != chvc)
4311 if (GNUNET_HELLO_equals (hello,
4313 GNUNET_TIME_absolute_get ()).abs_value > 0)
4315 #if DEBUG_TRANSPORT_HELLO > 2
4316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4317 "Received duplicate `%s' message for `%4s'; ignored\n",
4319 GNUNET_i2s (&target));
4321 return GNUNET_OK; /* validation already pending */
4323 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4324 GNUNET_break (0 != memcmp (hello, chvc->hello,
4325 GNUNET_HELLO_size(hello)));
4330 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4331 if ((NULL != temp_neighbor))
4333 fprintf(stderr, "Already know peer, ignoring hello\n");
4338 #if DEBUG_TRANSPORT_HELLO > 2
4341 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4343 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4346 GNUNET_i2s (&target),
4348 GNUNET_HELLO_size(hello));
4352 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4354 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4355 memcpy (&chvc[1], hello, hsize);
4356 GNUNET_CONTAINER_DLL_insert (chvc_head,
4359 /* finally, check if HELLO was previously validated
4360 (continuation will then schedule actual validation) */
4361 GNUNET_STATISTICS_update (stats,
4362 gettext_noop ("# peerinfo process hello iterate requests"),
4365 GNUNET_STATISTICS_update (stats,
4366 gettext_noop ("# outstanding peerinfo iterate requests"),
4369 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4371 HELLO_VERIFICATION_TIMEOUT,
4372 &check_hello_validated, chvc);
4378 * The peer specified by the given neighbour has timed-out or a plugin
4379 * has disconnected. We may either need to do nothing (other plugins
4380 * still up), or trigger a full disconnect and clean up. This
4381 * function updates our state and does the necessary notifications.
4382 * Also notifies our clients that the neighbour is now officially
4385 * @param n the neighbour list entry for the peer
4386 * @param check GNUNET_YES to check if ALL addresses for this peer
4387 * are gone, GNUNET_NO to force a disconnect of the peer
4388 * regardless of whether other addresses exist.
4391 disconnect_neighbour (struct NeighbourList *n, int check)
4393 struct ReadyList *rpos;
4394 struct NeighbourList *npos;
4395 struct NeighbourList *nprev;
4396 struct MessageQueue *mq;
4397 struct ForeignAddressList *peer_addresses;
4398 struct ForeignAddressList *peer_pos;
4400 if (GNUNET_YES == check)
4403 while (NULL != rpos)
4405 peer_addresses = rpos->addresses;
4406 while (peer_addresses != NULL)
4408 if (GNUNET_YES == peer_addresses->connected)
4410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4411 "NOT Disconnecting from `%4s', still have live addresses!\n",
4412 GNUNET_i2s (&n->id));
4413 return; /* still connected */
4415 peer_addresses = peer_addresses->next;
4421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4422 "Disconnecting from `%4s'\n",
4423 GNUNET_i2s (&n->id));
4425 /* remove n from neighbours list */
4428 while ((npos != NULL) && (npos != n))
4433 GNUNET_assert (npos != NULL);
4435 neighbours = n->next;
4437 nprev->next = n->next;
4439 /* notify all clients about disconnect */
4440 if (GNUNET_YES == n->received_pong)
4441 notify_clients_disconnect (&n->id);
4443 /* clean up all plugins, cancel connections and pending transmissions */
4444 while (NULL != (rpos = n->plugins))
4446 n->plugins = rpos->next;
4447 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4448 while (rpos->addresses != NULL)
4450 peer_pos = rpos->addresses;
4451 rpos->addresses = peer_pos->next;
4452 if (peer_pos->connected == GNUNET_YES)
4453 GNUNET_STATISTICS_update (stats,
4454 gettext_noop ("# connected addresses"),
4457 if (GNUNET_YES == peer_pos->validated)
4458 GNUNET_STATISTICS_update (stats,
4459 gettext_noop ("# peer addresses considered valid"),
4462 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4464 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4465 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4467 GNUNET_free(peer_pos);
4472 /* free all messages on the queue */
4473 while (NULL != (mq = n->messages_head))
4475 GNUNET_STATISTICS_update (stats,
4476 gettext_noop ("# bytes in message queue for other peers"),
4477 - (int64_t) mq->message_buf_size,
4479 GNUNET_STATISTICS_update (stats,
4480 gettext_noop ("# bytes discarded due to disconnect"),
4481 mq->message_buf_size,
4483 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4486 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4488 sizeof(struct GNUNET_PeerIdentity)));
4491 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4493 GNUNET_SCHEDULER_cancel (n->timeout_task);
4494 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4496 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4498 GNUNET_SCHEDULER_cancel (n->retry_task);
4499 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4501 if (n->piter != NULL)
4503 GNUNET_PEERINFO_iterate_cancel (n->piter);
4504 GNUNET_STATISTICS_update (stats,
4505 gettext_noop ("# outstanding peerinfo iterate requests"),
4510 /* finally, free n itself */
4511 GNUNET_STATISTICS_update (stats,
4512 gettext_noop ("# active neighbours"),
4515 GNUNET_free_non_null (n->pre_connect_message_buffer);
4521 * We have received a PING message from someone. Need to send a PONG message
4522 * in response to the peer by any means necessary.
4525 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4526 const struct GNUNET_PeerIdentity *peer,
4527 struct Session *session,
4528 const char *sender_address,
4529 uint16_t sender_address_len)
4531 struct TransportPlugin *plugin = cls;
4532 struct SessionHeader *session_header = (struct SessionHeader*) session;
4533 struct TransportPingMessage *ping;
4534 struct TransportPongMessage *pong;
4535 struct NeighbourList *n;
4536 struct ReadyList *rl;
4537 struct ForeignAddressList *fal;
4538 struct OwnAddressList *oal;
4543 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4545 GNUNET_break_op (0);
4546 return GNUNET_SYSERR;
4549 ping = (struct TransportPingMessage *) message;
4550 if (0 != memcmp (&ping->target,
4551 plugin->env.my_identity,
4552 sizeof (struct GNUNET_PeerIdentity)))
4554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4555 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4557 (sender_address != NULL)
4558 ? a2s (plugin->short_name,
4559 (const struct sockaddr *)sender_address,
4562 GNUNET_i2s (&ping->target));
4563 return GNUNET_SYSERR;
4566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4567 "Processing `%s' from `%s'\n",
4569 (sender_address != NULL)
4570 ? a2s (plugin->short_name,
4571 (const struct sockaddr *)sender_address,
4575 GNUNET_STATISTICS_update (stats,
4576 gettext_noop ("# PING messages received"),
4579 addr = (const char*) &ping[1];
4580 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4581 slen = strlen (plugin->short_name) + 1;
4584 /* peer wants to confirm that we have an outbound connection to him */
4585 if (session == NULL)
4587 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4588 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4590 return GNUNET_SYSERR;
4592 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4593 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4594 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4595 pong->purpose.size =
4596 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4598 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4599 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4600 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4601 pong->challenge = ping->challenge;
4602 pong->addrlen = htonl(sender_address_len + slen);
4605 sizeof(struct GNUNET_PeerIdentity));
4609 if ((sender_address!=NULL) && (sender_address_len > 0))
4610 memcpy (&((char*)&pong[1])[slen],
4612 sender_address_len);
4613 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4615 /* create / update cached sig */
4617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4618 "Creating PONG signature to indicate active connection.\n");
4620 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4621 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4622 GNUNET_assert (GNUNET_OK ==
4623 GNUNET_CRYPTO_rsa_sign (my_private_key,
4625 &session_header->pong_signature));
4629 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4631 memcpy (&pong->signature,
4632 &session_header->pong_signature,
4633 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4639 /* peer wants to confirm that this is one of our addresses */
4643 plugin->api->check_address (plugin->api->cls,
4647 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4648 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4649 a2s (plugin->short_name,
4654 oal = plugin->addresses;
4657 if ( (oal->addrlen == alen) &&
4664 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4665 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4666 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4667 pong->purpose.size =
4668 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4670 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4671 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4672 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4673 pong->challenge = ping->challenge;
4674 pong->addrlen = htonl(alen + slen);
4677 sizeof(struct GNUNET_PeerIdentity));
4678 memcpy (&pong[1], plugin->short_name, slen);
4679 memcpy (&((char*)&pong[1])[slen], addr, alen);
4680 if ( (oal != NULL) &&
4681 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4683 /* create / update cached sig */
4685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4686 "Creating PONG signature to indicate ownership.\n");
4688 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4689 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4690 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4691 GNUNET_assert (GNUNET_OK ==
4692 GNUNET_CRYPTO_rsa_sign (my_private_key,
4694 &oal->pong_signature));
4695 memcpy (&pong->signature,
4696 &oal->pong_signature,
4697 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4699 else if (oal == NULL)
4701 /* not using cache (typically DV-only) */
4702 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4703 GNUNET_assert (GNUNET_OK ==
4704 GNUNET_CRYPTO_rsa_sign (my_private_key,
4710 /* can used cached version */
4711 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4712 memcpy (&pong->signature,
4713 &oal->pong_signature,
4714 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4717 n = find_neighbour(peer);
4718 GNUNET_assert (n != NULL);
4719 /* first try reliable response transmission */
4723 fal = rl->addresses;
4726 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4729 ntohs (pong->header.size),
4730 TRANSPORT_PONG_PRIORITY,
4731 HELLO_VERIFICATION_TIMEOUT,
4739 GNUNET_STATISTICS_update (stats,
4740 gettext_noop ("# PONGs unicast via reliable transport"),
4750 /* no reliable method found, do multicast */
4751 GNUNET_STATISTICS_update (stats,
4752 gettext_noop ("# PONGs multicast to all available addresses"),
4758 fal = rl->addresses;
4761 transmit_to_peer(NULL, fal,
4762 TRANSPORT_PONG_PRIORITY,
4763 HELLO_VERIFICATION_TIMEOUT,
4765 ntohs(pong->header.size),
4778 * Function called by the plugin for each received message.
4779 * Update data volumes, possibly notify plugins about
4780 * reducing the rate at which they read from the socket
4781 * and generally forward to our receive callback.
4783 * @param cls the "struct TransportPlugin *" we gave to the plugin
4784 * @param peer (claimed) identity of the other peer
4785 * @param message the message, NULL if we only care about
4786 * learning about the delay until we should receive again
4787 * @param ats_data information for automatic transport selection
4788 * @param ats_count number of elements in ats not including 0-terminator
4789 * @param session identifier used for this session (can be NULL)
4790 * @param sender_address binary address of the sender (if observed)
4791 * @param sender_address_len number of bytes in sender_address
4792 * @return how long in ms the plugin should wait until receiving more data
4793 * (plugins that do not support this, can ignore the return value)
4795 static struct GNUNET_TIME_Relative
4796 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4797 const struct GNUNET_MessageHeader *message,
4798 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4800 struct Session *session,
4801 const char *sender_address,
4802 uint16_t sender_address_len)
4804 struct TransportPlugin *plugin = cls;
4805 struct ReadyList *service_context;
4806 struct ForeignAddressList *peer_address;
4808 struct NeighbourList *n;
4809 struct GNUNET_TIME_Relative ret;
4810 if (is_blacklisted (peer, plugin))
4811 return GNUNET_TIME_UNIT_FOREVER_REL;
4815 n = find_neighbour (peer);
4817 n = setup_new_neighbour (peer, GNUNET_YES);
4818 service_context = n->plugins;
4819 while ((service_context != NULL) && (plugin != service_context->plugin))
4820 service_context = service_context->next;
4821 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4822 peer_address = NULL;
4824 for (c=0; c<ats_count; c++)
4826 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4828 distance = ntohl(ats_data[c].value);
4831 /* notify ATS about incoming data */
4832 ats_notify_ats_data(ats, peer, ats_data);
4835 if (message != NULL)
4837 if ( (session != NULL) ||
4838 (sender_address != NULL) )
4839 peer_address = add_peer_address (n,
4843 sender_address_len);
4844 if (peer_address != NULL)
4846 peer_address->distance = distance;
4847 if (GNUNET_YES == peer_address->validated)
4848 mark_address_connected (peer_address);
4849 peer_address->timeout
4851 GNUNET_TIME_relative_to_absolute
4852 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4853 schedule_next_ping (peer_address);
4855 /* update traffic received amount ... */
4856 msize = ntohs (message->size);
4857 GNUNET_STATISTICS_update (stats,
4858 gettext_noop ("# bytes received from other peers"),
4861 n->distance = distance;
4863 GNUNET_TIME_relative_to_absolute
4864 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4865 GNUNET_SCHEDULER_cancel (n->timeout_task);
4867 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4868 &neighbour_timeout_task, n);
4869 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4871 /* dropping message due to frequent inbound volume violations! */
4872 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4873 GNUNET_ERROR_TYPE_BULK,
4875 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4876 n->in_tracker.available_bytes_per_s__,
4877 n->quota_violation_count);
4878 GNUNET_STATISTICS_update (stats,
4879 gettext_noop ("# bandwidth quota violations by other peers"),
4882 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4887 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4888 ntohs (message->type),
4889 ntohs (message->size),
4892 switch (ntohs (message->type))
4894 case GNUNET_MESSAGE_TYPE_HELLO:
4895 GNUNET_STATISTICS_update (stats,
4896 gettext_noop ("# HELLO messages received from other peers"),
4899 process_hello (plugin, message);
4901 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4902 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4904 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4905 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4908 handle_payload_message (message, n);
4912 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4913 if (ret.rel_value > 0)
4915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4916 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4917 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4918 (unsigned int) n->in_tracker.available_bytes_per_s__,
4919 (unsigned long long) ret.rel_value);
4920 GNUNET_STATISTICS_update (stats,
4921 gettext_noop ("# ms throttling suggested"),
4922 (int64_t) ret.rel_value,
4929 * Handle START-message. This is the first message sent to us
4930 * by any client which causes us to add it to our list.
4932 * @param cls closure (always NULL)
4933 * @param client identification of the client
4934 * @param message the actual message
4937 handle_start (void *cls,
4938 struct GNUNET_SERVER_Client *client,
4939 const struct GNUNET_MessageHeader *message)
4941 const struct StartMessage *start;
4942 struct TransportClient *c;
4943 struct ConnectInfoMessage * cim;
4944 struct NeighbourList *n;
4948 start = (const struct StartMessage*) message;
4950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4951 "Received `%s' request from client\n", "START");
4956 if (c->client == client)
4958 /* client already on our list! */
4960 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4965 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4966 (0 != memcmp (&start->self,
4968 sizeof (struct GNUNET_PeerIdentity))) )
4970 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4971 _("Rejecting control connection from peer `%s', which is not me!\n"),
4972 GNUNET_i2s (&start->self));
4973 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4976 c = GNUNET_malloc (sizeof (struct TransportClient));
4980 if (our_hello != NULL)
4983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4984 "Sending our own `%s' to new client\n", "HELLO");
4986 transmit_to_client (c,
4987 (const struct GNUNET_MessageHeader *) our_hello,
4989 /* tell new client about all existing connections */
4991 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4992 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4996 cim = GNUNET_malloc (size);
4997 cim->header.size = htons (size);
4998 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4999 cim->ats_count = htonl(ats_count);
5000 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5001 (&(cim->ats))[2].value = htonl (0);
5005 if (GNUNET_YES == n->received_pong)
5007 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5008 (&(cim->ats))[0].value = htonl (n->distance);
5009 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5010 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5012 transmit_to_client (c, &cim->header, GNUNET_NO);
5018 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5023 * Handle HELLO-message.
5025 * @param cls closure (always NULL)
5026 * @param client identification of the client
5027 * @param message the actual message
5030 handle_hello (void *cls,
5031 struct GNUNET_SERVER_Client *client,
5032 const struct GNUNET_MessageHeader *message)
5036 GNUNET_STATISTICS_update (stats,
5037 gettext_noop ("# HELLOs received from clients"),
5040 ret = process_hello (NULL, message);
5041 GNUNET_SERVER_receive_done (client, ret);
5046 * Closure for 'transmit_client_message'; followed by
5047 * 'msize' bytes of the actual message.
5049 struct TransmitClientMessageContext
5052 * Client on whom's behalf we are sending.
5054 struct GNUNET_SERVER_Client *client;
5057 * Timeout for the transmission.
5059 struct GNUNET_TIME_Absolute timeout;
5067 * Size of the message in bytes.
5074 * Schedule transmission of a message we got from a client to a peer.
5076 * @param cls the 'struct TransmitClientMessageContext*'
5077 * @param n destination, or NULL on error (in that case, drop the message)
5080 transmit_client_message (void *cls,
5081 struct NeighbourList *n)
5083 struct TransmitClientMessageContext *tcmc = cls;
5084 struct TransportClient *tc;
5087 while ((tc != NULL) && (tc->client != tcmc->client))
5092 transmit_to_peer (tc, NULL, tcmc->priority,
5093 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5095 tcmc->msize, GNUNET_NO, n);
5097 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5098 GNUNET_SERVER_client_drop (tcmc->client);
5104 * Handle SEND-message.
5106 * @param cls closure (always NULL)
5107 * @param client identification of the client
5108 * @param message the actual message
5111 handle_send (void *cls,
5112 struct GNUNET_SERVER_Client *client,
5113 const struct GNUNET_MessageHeader *message)
5115 const struct OutboundMessage *obm;
5116 const struct GNUNET_MessageHeader *obmm;
5117 struct TransmitClientMessageContext *tcmc;
5121 size = ntohs (message->size);
5123 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5126 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5129 GNUNET_STATISTICS_update (stats,
5130 gettext_noop ("# payload received for other peers"),
5133 obm = (const struct OutboundMessage *) message;
5134 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5135 msize = size - sizeof (struct OutboundMessage);
5137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5138 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5139 "SEND", GNUNET_i2s (&obm->peer),
5143 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5144 tcmc->client = client;
5145 tcmc->priority = ntohl (obm->priority);
5146 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5147 tcmc->msize = msize;
5148 /* FIXME: this memcpy can be up to 7% of our total runtime */
5149 memcpy (&tcmc[1], obmm, msize);
5150 GNUNET_SERVER_client_keep (client);
5151 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5152 &transmit_client_message,
5158 * Handle request connect message
5160 * @param cls closure (always NULL)
5161 * @param client identification of the client
5162 * @param message the actual message
5165 handle_request_connect (void *cls,
5166 struct GNUNET_SERVER_Client *client,
5167 const struct GNUNET_MessageHeader *message)
5169 const struct TransportRequestConnectMessage *trcm =
5170 (const struct TransportRequestConnectMessage *) message;
5172 GNUNET_STATISTICS_update (stats,
5173 gettext_noop ("# REQUEST CONNECT messages received"),
5176 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5177 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5179 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5183 * Handle SET_QUOTA-message.
5185 * @param cls closure (always NULL)
5186 * @param client identification of the client
5187 * @param message the actual message
5190 handle_set_quota (void *cls,
5191 struct GNUNET_SERVER_Client *client,
5192 const struct GNUNET_MessageHeader *message)
5194 const struct QuotaSetMessage *qsm =
5195 (const struct QuotaSetMessage *) message;
5196 struct NeighbourList *n;
5198 GNUNET_STATISTICS_update (stats,
5199 gettext_noop ("# SET QUOTA messages received"),
5202 n = find_neighbour (&qsm->peer);
5205 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5206 GNUNET_STATISTICS_update (stats,
5207 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5214 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5216 (unsigned int) ntohl (qsm->quota.value__),
5217 (unsigned int) n->in_tracker.available_bytes_per_s__,
5218 GNUNET_i2s (&qsm->peer));
5220 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5222 if (0 == ntohl (qsm->quota.value__))
5224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5225 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5227 disconnect_neighbour (n, GNUNET_NO);
5229 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5234 * Take the given address and append it to the set of results sent back to
5237 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5238 * @param address the resolved name, NULL to indicate the last response
5241 transmit_address_to_client (void *cls, const char *address)
5243 struct GNUNET_SERVER_TransmitContext *tc = cls;
5246 if (NULL == address)
5249 slen = strlen (address) + 1;
5251 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5252 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5253 if (NULL == address)
5254 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5259 * Handle AddressLookup-message.
5261 * @param cls closure (always NULL)
5262 * @param client identification of the client
5263 * @param message the actual message
5266 handle_address_lookup (void *cls,
5267 struct GNUNET_SERVER_Client *client,
5268 const struct GNUNET_MessageHeader *message)
5270 const struct AddressLookupMessage *alum;
5271 struct TransportPlugin *lsPlugin;
5272 const char *nameTransport;
5273 const char *address;
5275 struct GNUNET_SERVER_TransmitContext *tc;
5276 struct GNUNET_TIME_Absolute timeout;
5277 struct GNUNET_TIME_Relative rtimeout;
5280 size = ntohs (message->size);
5281 if (size < sizeof (struct AddressLookupMessage))
5283 GNUNET_break_op (0);
5284 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5287 alum = (const struct AddressLookupMessage *) message;
5288 uint32_t addressLen = ntohl (alum->addrlen);
5289 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5291 GNUNET_break_op (0);
5292 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5295 address = (const char *) &alum[1];
5296 nameTransport = (const char *) &address[addressLen];
5298 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5300 GNUNET_break_op (0);
5301 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5304 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5305 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5306 numeric = ntohl (alum->numeric_only);
5307 lsPlugin = find_transport (nameTransport);
5308 if (NULL == lsPlugin)
5310 tc = GNUNET_SERVER_transmit_context_create (client);
5311 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5312 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5313 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5316 tc = GNUNET_SERVER_transmit_context_create (client);
5317 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5319 address, addressLen,
5322 &transmit_address_to_client, tc);
5327 * Setup the environment for this plugin.
5330 create_environment (struct TransportPlugin *plug)
5332 plug->env.cfg = cfg;
5333 plug->env.my_identity = &my_identity;
5334 plug->env.our_hello = &our_hello;
5335 plug->env.cls = plug;
5336 plug->env.receive = &plugin_env_receive;
5337 plug->env.notify_address = &plugin_env_notify_address;
5338 plug->env.session_end = &plugin_env_session_end;
5339 plug->env.max_connections = max_connect_per_transport;
5340 plug->env.stats = stats;
5345 * Start the specified transport (load the plugin).
5348 start_transport (struct GNUNET_SERVER_Handle *server,
5351 struct TransportPlugin *plug;
5354 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5355 _("Loading `%s' transport plugin\n"), name);
5356 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5357 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5358 create_environment (plug);
5359 plug->short_name = GNUNET_strdup (name);
5360 plug->lib_name = libname;
5361 plug->next = plugins;
5363 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5364 if (plug->api == NULL)
5366 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5367 _("Failed to load transport plugin for `%s'\n"), name);
5368 GNUNET_free (plug->short_name);
5369 plugins = plug->next;
5370 GNUNET_free (libname);
5377 * Called whenever a client is disconnected. Frees our
5378 * resources associated with that client.
5380 * @param cls closure
5381 * @param client identification of the client
5384 client_disconnect_notification (void *cls,
5385 struct GNUNET_SERVER_Client *client)
5387 struct TransportClient *pos;
5388 struct TransportClient *prev;
5389 struct ClientMessageQueueEntry *mqe;
5390 struct Blacklisters *bl;
5391 struct BlacklistCheck *bc;
5396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5397 "Client disconnected, cleaning up.\n");
5399 /* clean up blacklister */
5403 if (bl->client == client)
5408 if (bc->bl_pos == bl)
5410 bc->bl_pos = bl->next;
5413 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5416 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5417 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5423 GNUNET_CONTAINER_DLL_remove (bl_head,
5426 GNUNET_SERVER_client_drop (bl->client);
5432 /* clean up 'normal' clients */
5435 while ((pos != NULL) && (pos->client != client))
5442 while (NULL != (mqe = pos->message_queue_head))
5444 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5445 pos->message_queue_tail,
5447 pos->message_count--;
5451 clients = pos->next;
5453 prev->next = pos->next;
5454 if (GNUNET_YES == pos->tcs_pending)
5459 if (pos->th != NULL)
5461 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5464 GNUNET_break (0 == pos->message_count);
5470 * Function called when the service shuts down. Unloads our plugins
5471 * and cancels pending validations.
5473 * @param cls closure, unused
5474 * @param tc task context (unused)
5477 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5479 struct TransportPlugin *plug;
5480 struct OwnAddressList *al;
5481 struct CheckHelloValidatedContext *chvc;
5483 while (neighbours != NULL)
5485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5486 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5488 disconnect_neighbour (neighbours, GNUNET_NO);
5491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5492 "Transport service is unloading plugins...\n");
5494 while (NULL != (plug = plugins))
5496 plugins = plug->next;
5497 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5499 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5500 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5502 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5503 GNUNET_free (plug->lib_name);
5504 GNUNET_free (plug->short_name);
5505 while (NULL != (al = plug->addresses))
5507 plug->addresses = al->next;
5512 if (my_private_key != NULL)
5513 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5514 GNUNET_free_non_null (our_hello);
5516 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5519 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5520 validation_map = NULL;
5524 /* free 'chvc' data structure */
5525 while (NULL != (chvc = chvc_head))
5527 chvc_head = chvc->next;
5528 if (chvc->piter != NULL)
5530 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5531 GNUNET_STATISTICS_update (stats,
5532 gettext_noop ("# outstanding peerinfo iterate requests"),
5538 GNUNET_assert (chvc->ve_count == 0);
5545 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5548 if (peerinfo != NULL)
5550 GNUNET_PEERINFO_disconnect (peerinfo);
5553 /* Can we assume those are gone by now, or do we need to clean up
5555 GNUNET_break (bl_head == NULL);
5556 GNUNET_break (bc_head == NULL);
5559 struct ATS_transports
5566 #define FUNCTION ats_create_problem (int peers, int transports, double b_min, double b_max, double r, double R, const struct ATS_peer * pl, const struct ATS_transports * tl, int max_it, int max_dur)
5571 int result = GLP_UNDEF;
5576 int rows = 1 + (3*peers) + (transports);
5582 int ia[1+(rows*cols)], ja[1+(rows*cols)];
5583 double ar[1+(rows*cols)];
5586 /* Setting options */
5587 glp_smcp * options = GNUNET_malloc( sizeof (glp_smcp));
5588 glp_init_smcp(options);
5591 options->it_lim = max_it;
5593 options->tm_lim = max_dur;
5594 options->msg_lev = GLP_MSG_ALL;
5596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating LP problem: %i peers, relativity r %3.2f, b_max %5.2f, b_min %5.2f, \n",peers, r, b_max, b_min);
5597 lp = glp_create_prob();
5598 glp_set_prob_name(lp, "gnunet ats bandwidth distribution");
5599 glp_set_obj_dir(lp, GLP_MAX);
5601 /* Adding transports */
5602 glp_add_cols(lp, cols);
5603 for (c1=1; c1<=cols; c1++)
5605 GNUNET_asprintf(&peer_n,"%s",GNUNET_i2s(&pl[c1-1].peer));
5606 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer[%i] , transport %i, %s: f: %f\n",c1-1 , pl[c1-1].t, peer_n, pl[c1-1].f);
5607 /* add a single transport */
5608 glp_set_col_name(lp, c1, peer_n);
5609 /* add a lower bound */
5610 glp_set_col_bnds(lp, c1, GLP_LO, 0.0, 0.0);
5611 /* set coefficient function */
5612 value = pl[c1-1].f/b_max;
5614 glp_set_obj_coef(lp, c1, value);
5615 GNUNET_free(peer_n);
5619 /* Adding constraints */
5620 glp_add_rows(lp, rows);
5623 // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i \n", cur_row);
5624 glp_set_row_bnds(lp, cur_row, GLP_UP, 0.0, b_max);
5625 for (index=1; index<=cols; index++)
5627 ia[index] = 1, ja[index] = index, ar[index] = 1.0;
5633 for (c1=0; c1<peers; c1++)
5635 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i \n", cur_row);
5636 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0, b_max);
5638 for (c2 = 1; c2 <= cols; c2++)
5640 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "c1: %i c2 %i index: %i \n",c1 , c2, index);
5641 ia[index] = cur_row;
5643 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5644 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ia: %i ja %i ar: %f \n",cur_row , c2, ((c1+1 == c2) ? 1.0 : 0.0));
5651 for (c1=0; c1<peers; c1++)
5653 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i \n", cur_row);
5654 glp_set_row_bnds(lp, cur_row , GLP_LO, b_min, 0.0);
5656 for (c2 = 1; c2 <= cols; c2++)
5658 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "c1: %i c2 %i index: %i \n",c1 , c2, index);
5659 ia[index] = cur_row;
5661 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5662 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ia: %i ja %i ar: %f \n",cur_row , c2, ((c1+1 == c2) ? 1.0 : 0.0));
5669 for (c1=0; c1<peers; c1++)
5672 value = pl[c1].f * r;
5673 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i %f\n", cur_row, value);
5674 glp_set_row_bnds(lp, cur_row , GLP_LO, value, 0.0);
5676 for (c2 = 1; c2 <= cols; c2++)
5678 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "c1: %i c2 %i index: %i \n",c1 , c2, index);
5679 ia[index] = cur_row;
5681 ar[index] = ((c1+1 == c2) ? (1.0/b_max) : 0.0);
5682 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ia: %i ja %i ar: %f \n",cur_row , c2, ((c1+1 == c2) ? 1.0 : 0.0));
5688 /* transport capacity sum of b * c_i < c_max */
5690 for (c1=0; c1<transports; c1++)
5693 value = tl[c1].c_max;
5694 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Transport %i: c_max %5.2f c_1 %5.2f \n", c1, value, tl[c1].c_1);
5695 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0 , value);
5697 for (c2 = 1; c2 <= cols; c2++)
5699 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "c1: %i c2 %i index: %i \n",c1 , c2, index);
5700 ia[index] = cur_row;
5702 ar[index] = ((pl[c1-1].t == tl[c1].id) ? (tl[c1].c_1) : 0.0);
5703 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ia: %i ja %i ar: %f \n",cur_row , c2, ((c1+1 == c2) ? 1.0 : 0.0));
5709 glp_load_matrix(lp, rows * cols, ia, ja, ar);
5711 result = glp_simplex(lp, options);
5713 for (c1=1; c1<= peers; c1++ )
5715 printf("x%i = %g; ", c1, glp_get_col_prim(lp, c1));
5717 printf("z = %g; \n", glp_get_obj_val(lp));
5718 glp_delete_prob(lp);
5719 GNUNET_free(options);
5730 void ats_calculate_bandwidth_distribution (struct ATS_info * ats)
5732 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
5733 if (delta.rel_value < ats->min_delta.rel_value)
5736 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
5741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CALCULATE DISTRIBUTION\n");
5748 double b_max = 100.0;
5749 double r = 0.85;//1.0;
5755 struct ATS_transports * tl = GNUNET_malloc(transports * sizeof (struct ATS_peer));
5757 struct ATS_peer * pl = GNUNET_malloc(peers * sizeof (struct ATS_peer));
5761 pl[c].peer.hashPubKey.bits[0] = c+1;
5762 pl[c].f = 1 / (double) peers ;
5764 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %s %p \n",c , GNUNET_i2s(&list[c].peer), &list[c].peer);
5768 while (c < transports)
5783 ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur);
5788 ats->last = GNUNET_TIME_absolute_get();
5795 ats_schedule_calculation (void *cls,
5796 const struct GNUNET_SCHEDULER_TaskContext *tc)
5798 struct ATS_info *ats = (struct ATS_info *) cls;
5802 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5803 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
5807 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
5809 ats_calculate_bandwidth_distribution (ats);
5811 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5812 &ats_schedule_calculation, ats);
5816 int ats_map_remove_peer (void *cls,
5817 const GNUNET_HashCode * key,
5821 struct ATS_peer * p = (struct ATS_peer *) value;
5823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
5832 struct ATS_info * ats_init ()
5834 struct ATS_info * ats;
5836 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
5838 ats = GNUNET_malloc(sizeof (struct ATS_info));
5839 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
5840 GNUNET_assert(ats->peers!=NULL);
5842 ats->min_delta = ATS_MIN_INTERVAL;
5843 ats->reg_delta = ATS_EXEC_INTERVAL;
5845 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5847 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5848 &schedule_calculation, NULL);
5850 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5851 &schedule_calculation, NULL);
5853 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
5859 void ats_shutdown (struct ATS_info * ats)
5862 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
5864 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
5865 GNUNET_SCHEDULER_cancel(ats->ats_task);
5866 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5868 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
5869 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
5874 void ats_notify_peer_connect (struct ATS_info * ats,
5875 const struct GNUNET_PeerIdentity *peer,
5876 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
5883 while (ntohl(ats_data[c].type)!=0)
5886 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
5890 /* check if peer is already known */
5891 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
5893 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
5894 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
5895 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
5898 ats_calculate_bandwidth_distribution(ats);
5901 void ats_notify_peer_disconnect (struct ATS_info * ats,
5902 const struct GNUNET_PeerIdentity *peer)
5905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
5908 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
5910 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
5911 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
5914 ats_calculate_bandwidth_distribution (ats);
5918 void ats_notify_ats_data (struct ATS_info * ats,
5919 const struct GNUNET_PeerIdentity *peer,
5920 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5923 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
5925 ats_calculate_bandwidth_distribution(ats);
5928 struct ForeignAddressList * ats_get_preferred_address (struct ATS_info * ats,
5929 struct NeighbourList *n)
5932 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
5934 struct ReadyList *next = n->plugins;
5935 while (next != NULL)
5938 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
5942 return find_ready_address(n);
5946 * Initiate transport service.
5948 * @param cls closure
5949 * @param server the initialized server
5950 * @param c configuration to use
5954 struct GNUNET_SERVER_Handle *server,
5955 const struct GNUNET_CONFIGURATION_Handle *c)
5957 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
5958 {&handle_start, NULL,
5959 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
5960 {&handle_hello, NULL,
5961 GNUNET_MESSAGE_TYPE_HELLO, 0},
5962 {&handle_send, NULL,
5963 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
5964 {&handle_request_connect, NULL,
5965 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
5966 {&handle_set_quota, NULL,
5967 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
5968 {&handle_address_lookup, NULL,
5969 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
5971 {&handle_blacklist_init, NULL,
5972 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
5973 {&handle_blacklist_reply, NULL,
5974 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
5980 unsigned long long tneigh;
5984 stats = GNUNET_STATISTICS_create ("transport", cfg);
5985 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
5986 /* parse configuration */
5988 GNUNET_CONFIGURATION_get_value_number (c,
5993 GNUNET_CONFIGURATION_get_value_filename (c,
5995 "HOSTKEY", &keyfile)))
5997 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5999 ("Transport service is lacking key configuration settings. Exiting.\n"));
6000 GNUNET_SCHEDULER_shutdown ();
6003 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6006 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6007 validation_map = NULL;
6011 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("HAVE\n"));
6013 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("NOT HAVE\n"));
6017 max_connect_per_transport = (uint32_t) tneigh;
6018 peerinfo = GNUNET_PEERINFO_connect (cfg);
6019 if (peerinfo == NULL)
6021 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6022 _("Could not access PEERINFO service. Exiting.\n"));
6023 GNUNET_SCHEDULER_shutdown ();
6026 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6029 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6030 validation_map = NULL;
6031 GNUNET_free (keyfile);
6034 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6035 GNUNET_free (keyfile);
6036 if (my_private_key == NULL)
6038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6040 ("Transport service could not access hostkey. Exiting.\n"));
6041 GNUNET_SCHEDULER_shutdown ();
6044 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6047 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6048 validation_map = NULL;
6051 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6052 GNUNET_CRYPTO_hash (&my_public_key,
6053 sizeof (my_public_key), &my_identity.hashPubKey);
6054 /* setup notification */
6055 GNUNET_SERVER_disconnect_notify (server,
6056 &client_disconnect_notification, NULL);
6057 /* load plugins... */
6060 GNUNET_CONFIGURATION_get_value_string (c,
6061 "TRANSPORT", "PLUGINS", &plugs))
6063 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6064 _("Starting transport plugins `%s'\n"), plugs);
6065 pos = strtok (plugs, " ");
6068 start_transport (server, pos);
6070 pos = strtok (NULL, " ");
6072 GNUNET_free (plugs);
6074 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6075 &shutdown_task, NULL);
6080 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6082 /* If we have a blacklist file, read from it */
6083 read_blacklist_file(cfg);
6084 /* process client requests */
6085 GNUNET_SERVER_add_handlers (server, handlers);
6090 * The main function for the transport service.
6092 * @param argc number of arguments from the command line
6093 * @param argv command line arguments
6094 * @return 0 ok, 1 on error
6097 main (int argc, char *const *argv)
6099 a2s (NULL, NULL, 0); /* make compiler happy */
6100 return (GNUNET_OK ==
6101 GNUNET_SERVICE_run (argc,
6104 GNUNET_SERVICE_OPTION_NONE,
6105 &run, NULL)) ? 0 : 1;
6108 /* end of gnunet-service-transport.c */