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
51 #define VERBOSE_ATS GNUNET_NO
54 * Should we do some additional checks (to validate behavior
57 #define EXTRA_CHECKS GNUNET_YES
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
71 #define MAX_PENDING (128 * 1024)
74 * Size of the per-transport blacklist hash maps.
76 #define TRANSPORT_BLACKLIST_HT_SIZE 16
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
83 #define MAX_CONNECT_RETRY 3
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
90 #define MAX_HELLO_LOAD 4
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
96 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
106 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
115 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
118 * Priority to use for PONG messages.
120 #define TRANSPORT_PONG_PRIORITY 4
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
126 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
133 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
141 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * Maximum frequency for re-evaluating latencies for all transport addresses.
146 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
149 * Maximum frequency for re-evaluating latencies for connected addresses.
151 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
155 * List of addresses of other peers
157 struct ForeignAddressList
160 * This is a linked list.
162 struct ForeignAddressList *next;
165 * Which ready list does this entry belong to.
167 struct ReadyList *ready_list;
170 * How long until we auto-expire this address (unless it is
171 * re-confirmed by the transport)?
173 struct GNUNET_TIME_Absolute expires;
176 * Task used to re-validate addresses, updates latencies and
179 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
187 * Session (or NULL if no valid session currently exists or if the
188 * plugin does not use sessions).
190 struct Session *session;
193 * What was the last latency observed for this address, plugin and peer?
195 struct GNUNET_TIME_Relative latency;
198 * If we did not successfully transmit a message to the given peer
199 * via this connection during the specified time, we should consider
200 * the connection to be dead. This is used in the case that a TCP
201 * transport simply stalls writing to the stream but does not
202 * formerly get a signal that the other peer died.
204 struct GNUNET_TIME_Absolute timeout;
207 * How often have we tried to connect using this plugin? Used to
208 * discriminate against addresses that do not work well.
209 * FIXME: not yet used, but should be!
211 unsigned int connect_attempts;
214 * DV distance to this peer (1 if no DV is used).
215 * FIXME: need to set this from transport plugins!
225 * Have we ever estimated the latency of this address? Used to
226 * ensure that the first time we add an address, we immediately
232 * Are we currently connected via this address? The first time we
233 * successfully transmit or receive data to a peer via a particular
234 * address, we set this to GNUNET_YES. If we later get an error
235 * (disconnect notification, transmission failure, timeout), we set
236 * it back to GNUNET_NO.
241 * Is this plugin currently busy transmitting to the specific target?
242 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
243 * messages do not count as 'in transmit'.
248 * Has this address been validated yet?
256 * Entry in linked list of network addresses for ourselves. Also
257 * includes a cached signature for 'struct TransportPongMessage's.
259 struct OwnAddressList
262 * This is a linked list.
264 struct OwnAddressList *next;
267 * How long until we actually auto-expire this address (unless it is
268 * re-confirmed by the transport)?
270 struct GNUNET_TIME_Absolute expires;
273 * How long until the current signature expires? (ZERO if the
274 * signature was never created).
276 struct GNUNET_TIME_Absolute pong_sig_expires;
279 * Signature for a 'struct TransportPongMessage' for this address.
281 struct GNUNET_CRYPTO_RsaSignature pong_signature;
292 * Entry in linked list of all of our plugins.
294 struct TransportPlugin
298 * This is a linked list.
300 struct TransportPlugin *next;
303 * API of the transport as returned by the plugin's
304 * initialization function.
306 struct GNUNET_TRANSPORT_PluginFunctions *api;
309 * Short name for the plugin (i.e. "tcp").
314 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
319 * List of our known addresses for this transport.
321 struct OwnAddressList *addresses;
324 * Environment this transport service is using
327 struct GNUNET_TRANSPORT_PluginEnvironment env;
330 * ID of task that is used to clean up expired addresses.
332 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
335 * Set to GNUNET_YES if we need to scrap the existing list of
336 * "addresses" and start fresh when we receive the next address
337 * update from a transport. Set to GNUNET_NO if we should just add
338 * the new address to the list and wait for the commit call.
343 * Hashmap of blacklisted peers for this particular transport.
345 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
348 struct NeighbourList;
351 * For each neighbour we keep a list of messages
352 * that we still want to transmit to the neighbour.
358 * This is a doubly linked list.
360 struct MessageQueue *next;
363 * This is a doubly linked list.
365 struct MessageQueue *prev;
368 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
369 * stuck together in memory. Allocated at the end of this struct.
371 const char *message_buf;
374 * Size of the message buf
376 size_t message_buf_size;
379 * Client responsible for queueing the message;
380 * used to check that a client has no two messages
381 * pending for the same target. Can be NULL.
383 struct TransportClient *client;
386 * Using which specific address should we send this message?
388 struct ForeignAddressList *specific_address;
391 * Peer ID of the Neighbour this entry belongs to.
393 struct GNUNET_PeerIdentity neighbour_id;
396 * Plugin that we used for the transmission.
397 * NULL until we scheduled a transmission.
399 struct TransportPlugin *plugin;
402 * At what time should we fail?
404 struct GNUNET_TIME_Absolute timeout;
407 * Internal message of the transport system that should not be
408 * included in the usual SEND-SEND_OK transmission confirmation
409 * traffic management scheme. Typically, "internal_msg" will
410 * be set whenever "client" is NULL (but it is not strictly
416 * How important is the message?
418 unsigned int priority;
424 * For a given Neighbour, which plugins are available
425 * to talk to this peer and what are their costs?
430 * This is a linked list.
432 struct ReadyList *next;
435 * Which of our transport plugins does this entry
438 struct TransportPlugin *plugin;
441 * Transport addresses, latency, and readiness for
442 * this particular plugin.
444 struct ForeignAddressList *addresses;
447 * To which neighbour does this ready list belong to?
449 struct NeighbourList *neighbour;
455 * Entry in linked list of all of our current neighbours.
461 * This is a linked list.
463 struct NeighbourList *next;
466 * Which of our transports is connected to this peer
467 * and what is their status?
469 struct ReadyList *plugins;
472 * Head of list of messages we would like to send to this peer;
473 * must contain at most one message per client.
475 struct MessageQueue *messages_head;
478 * Tail of list of messages we would like to send to this peer; must
479 * contain at most one message per client.
481 struct MessageQueue *messages_tail;
484 * Buffer for at most one payload message used when we receive
485 * payload data before our PING-PONG has succeeded. We then
486 * store such messages in this intermediary buffer until the
487 * connection is fully up.
489 struct GNUNET_MessageHeader *pre_connect_message_buffer;
492 * Context for peerinfo iteration.
493 * NULL after we are done processing peerinfo's information.
495 struct GNUNET_PEERINFO_IteratorContext *piter;
498 * Public key for this peer. Valid only if the respective flag is set below.
500 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
503 * Identity of this neighbour.
505 struct GNUNET_PeerIdentity id;
508 * ID of task scheduled to run when this peer is about to
509 * time out (will free resources associated with the peer).
511 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
514 * ID of task scheduled to run when we should retry transmitting
515 * the head of the message queue. Actually triggered when the
516 * transmission is timing out (we trigger instantly when we have
517 * a chance of success).
519 GNUNET_SCHEDULER_TaskIdentifier retry_task;
522 * How long until we should consider this peer dead
523 * (if we don't receive another message in the
526 struct GNUNET_TIME_Absolute peer_timeout;
529 * Tracker for inbound bandwidth.
531 struct GNUNET_BANDWIDTH_Tracker in_tracker;
534 * The latency we have seen for this particular address for
535 * this particular peer. This latency may have been calculated
536 * over multiple transports. This value reflects how long it took
537 * us to receive a response when SENDING via this particular
538 * transport/neighbour/address combination!
540 * FIXME: we need to periodically send PINGs to update this
541 * latency (at least more often than the current "huge" (11h?)
544 struct GNUNET_TIME_Relative latency;
547 * How often has the other peer (recently) violated the
548 * inbound traffic limit? Incremented by 10 per violation,
549 * decremented by 1 per non-violation (for each
552 unsigned int quota_violation_count;
555 * DV distance to this peer (1 if no DV is used).
560 * Have we seen an PONG from this neighbour in the past (and
561 * not had a disconnect since)?
566 * Do we have a valid public key for this neighbour?
568 int public_key_valid;
571 * Performance data for the peer.
573 struct GNUNET_TRANSPORT_ATS_Information *ats;
576 * Identity of the neighbour.
578 struct GNUNET_PeerIdentity peer;
583 * Message used to ask a peer to validate receipt (to check an address
584 * from a HELLO). Followed by the address we are trying to validate,
585 * or an empty address if we are just sending a PING to confirm that a
586 * connection which the receiver (of the PING) initiated is still valid.
588 struct TransportPingMessage
592 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
594 struct GNUNET_MessageHeader header;
597 * Challenge code (to ensure fresh reply).
599 uint32_t challenge GNUNET_PACKED;
602 * Who is the intended recipient?
604 struct GNUNET_PeerIdentity target;
610 * Message used to validate a HELLO. The challenge is included in the
611 * confirmation to make matching of replies to requests possible. The
612 * signature signs our public key, an expiration time and our address.<p>
614 * This message is followed by our transport address that the PING tried
615 * to confirm (if we liked it). The address can be empty (zero bytes)
616 * if the PING had not address either (and we received the request via
617 * a connection that we initiated).
619 struct TransportPongMessage
623 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
625 struct GNUNET_MessageHeader header;
628 * Challenge code from PING (showing freshness). Not part of what
629 * is signed so that we can re-use signatures.
631 uint32_t challenge GNUNET_PACKED;
636 struct GNUNET_CRYPTO_RsaSignature signature;
639 * What are we signing and why? Two possible reason codes can be here:
640 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
641 * plausible address for this peer (pid is set to identity of signer); or
642 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
643 * an address we used to connect to the peer with the given pid.
645 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
648 * When does this signature expire?
650 struct GNUNET_TIME_AbsoluteNBO expiration;
653 * Either the identity of the peer Who signed this message, or the
654 * identity of the peer that we're connected to using the given
655 * address (depending on purpose.type).
657 struct GNUNET_PeerIdentity pid;
660 * Size of address appended to this message (part of what is
661 * being signed, hence not redundant).
669 * Linked list of messages to be transmitted to the client. Each
670 * entry is followed by the actual message.
672 struct ClientMessageQueueEntry
675 * This is a doubly-linked list.
677 struct ClientMessageQueueEntry *next;
680 * This is a doubly-linked list.
682 struct ClientMessageQueueEntry *prev;
687 * Client connected to the transport service.
689 struct TransportClient
693 * This is a linked list.
695 struct TransportClient *next;
698 * Handle to the client.
700 struct GNUNET_SERVER_Client *client;
703 * Linked list of messages yet to be transmitted to
706 struct ClientMessageQueueEntry *message_queue_head;
709 * Tail of linked list of messages yet to be transmitted to the
712 struct ClientMessageQueueEntry *message_queue_tail;
715 * Current transmit request handle.
717 struct GNUNET_CONNECTION_TransmitHandle *th;
720 * Is a call to "transmit_send_continuation" pending? If so, we
721 * must not free this struct (even if the corresponding client
722 * disconnects) and instead only remove it from the linked list and
723 * set the "client" field to NULL.
728 * Length of the list of messages pending for this client.
730 unsigned int message_count;
736 * Context of currently active requests to peerinfo
737 * for validation of HELLOs.
739 struct CheckHelloValidatedContext;
743 * Entry in map of all HELLOs awaiting validation.
745 struct ValidationEntry
749 * NULL if this entry is not part of a larger HELLO validation.
751 struct CheckHelloValidatedContext *chvc;
754 * The address, actually a pointer to the end
755 * of this struct. Do not free!
760 * Name of the transport.
762 char *transport_name;
765 * The public key of the peer.
767 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
770 * ID of task that will clean up this entry if we don't succeed
771 * with the validation first.
773 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
776 * At what time did we send this validation?
778 struct GNUNET_TIME_Absolute send_time;
781 * Session being validated (or NULL for none).
783 struct Session *session;
786 * Challenge number we used.
799 * Context of currently active requests to peerinfo
800 * for validation of HELLOs.
802 struct CheckHelloValidatedContext
806 * This is a doubly-linked list.
808 struct CheckHelloValidatedContext *next;
811 * This is a doubly-linked list.
813 struct CheckHelloValidatedContext *prev;
816 * Hello that we are validating.
818 const struct GNUNET_HELLO_Message *hello;
821 * Context for peerinfo iteration.
822 * NULL after we are done processing peerinfo's information.
824 struct GNUNET_PEERINFO_IteratorContext *piter;
827 * Was a HELLO known for this peer to peerinfo?
832 * Number of validation entries currently referring to this
835 unsigned int ve_count;
843 static struct GNUNET_HELLO_Message *our_hello;
848 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
853 static struct GNUNET_PeerIdentity my_identity;
858 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
863 const struct GNUNET_CONFIGURATION_Handle *cfg;
866 * Linked list of all clients to this service.
868 static struct TransportClient *clients;
871 * All loaded plugins.
873 static struct TransportPlugin *plugins;
876 * Handle to peerinfo service.
878 static struct GNUNET_PEERINFO_Handle *peerinfo;
881 * All known neighbours and their HELLOs.
883 static struct NeighbourList *neighbours;
886 * Number of neighbours we'd like to have.
888 static uint32_t max_connect_per_transport;
891 * Head of linked list.
893 static struct CheckHelloValidatedContext *chvc_head;
896 * Tail of linked list.
898 static struct CheckHelloValidatedContext *chvc_tail;
901 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
902 * of the given peer that we are currently validating).
904 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
907 * Handle for reporting statistics.
909 static struct GNUNET_STATISTICS_Handle *stats;
912 * Handle for ats information
914 static struct ATS_info *ats;
917 * The peer specified by the given neighbour has timed-out or a plugin
918 * has disconnected. We may either need to do nothing (other plugins
919 * still up), or trigger a full disconnect and clean up. This
920 * function updates our state and do the necessary notifications.
921 * Also notifies our clients that the neighbour is now officially
924 * @param n the neighbour list entry for the peer
925 * @param check should we just check if all plugins
926 * disconnected or must we ask all plugins to
929 static void disconnect_neighbour (struct NeighbourList *n, int check);
932 * Check the ready list for the given neighbour and if a plugin is
933 * ready for transmission (and if we have a message), do so!
935 * @param neighbour target peer for which to transmit
937 static void try_transmission_to_peer (struct NeighbourList *n);
940 struct ATS_info * ats_init ();
942 void ats_shutdown ( );
944 void ats_notify_peer_connect (
945 const struct GNUNET_PeerIdentity *peer,
946 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
948 void ats_notify_peer_disconnect (
949 const struct GNUNET_PeerIdentity *peer);
951 void ats_notify_ats_data (
952 const struct GNUNET_PeerIdentity *peer,
953 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
955 struct ForeignAddressList * ats_get_preferred_address (
956 struct NeighbourList *n);
959 * Find an entry in the neighbour list for a particular peer.
961 * @return NULL if not found.
963 static struct NeighbourList *
964 find_neighbour (const struct GNUNET_PeerIdentity *key)
966 struct NeighbourList *head = neighbours;
968 while ((head != NULL) &&
969 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
976 * Find an entry in the transport list for a particular transport.
978 * @return NULL if not found.
980 static struct TransportPlugin *
981 find_transport (const char *short_name)
983 struct TransportPlugin *head = plugins;
984 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
990 * Is a particular peer blacklisted for a particular transport?
992 * @param peer the peer to check for
993 * @param plugin the plugin used to connect to the peer
995 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
998 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1001 if (plugin->blacklist != NULL)
1003 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1007 "Peer `%s:%s' is blacklisted!\n",
1008 plugin->short_name, GNUNET_i2s (peer));
1011 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1021 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1023 struct TransportPlugin *plugin;
1025 plugin = find_transport(transport_name);
1026 if (plugin == NULL) /* Nothing to do */
1028 if (plugin->blacklist == NULL)
1029 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1030 GNUNET_assert(plugin->blacklist != NULL);
1031 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1033 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1038 * Read the blacklist file, containing transport:peer entries.
1039 * Provided the transport is loaded, set up hashmap with these
1040 * entries to blacklist peers by transport.
1044 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1051 struct GNUNET_PeerIdentity pid;
1053 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1054 unsigned int entries_found;
1055 char *transport_name;
1058 GNUNET_CONFIGURATION_get_value_filename (cfg,
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "Option `%s' in section `%s' not specified!\n",
1071 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1072 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1073 | GNUNET_DISK_PERM_USER_WRITE);
1074 if (0 != STAT (fn, &frstat))
1076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1077 _("Could not read blacklist file `%s'\n"), fn);
1081 if (frstat.st_size == 0)
1084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085 _("Blacklist file `%s' is empty.\n"),
1091 /* FIXME: use mmap */
1092 data = GNUNET_malloc_large (frstat.st_size);
1093 GNUNET_assert(data != NULL);
1094 if (frstat.st_size !=
1095 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1098 _("Failed to read blacklist from `%s'\n"), fn);
1105 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1107 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1108 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1111 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1114 if (colon_pos >= frstat.st_size)
1116 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1117 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1118 (unsigned long long) colon_pos);
1124 if (isspace( (unsigned char) data[colon_pos]))
1126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1127 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1128 (unsigned long long) colon_pos);
1130 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1134 tsize = colon_pos - pos;
1135 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1137 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1138 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1139 (unsigned long long) colon_pos);
1148 transport_name = GNUNET_malloc(tsize + 1);
1149 memcpy(transport_name, &data[pos], tsize);
1150 pos = colon_pos + 1;
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 "Read transport name %s in blacklist file.\n",
1156 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1157 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1159 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1160 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1161 (unsigned long long) pos);
1163 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1165 GNUNET_free_non_null(transport_name);
1168 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1169 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1171 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1172 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1173 (unsigned long long) pos,
1178 if (0 != memcmp (&pid,
1180 sizeof (struct GNUNET_PeerIdentity)))
1183 add_peer_to_blacklist (&pid,
1188 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1189 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1193 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1194 GNUNET_free_non_null(transport_name);
1195 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1198 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1205 * Function called to notify a client about the socket being ready to
1206 * queue more data. "buf" will be NULL and "size" zero if the socket
1207 * was closed for writing in the meantime.
1209 * @param cls closure
1210 * @param size number of bytes available in buf
1211 * @param buf where the callee should write the message
1212 * @return number of bytes written to buf
1215 transmit_to_client_callback (void *cls, size_t size, void *buf)
1217 struct TransportClient *client = cls;
1218 struct ClientMessageQueueEntry *q;
1221 const struct GNUNET_MessageHeader *msg;
1228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1229 "Transmission to client failed, closing connection.\n");
1231 /* fatal error with client, free message queue! */
1232 while (NULL != (q = client->message_queue_head))
1234 GNUNET_STATISTICS_update (stats,
1235 gettext_noop ("# bytes discarded (could not transmit to client)"),
1236 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1238 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1239 client->message_queue_tail,
1243 client->message_count = 0;
1248 while (NULL != (q = client->message_queue_head))
1250 msg = (const struct GNUNET_MessageHeader *) &q[1];
1251 msize = ntohs (msg->size);
1252 if (msize + tsize > size)
1255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1256 "Transmitting message of type %u to client.\n",
1259 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1260 client->message_queue_tail,
1262 memcpy (&cbuf[tsize], msg, msize);
1265 client->message_count--;
1269 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1270 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1272 GNUNET_TIME_UNIT_FOREVER_REL,
1273 &transmit_to_client_callback,
1275 GNUNET_assert (client->th != NULL);
1282 * Convert an address to a string.
1284 * @param plugin name of the plugin responsible for the address
1285 * @param addr binary address
1286 * @param addr_len number of bytes in addr
1287 * @return NULL on error, otherwise address string
1290 a2s (const char *plugin,
1294 struct TransportPlugin *p;
1298 p = find_transport (plugin);
1301 return p->api->address_to_string (p->api->cls,
1308 * Mark the given FAL entry as 'connected' (and hence preferred for
1309 * sending); also mark all others for the same peer as 'not connected'
1310 * (since only one can be preferred).
1312 * @param fal address to set to 'connected'
1315 mark_address_connected (struct ForeignAddressList *fal)
1317 struct ForeignAddressList *pos;
1320 GNUNET_assert (GNUNET_YES == fal->validated);
1321 if (fal->connected == GNUNET_YES)
1322 return; /* nothing to do */
1324 pos = fal->ready_list->addresses;
1327 if (GNUNET_YES == pos->connected)
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1332 a2s (pos->ready_list->plugin->short_name,
1336 GNUNET_break (cnt == GNUNET_YES);
1338 pos->connected = GNUNET_NO;
1339 GNUNET_STATISTICS_update (stats,
1340 gettext_noop ("# connected addresses"),
1346 fal->connected = GNUNET_YES;
1347 if (GNUNET_YES == cnt)
1349 GNUNET_STATISTICS_update (stats,
1350 gettext_noop ("# connected addresses"),
1358 * Send the specified message to the specified client. Since multiple
1359 * messages may be pending for the same client at a time, this code
1360 * makes sure that no message is lost.
1362 * @param client client to transmit the message to
1363 * @param msg the message to send
1364 * @param may_drop can this message be dropped if the
1365 * message queue for this client is getting far too large?
1368 transmit_to_client (struct TransportClient *client,
1369 const struct GNUNET_MessageHeader *msg, int may_drop)
1371 struct ClientMessageQueueEntry *q;
1374 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1376 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1378 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1381 client->message_count,
1383 GNUNET_STATISTICS_update (stats,
1384 gettext_noop ("# messages dropped due to slow client"),
1389 msize = ntohs (msg->size);
1390 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1391 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1392 memcpy (&q[1], msg, msize);
1393 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1394 client->message_queue_tail,
1395 client->message_queue_tail,
1397 client->message_count++;
1398 if (client->th == NULL)
1400 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1402 GNUNET_TIME_UNIT_FOREVER_REL,
1403 &transmit_to_client_callback,
1405 GNUNET_assert (client->th != NULL);
1411 * Transmit a 'SEND_OK' notification to the given client for the
1414 * @param client who to notify
1415 * @param n neighbour to notify about, can be NULL (on failure)
1416 * @param target target of the transmission
1417 * @param result status code for the transmission request
1420 transmit_send_ok (struct TransportClient *client,
1421 struct NeighbourList *n,
1422 const struct GNUNET_PeerIdentity *target,
1425 struct SendOkMessage send_ok_msg;
1427 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1428 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1429 send_ok_msg.success = htonl (result);
1431 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1433 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1434 send_ok_msg.peer = *target;
1435 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1440 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1441 * upon "completion" of a send request. This tells the API
1442 * that it is now legal to send another message to the given
1445 * @param cls closure, identifies the entry on the
1446 * message queue that was transmitted and the
1447 * client responsible for queuing the message
1448 * @param target the peer receiving the message
1449 * @param result GNUNET_OK on success, if the transmission
1450 * failed, we should not tell the client to transmit
1454 transmit_send_continuation (void *cls,
1455 const struct GNUNET_PeerIdentity *target,
1458 struct MessageQueue *mq = cls;
1459 struct NeighbourList *n;
1461 GNUNET_STATISTICS_update (stats,
1462 gettext_noop ("# bytes pending with plugins"),
1463 - (int64_t) mq->message_buf_size,
1465 if (result == GNUNET_OK)
1467 GNUNET_STATISTICS_update (stats,
1468 gettext_noop ("# bytes successfully transmitted by plugins"),
1469 mq->message_buf_size,
1474 GNUNET_STATISTICS_update (stats,
1475 gettext_noop ("# bytes with transmission failure by plugins"),
1476 mq->message_buf_size,
1479 if (mq->specific_address != NULL)
1481 if (result == GNUNET_OK)
1483 mq->specific_address->timeout =
1484 GNUNET_TIME_relative_to_absolute
1485 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1486 if (mq->specific_address->validated == GNUNET_YES)
1487 mark_address_connected (mq->specific_address);
1491 if (mq->specific_address->connected != GNUNET_NO)
1494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1495 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1496 a2s (mq->specific_address->ready_list->plugin->short_name,
1497 mq->specific_address->addr,
1498 mq->specific_address->addrlen));
1500 GNUNET_STATISTICS_update (stats,
1501 gettext_noop ("# connected addresses"),
1504 mq->specific_address->connected = GNUNET_NO;
1507 if (! mq->internal_msg)
1508 mq->specific_address->in_transmit = GNUNET_NO;
1510 n = find_neighbour(&mq->neighbour_id);
1511 if (mq->client != NULL)
1512 transmit_send_ok (mq->client, n, target, result);
1515 try_transmission_to_peer (n);
1520 * Find an address in any of the available transports for
1521 * the given neighbour that would be good for message
1522 * transmission. This is essentially the transport selection
1525 * @param neighbour for whom to select an address
1526 * @return selected address, NULL if we have none
1528 struct ForeignAddressList *
1529 find_ready_address(struct NeighbourList *neighbour)
1531 struct ReadyList *head = neighbour->plugins;
1532 struct ForeignAddressList *addresses;
1533 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1534 struct ForeignAddressList *best_address;
1536 /* Hack to prefer unix domain sockets */
1537 struct ForeignAddressList *unix_address = NULL;
1539 best_address = NULL;
1540 while (head != NULL)
1542 addresses = head->addresses;
1543 while (addresses != NULL)
1545 if ( (addresses->timeout.abs_value < now.abs_value) &&
1546 (addresses->connected == GNUNET_YES) )
1549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1550 "Marking long-time inactive connection to `%4s' as down.\n",
1551 GNUNET_i2s (&neighbour->id));
1553 GNUNET_STATISTICS_update (stats,
1554 gettext_noop ("# connected addresses"),
1557 addresses->connected = GNUNET_NO;
1559 addresses = addresses->next;
1562 addresses = head->addresses;
1563 while (addresses != NULL)
1565 #if DEBUG_TRANSPORT > 1
1566 if (addresses->addr != NULL)
1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1568 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1569 a2s (head->plugin->short_name,
1571 addresses->addrlen),
1572 GNUNET_i2s (&neighbour->id),
1573 addresses->connected,
1574 addresses->in_transmit,
1575 addresses->validated,
1576 addresses->connect_attempts,
1577 (unsigned long long) addresses->timeout.abs_value,
1578 (unsigned int) addresses->distance);
1580 if (0==strcmp(head->plugin->short_name,"unix"))
1582 if ((unix_address == NULL) || ((unix_address != NULL) &&
1583 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1584 unix_address = addresses;
1586 if ( ( (best_address == NULL) ||
1587 (addresses->connected == GNUNET_YES) ||
1588 (best_address->connected == GNUNET_NO) ) &&
1589 (addresses->in_transmit == GNUNET_NO) &&
1590 ( (best_address == NULL) ||
1591 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1592 best_address = addresses;
1593 /* FIXME: also give lower-latency addresses that are not
1594 connected a chance some times... */
1595 addresses = addresses->next;
1597 if (unix_address != NULL)
1601 if (unix_address != NULL)
1603 best_address = unix_address;
1605 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1608 if (best_address != NULL)
1612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1613 "Best address found (`%s') has latency of %llu ms.\n",
1614 (best_address->addrlen > 0)
1615 ? a2s (best_address->ready_list->plugin->short_name,
1617 best_address->addrlen)
1619 best_address->latency.rel_value);
1624 GNUNET_STATISTICS_update (stats,
1625 gettext_noop ("# transmission attempts failed (no address)"),
1630 return best_address;
1636 * We should re-try transmitting to the given peer,
1637 * hopefully we've learned something in the meantime.
1640 retry_transmission_task (void *cls,
1641 const struct GNUNET_SCHEDULER_TaskContext *tc)
1643 struct NeighbourList *n = cls;
1645 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1646 try_transmission_to_peer (n);
1651 * Check the ready list for the given neighbour and if a plugin is
1652 * ready for transmission (and if we have a message), do so!
1654 * @param neighbour target peer for which to transmit
1657 try_transmission_to_peer (struct NeighbourList *n)
1659 struct ReadyList *rl;
1660 struct MessageQueue *mq;
1661 struct GNUNET_TIME_Relative timeout;
1665 if (n->messages_head == NULL)
1668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1669 "Transmission queue for `%4s' is empty\n",
1670 GNUNET_i2s (&neighbour->id));
1672 return; /* nothing to do */
1675 mq = n->messages_head;
1676 force_address = GNUNET_YES;
1677 if (mq->specific_address == NULL)
1680 mq->specific_address = ats_get_preferred_address(n);
1681 GNUNET_STATISTICS_update (stats,
1682 gettext_noop ("# transport selected peer address freely"),
1685 force_address = GNUNET_NO;
1687 if (mq->specific_address == NULL)
1689 GNUNET_STATISTICS_update (stats,
1690 gettext_noop ("# transport failed to selected peer address"),
1693 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1694 if (timeout.rel_value == 0)
1697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1698 "No destination address available to transmit message of size %u to peer `%4s'\n",
1699 mq->message_buf_size,
1700 GNUNET_i2s (&mq->neighbour_id));
1702 GNUNET_STATISTICS_update (stats,
1703 gettext_noop ("# bytes in message queue for other peers"),
1704 - (int64_t) mq->message_buf_size,
1706 GNUNET_STATISTICS_update (stats,
1707 gettext_noop ("# bytes discarded (no destination address available)"),
1708 mq->message_buf_size,
1710 if (mq->client != NULL)
1711 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1712 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1716 return; /* nobody ready */
1718 GNUNET_STATISTICS_update (stats,
1719 gettext_noop ("# message delivery deferred (no address)"),
1722 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1723 GNUNET_SCHEDULER_cancel (n->retry_task);
1724 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1725 &retry_transmission_task,
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1730 mq->message_buf_size,
1731 GNUNET_i2s (&mq->neighbour_id),
1734 /* FIXME: might want to trigger peerinfo lookup here
1735 (unless that's already pending...) */
1738 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1741 if (mq->specific_address->connected == GNUNET_NO)
1742 mq->specific_address->connect_attempts++;
1743 rl = mq->specific_address->ready_list;
1744 mq->plugin = rl->plugin;
1745 if (!mq->internal_msg)
1746 mq->specific_address->in_transmit = GNUNET_YES;
1748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1749 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1750 mq->message_buf_size,
1751 GNUNET_i2s (&neighbour->id),
1752 (mq->specific_address->addr != NULL)
1753 ? a2s (mq->plugin->short_name,
1754 mq->specific_address->addr,
1755 mq->specific_address->addrlen)
1757 rl->plugin->short_name);
1759 GNUNET_STATISTICS_update (stats,
1760 gettext_noop ("# bytes in message queue for other peers"),
1761 - (int64_t) mq->message_buf_size,
1763 GNUNET_STATISTICS_update (stats,
1764 gettext_noop ("# bytes pending with plugins"),
1765 mq->message_buf_size,
1767 ret = rl->plugin->api->send (rl->plugin->api->cls,
1770 mq->message_buf_size,
1772 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1773 mq->specific_address->session,
1774 mq->specific_address->addr,
1775 mq->specific_address->addrlen,
1777 &transmit_send_continuation, mq);
1780 /* failure, but 'send' would not call continuation in this case,
1781 so we need to do it here! */
1782 transmit_send_continuation (mq,
1790 * Send the specified message to the specified peer.
1792 * @param client source of the transmission request (can be NULL)
1793 * @param peer_address ForeignAddressList where we should send this message
1794 * @param priority how important is the message
1795 * @param timeout how long do we have to transmit?
1796 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1797 * @param message_buf_size total size of all messages in message_buf
1798 * @param is_internal is this an internal message; these are pre-pended and
1799 * also do not count for plugins being "ready" to transmit
1800 * @param neighbour handle to the neighbour for transmission
1803 transmit_to_peer (struct TransportClient *client,
1804 struct ForeignAddressList *peer_address,
1805 unsigned int priority,
1806 struct GNUNET_TIME_Relative timeout,
1807 const char *message_buf,
1808 size_t message_buf_size,
1809 int is_internal, struct NeighbourList *neighbour)
1811 struct MessageQueue *mq;
1816 /* check for duplicate submission */
1817 mq = neighbour->messages_head;
1820 if (mq->client == client)
1822 /* client transmitted to same peer twice
1823 before getting SEND_OK! */
1831 GNUNET_STATISTICS_update (stats,
1832 gettext_noop ("# bytes in message queue for other peers"),
1835 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1836 mq->specific_address = peer_address;
1837 mq->client = client;
1838 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1839 memcpy (&mq[1], message_buf, message_buf_size);
1840 mq->message_buf = (const char*) &mq[1];
1841 mq->message_buf_size = message_buf_size;
1842 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1843 mq->internal_msg = is_internal;
1844 mq->priority = priority;
1845 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1847 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1848 neighbour->messages_tail,
1851 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1852 neighbour->messages_tail,
1853 neighbour->messages_tail,
1855 try_transmission_to_peer (neighbour);
1862 struct GeneratorContext
1864 struct TransportPlugin *plug_pos;
1865 struct OwnAddressList *addr_pos;
1866 struct GNUNET_TIME_Absolute expiration;
1874 address_generator (void *cls, size_t max, void *buf)
1876 struct GeneratorContext *gc = cls;
1879 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1881 gc->plug_pos = gc->plug_pos->next;
1882 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1884 if (NULL == gc->plug_pos)
1889 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1892 gc->addr_pos->addrlen, buf, max);
1893 gc->addr_pos = gc->addr_pos->next;
1899 * Construct our HELLO message from all of the addresses of
1900 * all of the transports.
1905 struct GNUNET_HELLO_Message *hello;
1906 struct TransportClient *cpos;
1907 struct NeighbourList *npos;
1908 struct GeneratorContext gc;
1910 gc.plug_pos = plugins;
1911 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1912 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1913 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1916 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1918 GNUNET_STATISTICS_update (stats,
1919 gettext_noop ("# refreshed my HELLO"),
1923 while (cpos != NULL)
1925 transmit_to_client (cpos,
1926 (const struct GNUNET_MessageHeader *) hello,
1931 GNUNET_free_non_null (our_hello);
1933 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1935 while (npos != NULL)
1938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1939 "Transmitting updated `%s' to neighbour `%4s'\n",
1940 "HELLO", GNUNET_i2s (&npos->id));
1942 GNUNET_STATISTICS_update (stats,
1943 gettext_noop ("# transmitted my HELLO to other peers"),
1946 transmit_to_peer (NULL, NULL, 0,
1947 HELLO_ADDRESS_EXPIRATION,
1948 (const char *) our_hello,
1949 GNUNET_HELLO_size(our_hello),
1957 * Task used to clean up expired addresses for a plugin.
1959 * @param cls closure
1963 expire_address_task (void *cls,
1964 const struct GNUNET_SCHEDULER_TaskContext *tc);
1968 * Update the list of addresses for this plugin,
1969 * expiring those that are past their expiration date.
1971 * @param plugin addresses of which plugin should be recomputed?
1972 * @param fresh set to GNUNET_YES if a new address was added
1973 * and we need to regenerate the HELLO even if nobody
1977 update_addresses (struct TransportPlugin *plugin,
1980 static struct GNUNET_TIME_Absolute last_update;
1981 struct GNUNET_TIME_Relative min_remaining;
1982 struct GNUNET_TIME_Relative remaining;
1983 struct GNUNET_TIME_Absolute now;
1984 struct OwnAddressList *pos;
1985 struct OwnAddressList *prev;
1986 struct OwnAddressList *next;
1989 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1990 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1991 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1992 now = GNUNET_TIME_absolute_get ();
1993 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1994 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
1996 pos = plugin->addresses;
2000 if (pos->expires.abs_value < now.abs_value)
2002 expired = GNUNET_YES;
2004 plugin->addresses = pos->next;
2006 prev->next = pos->next;
2011 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2012 if (remaining.rel_value < min_remaining.rel_value)
2013 min_remaining = remaining;
2019 if (expired || fresh)
2024 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2025 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2027 plugin->address_update_task
2028 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2029 &expire_address_task, plugin);
2034 * Task used to clean up expired addresses for a plugin.
2036 * @param cls closure
2040 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2042 struct TransportPlugin *plugin = cls;
2044 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2045 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2046 update_addresses (plugin, GNUNET_NO);
2051 * Iterator over hash map entries that NULLs the session of validation
2052 * entries that match the given session.
2054 * @param cls closure (the 'struct Session*' to match against)
2055 * @param key current key code (peer ID, not used)
2056 * @param value value in the hash map ('struct ValidationEntry*')
2057 * @return GNUNET_YES (we should continue to iterate)
2060 remove_session_validations (void *cls,
2061 const GNUNET_HashCode * key,
2064 struct Session *session = cls;
2065 struct ValidationEntry *ve = value;
2067 if (session == ve->session)
2074 * We've been disconnected from the other peer (for some
2075 * connection-oriented transport). Either quickly
2076 * re-establish the connection or signal the disconnect
2079 * Only signal CORE level disconnect if ALL addresses
2080 * for the peer are exhausted.
2082 * @param p overall plugin context
2083 * @param nl neighbour that was disconnected
2086 try_fast_reconnect (struct TransportPlugin *p,
2087 struct NeighbourList *nl)
2089 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2090 /* Note: the idea here is to hide problems with transports (or
2091 switching between plugins) from the core to eliminate the need to
2092 re-negotiate session keys and the like; OTOH, we should tell core
2093 quickly (much faster than timeout) `if a connection was lost and
2094 could not be re-established (i.e. other peer went down or is
2095 unable / refuses to communicate);
2097 So we should consider:
2098 1) ideally: our own willingness / need to connect
2099 2) prior failures to connect to this peer (by plugin)
2100 3) ideally: reasons why other peer terminated (as far as knowable)
2102 Most importantly, it must be POSSIBLE for another peer to terminate
2103 a connection for a while (without us instantly re-establishing it).
2104 Similarly, if another peer is gone we should quickly notify CORE.
2105 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2106 on the other end), we should reconnect in such a way that BOTH CORE
2107 services never even notice.
2108 Furthermore, the same mechanism (or small variation) could be used
2109 to switch to a better-performing plugin (ATS).
2111 Finally, this needs to be tested throughly... */
2114 * GNUNET_NO in the call below makes transport disconnect the peer,
2115 * even if only a single address (out of say, six) went away. This
2116 * function must be careful to ONLY disconnect if the peer is gone,
2117 * not just a specifi address.
2119 * More specifically, half the places it was used had it WRONG.
2122 /* No reconnect, signal disconnect instead! */
2123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2124 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2125 "try_fast_reconnect");
2126 disconnect_neighbour (nl, GNUNET_YES);
2131 * Function that will be called whenever the plugin internally
2132 * cleans up a session pointer and hence the service needs to
2133 * discard all of those sessions as well. Plugins that do not
2134 * use sessions can simply omit calling this function and always
2135 * use NULL wherever a session pointer is needed.
2137 * @param cls closure
2138 * @param peer which peer was the session for
2139 * @param session which session is being destoyed
2142 plugin_env_session_end (void *cls,
2143 const struct GNUNET_PeerIdentity *peer,
2144 struct Session *session)
2146 struct TransportPlugin *p = cls;
2147 struct NeighbourList *nl;
2148 struct ReadyList *rl;
2149 struct ForeignAddressList *pos;
2150 struct ForeignAddressList *prev;
2152 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2153 &remove_session_validations,
2155 nl = find_neighbour (peer);
2157 return; /* was never marked as connected */
2161 if (rl->plugin == p)
2166 return; /* was never marked as connected */
2168 pos = rl->addresses;
2169 while ( (pos != NULL) &&
2170 (pos->session != session) )
2176 return; /* was never marked as connected */
2177 pos->session = NULL;
2178 if (pos->addrlen != 0)
2180 if (nl->received_pong != GNUNET_NO)
2181 try_fast_reconnect (p, nl);
2184 /* was inbound connection, free 'pos' */
2186 rl->addresses = pos->next;
2188 prev->next = pos->next;
2189 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2191 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2192 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2195 if (nl->received_pong == GNUNET_NO)
2196 return; /* nothing to do, never connected... */
2197 /* check if we have any validated addresses left */
2198 pos = rl->addresses;
2203 try_fast_reconnect (p, nl);
2208 /* no valid addresses left, signal disconnect! */
2210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2211 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2212 "plugin_env_session_end");
2213 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2214 * it means there aren't any left for this PLUGIN/PEER combination! So
2215 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2216 * when it isn't necessary. Using GNUNET_YES at least checks to see
2217 * if there are any addresses that work first, so as not to overdo it.
2220 disconnect_neighbour (nl, GNUNET_YES);
2225 * Function that must be called by each plugin to notify the
2226 * transport service about the addresses under which the transport
2227 * provided by the plugin can be reached.
2229 * @param cls closure
2230 * @param name name of the transport that generated the address
2231 * @param addr one of the addresses of the host, NULL for the last address
2232 * the specific address format depends on the transport
2233 * @param addrlen length of the address
2234 * @param expires when should this address automatically expire?
2237 plugin_env_notify_address (void *cls,
2241 struct GNUNET_TIME_Relative expires)
2243 struct TransportPlugin *p = cls;
2244 struct OwnAddressList *al;
2245 struct GNUNET_TIME_Absolute abex;
2247 GNUNET_assert (addr != NULL);
2248 abex = GNUNET_TIME_relative_to_absolute (expires);
2249 GNUNET_assert (p == find_transport (name));
2253 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2256 update_addresses (p, GNUNET_NO);
2262 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2263 al->next = p->addresses;
2266 al->addrlen = addrlen;
2267 memcpy (&al[1], addr, addrlen);
2268 update_addresses (p, GNUNET_YES);
2273 * Notify all of our clients about a peer connecting.
2276 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2277 struct GNUNET_TIME_Relative latency,
2280 struct ConnectInfoMessage * cim;
2281 struct TransportClient *cpos;
2286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2287 "Notifying clients about connection from `%s'\n",
2290 GNUNET_STATISTICS_update (stats,
2291 gettext_noop ("# peers connected"),
2296 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2297 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2301 cim = GNUNET_malloc (size);
2303 cim->header.size = htons (size);
2304 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2305 cim->ats_count = htonl(2);
2306 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2307 (&(cim->ats))[0].value = htonl (distance);
2308 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2309 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2310 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2311 (&(cim->ats))[2].value = htonl (0);
2312 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2314 /* notify ats about connecting peer */
2315 ats_notify_peer_connect (peer, &(cim->ats));
2318 while (cpos != NULL)
2320 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2329 * Notify all of our clients about a peer disconnecting.
2332 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2334 struct DisconnectInfoMessage dim;
2335 struct TransportClient *cpos;
2338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2339 "Notifying clients about lost connection to `%s'\n",
2342 GNUNET_STATISTICS_update (stats,
2343 gettext_noop ("# peers connected"),
2346 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2347 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2348 dim.reserved = htonl (0);
2349 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2351 /* notify ats about connecting peer */
2352 ats_notify_peer_disconnect (peer);
2355 while (cpos != NULL)
2357 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2364 * Find a ForeignAddressList entry for the given neighbour
2365 * that matches the given address and transport.
2367 * @param neighbour which peer we care about
2368 * @param tname name of the transport plugin
2369 * @param session session to look for, NULL for 'any'; otherwise
2370 * can be used for the service to "learn" this session ID
2372 * @param addr binary address
2373 * @param addrlen length of addr
2374 * @return NULL if no such entry exists
2376 static struct ForeignAddressList *
2377 find_peer_address(struct NeighbourList *neighbour,
2379 struct Session *session,
2383 struct ReadyList *head;
2384 struct ForeignAddressList *pos;
2386 head = neighbour->plugins;
2387 while (head != NULL)
2389 if (0 == strcmp (tname, head->plugin->short_name))
2395 pos = head->addresses;
2396 while ( (pos != NULL) &&
2397 ( (pos->addrlen != addrlen) ||
2398 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2400 if ( (session != NULL) &&
2401 (pos->session == session) )
2405 if ( (session != NULL) && (pos != NULL) )
2406 pos->session = session; /* learn it! */
2412 * Get the peer address struct for the given neighbour and
2413 * address. If it doesn't yet exist, create it.
2415 * @param neighbour which peer we care about
2416 * @param tname name of the transport plugin
2417 * @param session session of the plugin, or NULL for none
2418 * @param addr binary address
2419 * @param addrlen length of addr
2420 * @return NULL if we do not have a transport plugin for 'tname'
2422 static struct ForeignAddressList *
2423 add_peer_address (struct NeighbourList *neighbour,
2425 struct Session *session,
2429 struct ReadyList *head;
2430 struct ForeignAddressList *ret;
2432 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2435 head = neighbour->plugins;
2437 while (head != NULL)
2439 if (0 == strcmp (tname, head->plugin->short_name))
2445 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2446 ret->session = session;
2449 ret->addr = (const char*) &ret[1];
2450 memcpy (&ret[1], addr, addrlen);
2456 ret->addrlen = addrlen;
2457 ret->expires = GNUNET_TIME_relative_to_absolute
2458 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2459 ret->latency = GNUNET_TIME_relative_get_forever();
2461 ret->timeout = GNUNET_TIME_relative_to_absolute
2462 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2463 ret->ready_list = head;
2464 ret->next = head->addresses;
2465 head->addresses = ret;
2471 * Closure for 'add_validated_address'.
2473 struct AddValidatedAddressContext
2476 * Entry that has been validated.
2478 const struct ValidationEntry *ve;
2481 * Flag set after we have added the address so
2482 * that we terminate the iteration next time.
2489 * Callback function used to fill a buffer of max bytes with a list of
2490 * addresses in the format used by HELLOs. Should use
2491 * "GNUNET_HELLO_add_address" as a helper function.
2493 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2494 * @param max maximum number of bytes that can be written to buf
2495 * @param buf where to write the address information
2496 * @return number of bytes written, 0 to signal the
2497 * end of the iteration.
2500 add_validated_address (void *cls,
2501 size_t max, void *buf)
2503 struct AddValidatedAddressContext *avac = cls;
2504 const struct ValidationEntry *ve = avac->ve;
2506 if (GNUNET_YES == avac->done)
2508 avac->done = GNUNET_YES;
2509 return GNUNET_HELLO_add_address (ve->transport_name,
2510 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2520 * Closure for 'check_address_exists'.
2522 struct CheckAddressExistsClosure
2525 * Address to check for.
2530 * Name of the transport.
2537 struct Session *session;
2540 * Set to GNUNET_YES if the address exists.
2553 * Iterator over hash map entries. Checks if the given
2554 * validation entry is for the same address as what is given
2557 * @param cls the 'struct CheckAddressExistsClosure*'
2558 * @param key current key code (ignored)
2559 * @param value value in the hash map ('struct ValidationEntry')
2560 * @return GNUNET_YES if we should continue to
2561 * iterate (mismatch), GNUNET_NO if not (entry matched)
2564 check_address_exists (void *cls,
2565 const GNUNET_HashCode * key,
2568 struct CheckAddressExistsClosure *caec = cls;
2569 struct ValidationEntry *ve = value;
2571 if ( (0 == strcmp (caec->tname,
2572 ve->transport_name)) &&
2573 (caec->addrlen == ve->addrlen) &&
2574 (0 == memcmp (caec->addr,
2578 caec->exists = GNUNET_YES;
2581 if ( (ve->session != NULL) &&
2582 (caec->session == ve->session) )
2584 caec->exists = GNUNET_YES;
2593 * Iterator to free entries in the validation_map.
2595 * @param cls closure (unused)
2596 * @param key current key code
2597 * @param value value in the hash map (validation to abort)
2598 * @return GNUNET_YES (always)
2601 abort_validation (void *cls,
2602 const GNUNET_HashCode * key,
2605 struct ValidationEntry *va = value;
2607 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2608 GNUNET_SCHEDULER_cancel (va->timeout_task);
2609 GNUNET_free (va->transport_name);
2610 if (va->chvc != NULL)
2612 va->chvc->ve_count--;
2613 if (va->chvc->ve_count == 0)
2615 GNUNET_CONTAINER_DLL_remove (chvc_head,
2618 GNUNET_free (va->chvc);
2628 * HELLO validation cleanup task (validation failed).
2630 * @param cls the 'struct ValidationEntry' that failed
2631 * @param tc scheduler context (unused)
2634 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2636 struct ValidationEntry *va = cls;
2637 struct GNUNET_PeerIdentity pid;
2639 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2640 GNUNET_STATISTICS_update (stats,
2641 gettext_noop ("# address validation timeouts"),
2644 GNUNET_CRYPTO_hash (&va->publicKey,
2646 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2648 GNUNET_break (GNUNET_OK ==
2649 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2652 abort_validation (NULL, NULL, va);
2657 neighbour_timeout_task (void *cls,
2658 const struct GNUNET_SCHEDULER_TaskContext *tc)
2660 struct NeighbourList *n = cls;
2663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2664 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2666 GNUNET_STATISTICS_update (stats,
2667 gettext_noop ("# disconnects due to timeout"),
2670 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2671 disconnect_neighbour (n, GNUNET_NO);
2676 * Schedule the job that will cause us to send a PING to the
2677 * foreign address to evaluate its validity and latency.
2679 * @param fal address to PING
2682 schedule_next_ping (struct ForeignAddressList *fal);
2686 * Add the given address to the list of foreign addresses
2687 * available for the given peer (check for duplicates).
2689 * @param cls the respective 'struct NeighbourList' to update
2690 * @param tname name of the transport
2691 * @param expiration expiration time
2692 * @param addr the address
2693 * @param addrlen length of the address
2694 * @return GNUNET_OK (always)
2697 add_to_foreign_address_list (void *cls,
2699 struct GNUNET_TIME_Absolute expiration,
2703 struct NeighbourList *n = cls;
2704 struct ForeignAddressList *fal;
2707 GNUNET_STATISTICS_update (stats,
2708 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2712 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2715 #if DEBUG_TRANSPORT_HELLO
2716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2717 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2718 a2s (tname, addr, addrlen),
2720 GNUNET_i2s (&n->id),
2721 expiration.abs_value);
2723 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2726 GNUNET_STATISTICS_update (stats,
2727 gettext_noop ("# previously validated addresses lacking transport"),
2733 fal->expires = GNUNET_TIME_absolute_max (expiration,
2735 schedule_next_ping (fal);
2741 fal->expires = GNUNET_TIME_absolute_max (expiration,
2746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2747 "Failed to add new address for `%4s'\n",
2748 GNUNET_i2s (&n->id));
2751 if (fal->validated == GNUNET_NO)
2753 fal->validated = GNUNET_YES;
2754 GNUNET_STATISTICS_update (stats,
2755 gettext_noop ("# peer addresses considered valid"),
2759 if (try == GNUNET_YES)
2761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2762 "Have new addresses, will try to trigger transmissions.\n");
2763 try_transmission_to_peer (n);
2770 * Add addresses in validated HELLO "h" to the set of addresses
2771 * we have for this peer.
2773 * @param cls closure ('struct NeighbourList*')
2774 * @param peer id of the peer, NULL for last call
2775 * @param h hello message for the peer (can be NULL)
2776 * @param err_msg NULL if successful, otherwise contains error message
2779 add_hello_for_peer (void *cls,
2780 const struct GNUNET_PeerIdentity *peer,
2781 const struct GNUNET_HELLO_Message *h,
2782 const char *err_msg)
2784 struct NeighbourList *n = cls;
2786 if (err_msg != NULL)
2788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2789 _("Error in communication with PEERINFO service\n"));
2794 GNUNET_STATISTICS_update (stats,
2795 gettext_noop ("# outstanding peerinfo iterate requests"),
2802 return; /* no HELLO available */
2804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2805 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2809 if (GNUNET_YES != n->public_key_valid)
2811 GNUNET_HELLO_get_key (h, &n->publicKey);
2812 n->public_key_valid = GNUNET_YES;
2814 GNUNET_HELLO_iterate_addresses (h,
2816 &add_to_foreign_address_list,
2822 * Create a fresh entry in our neighbour list for the given peer.
2823 * Will try to transmit our current HELLO to the new neighbour.
2824 * Do not call this function directly, use 'setup_peer_check_blacklist.
2826 * @param peer the peer for which we create the entry
2827 * @param do_hello should we schedule transmitting a HELLO
2828 * @return the new neighbour list entry
2830 static struct NeighbourList *
2831 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2834 struct NeighbourList *n;
2835 struct TransportPlugin *tp;
2836 struct ReadyList *rl;
2839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2840 "Setting up state for neighbour `%4s'\n",
2843 GNUNET_assert (our_hello != NULL);
2844 GNUNET_STATISTICS_update (stats,
2845 gettext_noop ("# active neighbours"),
2848 n = GNUNET_malloc (sizeof (struct NeighbourList));
2849 n->next = neighbours;
2853 GNUNET_TIME_relative_to_absolute
2854 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2855 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2856 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2857 MAX_BANDWIDTH_CARRY_S);
2861 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2863 rl = GNUNET_malloc (sizeof (struct ReadyList));
2865 rl->next = n->plugins;
2868 rl->addresses = NULL;
2872 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2874 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2875 &neighbour_timeout_task, n);
2878 GNUNET_STATISTICS_update (stats,
2879 gettext_noop ("# peerinfo new neighbor iterate requests"),
2882 GNUNET_STATISTICS_update (stats,
2883 gettext_noop ("# outstanding peerinfo iterate requests"),
2886 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2887 GNUNET_TIME_UNIT_FOREVER_REL,
2888 &add_hello_for_peer, n);
2890 GNUNET_STATISTICS_update (stats,
2891 gettext_noop ("# HELLO's sent to new neighbors"),
2894 transmit_to_peer (NULL, NULL, 0,
2895 HELLO_ADDRESS_EXPIRATION,
2896 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2904 * Function called after we have checked if communicating
2905 * with a given peer is acceptable.
2907 * @param cls closure
2908 * @param n NULL if communication is not acceptable
2910 typedef void (*SetupContinuation)(void *cls,
2911 struct NeighbourList *n);
2915 * Information kept for each client registered to perform
2921 * This is a linked list.
2923 struct Blacklisters *next;
2926 * This is a linked list.
2928 struct Blacklisters *prev;
2931 * Client responsible for this entry.
2933 struct GNUNET_SERVER_Client *client;
2936 * Blacklist check that we're currently performing.
2938 struct BlacklistCheck *bc;
2944 * Head of DLL of blacklisting clients.
2946 static struct Blacklisters *bl_head;
2949 * Tail of DLL of blacklisting clients.
2951 static struct Blacklisters *bl_tail;
2955 * Context we use when performing a blacklist check.
2957 struct BlacklistCheck
2961 * This is a linked list.
2963 struct BlacklistCheck *next;
2966 * This is a linked list.
2968 struct BlacklistCheck *prev;
2971 * Peer being checked.
2973 struct GNUNET_PeerIdentity peer;
2976 * Option for setup neighbour afterwards.
2981 * Continuation to call with the result.
2983 SetupContinuation cont;
2991 * Current transmission request handle for this client, or NULL if no
2992 * request is pending.
2994 struct GNUNET_CONNECTION_TransmitHandle *th;
2997 * Our current position in the blacklisters list.
2999 struct Blacklisters *bl_pos;
3002 * Current task performing the check.
3004 GNUNET_SCHEDULER_TaskIdentifier task;
3009 * Head of DLL of active blacklisting queries.
3011 static struct BlacklistCheck *bc_head;
3014 * Tail of DLL of active blacklisting queries.
3016 static struct BlacklistCheck *bc_tail;
3020 * Perform next action in the blacklist check.
3022 * @param cls the 'struct BlacklistCheck*'
3026 do_blacklist_check (void *cls,
3027 const struct GNUNET_SCHEDULER_TaskContext *tc);
3030 * Transmit blacklist query to the client.
3032 * @param cls the 'struct BlacklistCheck'
3033 * @param size number of bytes allowed
3034 * @param buf where to copy the message
3035 * @return number of bytes copied to buf
3038 transmit_blacklist_message (void *cls,
3042 struct BlacklistCheck *bc = cls;
3043 struct Blacklisters *bl;
3044 struct BlacklistMessage bm;
3049 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3050 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3055 bm.header.size = htons (sizeof (struct BlacklistMessage));
3056 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3057 bm.is_allowed = htonl (0);
3059 memcpy (buf, &bm, sizeof (bm));
3060 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3066 * Perform next action in the blacklist check.
3068 * @param cls the 'struct BlacklistCheck*'
3072 do_blacklist_check (void *cls,
3073 const struct GNUNET_SCHEDULER_TaskContext *tc)
3075 struct BlacklistCheck *bc = cls;
3076 struct Blacklisters *bl;
3078 bc->task = GNUNET_SCHEDULER_NO_TASK;
3082 bc->cont (bc->cont_cls,
3083 setup_new_neighbour (&bc->peer, bc->do_hello));
3090 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3091 sizeof (struct BlacklistMessage),
3092 GNUNET_TIME_UNIT_FOREVER_REL,
3093 &transmit_blacklist_message,
3100 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3101 * does not yet exist, check the blacklist. If the blacklist says creating
3102 * one is acceptable, create one and call the continuation; otherwise
3103 * call the continuation with NULL.
3105 * @param peer peer to setup or look up a struct NeighbourList for
3106 * @param do_hello should we also schedule sending our HELLO to the peer
3107 * if this is a new record
3108 * @param cont function to call with the 'struct NeigbhbourList*'
3109 * @param cont_cls closure for cont
3112 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3114 SetupContinuation cont,
3117 struct NeighbourList *n;
3118 struct BlacklistCheck *bc;
3120 n = find_neighbour(peer);
3127 if (bl_head == NULL)
3130 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3132 setup_new_neighbour(peer, do_hello);
3135 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3136 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3138 bc->do_hello = do_hello;
3140 bc->cont_cls = cont_cls;
3141 bc->bl_pos = bl_head;
3142 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3148 * Function called with the result of querying a new blacklister about
3149 * it being allowed (or not) to continue to talk to an existing neighbour.
3151 * @param cls the original 'struct NeighbourList'
3152 * @param n NULL if we need to disconnect
3155 confirm_or_drop_neighbour (void *cls,
3156 struct NeighbourList *n)
3158 struct NeighbourList * orig = cls;
3162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3163 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3164 "confirm_or_drop_neighboUr");
3165 disconnect_neighbour (orig, GNUNET_NO);
3171 * Handle a request to start a blacklist.
3173 * @param cls closure (always NULL)
3174 * @param client identification of the client
3175 * @param message the actual message
3178 handle_blacklist_init (void *cls,
3179 struct GNUNET_SERVER_Client *client,
3180 const struct GNUNET_MessageHeader *message)
3182 struct Blacklisters *bl;
3183 struct BlacklistCheck *bc;
3184 struct NeighbourList *n;
3189 if (bl->client == client)
3192 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3197 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3198 bl->client = client;
3199 GNUNET_SERVER_client_keep (client);
3200 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3201 /* confirm that all existing connections are OK! */
3205 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3206 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3208 bc->do_hello = GNUNET_NO;
3209 bc->cont = &confirm_or_drop_neighbour;
3212 if (n == neighbours) /* all would wait for the same client, no need to
3213 create more than just the first task right now */
3214 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3222 * Handle a request to blacklist a peer.
3224 * @param cls closure (always NULL)
3225 * @param client identification of the client
3226 * @param message the actual message
3229 handle_blacklist_reply (void *cls,
3230 struct GNUNET_SERVER_Client *client,
3231 const struct GNUNET_MessageHeader *message)
3233 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3234 struct Blacklisters *bl;
3235 struct BlacklistCheck *bc;
3238 while ( (bl != NULL) &&
3239 (bl->client != client) )
3243 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3248 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3250 bc->cont (bc->cont_cls, NULL);
3251 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3256 bc->bl_pos = bc->bl_pos->next;
3257 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3260 /* check if any other bc's are waiting for this blacklister */
3264 if ( (bc->bl_pos == bl) &&
3265 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3266 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3274 * Send periodic PING messages to a given foreign address.
3276 * @param cls our 'struct PeriodicValidationContext*'
3277 * @param tc task context
3280 send_periodic_ping (void *cls,
3281 const struct GNUNET_SCHEDULER_TaskContext *tc)
3283 struct ForeignAddressList *peer_address = cls;
3284 struct TransportPlugin *tp;
3285 struct ValidationEntry *va;
3286 struct NeighbourList *neighbour;
3287 struct TransportPingMessage ping;
3288 struct CheckAddressExistsClosure caec;
3290 uint16_t hello_size;
3294 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3295 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3297 tp = peer_address->ready_list->plugin;
3298 neighbour = peer_address->ready_list->neighbour;
3299 if (GNUNET_YES != neighbour->public_key_valid)
3301 /* no public key yet, try again later */
3302 schedule_next_ping (peer_address);
3305 caec.addr = peer_address->addr;
3306 caec.addrlen = peer_address->addrlen;
3307 caec.tname = tp->short_name;
3308 caec.session = peer_address->session;
3309 caec.exists = GNUNET_NO;
3310 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3311 &check_address_exists,
3313 if (caec.exists == GNUNET_YES)
3315 /* During validation attempts we will likely trigger the other
3316 peer trying to validate our address which in turn will cause
3317 it to send us its HELLO, so we expect to hit this case rather
3318 frequently. Only print something if we are very verbose. */
3319 #if DEBUG_TRANSPORT > 1
3320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3321 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3322 (peer_address->addr != NULL)
3323 ? a2s (tp->short_name,
3325 peer_address->addrlen)
3328 GNUNET_i2s (&neighbour->id));
3330 schedule_next_ping (peer_address);
3333 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3334 va->transport_name = GNUNET_strdup (tp->short_name);
3335 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3337 va->send_time = GNUNET_TIME_absolute_get();
3338 va->session = peer_address->session;
3339 if (peer_address->addr != NULL)
3341 va->addr = (const void*) &va[1];
3342 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3343 va->addrlen = peer_address->addrlen;
3345 memcpy(&va->publicKey,
3346 &neighbour->publicKey,
3347 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3349 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3350 &timeout_hello_validation,
3352 GNUNET_CONTAINER_multihashmap_put (validation_map,
3353 &neighbour->id.hashPubKey,
3355 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3357 if (peer_address->validated != GNUNET_YES)
3358 hello_size = GNUNET_HELLO_size(our_hello);
3362 tsize = sizeof(struct TransportPingMessage) + hello_size;
3364 if (peer_address->addr != NULL)
3366 slen = strlen (tp->short_name) + 1;
3367 tsize += slen + peer_address->addrlen;
3371 slen = 0; /* make gcc happy */
3373 message_buf = GNUNET_malloc(tsize);
3374 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3375 ping.challenge = htonl(va->challenge);
3376 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3377 if (peer_address->validated != GNUNET_YES)
3379 memcpy(message_buf, our_hello, hello_size);
3382 if (peer_address->addr != NULL)
3384 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3385 peer_address->addrlen +
3387 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3390 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3392 peer_address->addrlen);
3396 ping.header.size = htons(sizeof(struct TransportPingMessage));
3399 memcpy(&message_buf[hello_size],
3401 sizeof(struct TransportPingMessage));
3403 #if DEBUG_TRANSPORT_REVALIDATION
3404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3405 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3406 (peer_address->addr != NULL)
3407 ? a2s (peer_address->plugin->short_name,
3409 peer_address->addrlen)
3412 GNUNET_i2s (&neighbour->id),
3413 "HELLO", hello_size,
3416 if (peer_address->validated != GNUNET_YES)
3417 GNUNET_STATISTICS_update (stats,
3418 gettext_noop ("# PING with HELLO messages sent"),
3422 GNUNET_STATISTICS_update (stats,
3423 gettext_noop ("# PING without HELLO messages sent"),
3426 GNUNET_STATISTICS_update (stats,
3427 gettext_noop ("# PING messages sent for re-validation"),
3430 transmit_to_peer (NULL, peer_address,
3431 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3432 HELLO_VERIFICATION_TIMEOUT,
3434 GNUNET_YES, neighbour);
3435 GNUNET_free(message_buf);
3436 schedule_next_ping (peer_address);
3441 * Schedule the job that will cause us to send a PING to the
3442 * foreign address to evaluate its validity and latency.
3444 * @param fal address to PING
3447 schedule_next_ping (struct ForeignAddressList *fal)
3449 struct GNUNET_TIME_Relative delay;
3451 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3453 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3454 delay.rel_value /= 2; /* do before expiration */
3455 delay = GNUNET_TIME_relative_min (delay,
3456 LATENCY_EVALUATION_MAX_DELAY);
3457 if (GNUNET_YES != fal->estimated)
3459 delay = GNUNET_TIME_UNIT_ZERO;
3460 fal->estimated = GNUNET_YES;
3462 if (GNUNET_YES == fal->connected)
3464 delay = GNUNET_TIME_relative_min (delay,
3465 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3467 /* FIXME: also adjust delay based on how close the last
3468 observed latency is to the latency of the best alternative */
3469 /* bound how fast we can go */
3470 delay = GNUNET_TIME_relative_max (delay,
3471 GNUNET_TIME_UNIT_SECONDS);
3472 /* randomize a bit (to avoid doing all at the same time) */
3473 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3474 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3475 &send_periodic_ping,
3483 * Function that will be called if we receive some payload
3484 * from another peer.
3486 * @param message the payload
3487 * @param n peer who claimed to be the sender
3490 handle_payload_message (const struct GNUNET_MessageHeader *message,
3491 struct NeighbourList *n)
3493 struct InboundMessage *im;
3494 struct TransportClient *cpos;
3497 msize = ntohs (message->size);
3498 if (n->received_pong == GNUNET_NO)
3500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3501 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3502 ntohs (message->type),
3503 ntohs (message->size),
3504 GNUNET_i2s (&n->id));
3505 GNUNET_free_non_null (n->pre_connect_message_buffer);
3506 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3507 memcpy (n->pre_connect_message_buffer, message, msize);
3512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3513 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3514 ntohs (message->type),
3515 ntohs (message->size),
3516 GNUNET_i2s (&n->id));
3518 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3521 n->quota_violation_count++;
3523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3524 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3525 n->in_tracker.available_bytes_per_s__,
3526 n->quota_violation_count);
3528 /* Discount 32k per violation */
3529 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3534 if (n->quota_violation_count > 0)
3536 /* try to add 32k back */
3537 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3539 n->quota_violation_count--;
3542 GNUNET_STATISTICS_update (stats,
3543 gettext_noop ("# payload received from other peers"),
3546 /* transmit message to all clients */
3547 uint32_t ats_count = 2;
3548 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3549 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3552 im = GNUNET_malloc (size);
3553 im->header.size = htons (size);
3554 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3556 im->ats_count = htonl(ats_count);
3557 /* Setting ATS data */
3558 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3559 (&(im->ats))[0].value = htonl (n->distance);
3560 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3561 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3562 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3563 (&(im->ats))[ats_count].value = htonl (0);
3565 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3567 while (cpos != NULL)
3569 transmit_to_client (cpos, &im->header, GNUNET_YES);
3577 * Iterator over hash map entries. Checks if the given validation
3578 * entry is for the same challenge as what is given in the PONG.
3580 * @param cls the 'struct TransportPongMessage*'
3581 * @param key peer identity
3582 * @param value value in the hash map ('struct ValidationEntry')
3583 * @return GNUNET_YES if we should continue to
3584 * iterate (mismatch), GNUNET_NO if not (entry matched)
3587 check_pending_validation (void *cls,
3588 const GNUNET_HashCode * key,
3591 const struct TransportPongMessage *pong = cls;
3592 struct ValidationEntry *ve = value;
3593 struct AddValidatedAddressContext avac;
3594 unsigned int challenge = ntohl(pong->challenge);
3595 struct GNUNET_HELLO_Message *hello;
3596 struct GNUNET_PeerIdentity target;
3597 struct NeighbourList *n;
3598 struct ForeignAddressList *fal;
3599 struct OwnAddressList *oal;
3600 struct TransportPlugin *tp;
3601 struct GNUNET_MessageHeader *prem;
3607 ps = ntohs (pong->header.size);
3608 if (ps < sizeof (struct TransportPongMessage))
3610 GNUNET_break_op (0);
3613 addr = (const char*) &pong[1];
3614 slen = strlen (ve->transport_name) + 1;
3615 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3616 (ve->challenge != challenge) ||
3617 (addr[slen-1] != '\0') ||
3618 (0 != strcmp (addr, ve->transport_name)) ||
3619 (ntohl (pong->purpose.size)
3620 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3622 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3623 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3628 alen = ps - sizeof (struct TransportPongMessage) - slen;
3629 switch (ntohl (pong->purpose.purpose))
3631 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3632 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3633 (0 != memcmp (&addr[slen],
3637 return GNUNET_YES; /* different entry, keep trying! */
3639 if (0 != memcmp (&pong->pid,
3641 sizeof (struct GNUNET_PeerIdentity)))
3643 GNUNET_break_op (0);
3647 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3652 GNUNET_break_op (0);
3657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3658 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3660 a2s (ve->transport_name,
3661 (const struct sockaddr *) ve->addr,
3663 ve->transport_name);
3666 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3667 if (0 != memcmp (&pong->pid,
3669 sizeof (struct GNUNET_PeerIdentity)))
3671 GNUNET_break_op (0);
3674 if (ve->addrlen != 0)
3676 /* must have been for a different validation entry */
3679 tp = find_transport (ve->transport_name);
3685 oal = tp->addresses;
3688 if ( (oal->addrlen == alen) &&
3689 (0 == memcmp (&oal[1],
3697 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3698 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3699 a2s (ve->transport_name,
3705 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3710 GNUNET_break_op (0);
3715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3716 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3718 a2s (ve->transport_name,
3721 ve->transport_name);
3725 GNUNET_break_op (0);
3728 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3730 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3731 _("Received expired signature. Check system time.\n"));
3734 GNUNET_STATISTICS_update (stats,
3735 gettext_noop ("# address validation successes"),
3738 /* create the updated HELLO */
3739 GNUNET_CRYPTO_hash (&ve->publicKey,
3740 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3741 &target.hashPubKey);
3742 if (ve->addr != NULL)
3744 avac.done = GNUNET_NO;
3746 hello = GNUNET_HELLO_create (&ve->publicKey,
3747 &add_validated_address,
3749 GNUNET_PEERINFO_add_peer (peerinfo,
3751 GNUNET_free (hello);
3753 n = find_neighbour (&target);
3756 n->publicKey = ve->publicKey;
3757 n->public_key_valid = GNUNET_YES;
3758 fal = add_peer_address (n,
3763 GNUNET_assert (fal != NULL);
3764 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3765 fal->validated = GNUNET_YES;
3766 mark_address_connected (fal);
3767 GNUNET_STATISTICS_update (stats,
3768 gettext_noop ("# peer addresses considered valid"),
3771 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3772 schedule_next_ping (fal);
3773 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3774 n->latency = fal->latency;
3776 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3778 n->distance = fal->distance;
3779 if (GNUNET_NO == n->received_pong)
3781 n->received_pong = GNUNET_YES;
3783 notify_clients_connect (&target, n->latency, n->distance);
3784 if (NULL != (prem = n->pre_connect_message_buffer))
3786 n->pre_connect_message_buffer = NULL;
3787 handle_payload_message (prem, n);
3791 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3793 GNUNET_SCHEDULER_cancel (n->retry_task);
3794 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3795 try_transmission_to_peer (n);
3799 /* clean up validation entry */
3800 GNUNET_assert (GNUNET_YES ==
3801 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3804 abort_validation (NULL, NULL, ve);
3810 * Function that will be called if we receive a validation
3811 * of an address challenge that we transmitted to another
3812 * peer. Note that the validation should only be considered
3813 * acceptable if the challenge matches AND if the sender
3814 * address is at least a plausible address for this peer
3815 * (otherwise we may be seeing a MiM attack).
3817 * @param cls closure
3818 * @param message the pong message
3819 * @param peer who responded to our challenge
3820 * @param sender_address string describing our sender address (as observed
3821 * by the other peer in binary format)
3822 * @param sender_address_len number of bytes in 'sender_address'
3825 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3826 const struct GNUNET_PeerIdentity *peer,
3827 const char *sender_address,
3828 size_t sender_address_len)
3830 #if DEBUG_TRANSPORT > 1
3831 /* we get tons of these that just get discarded, only log
3832 if we are quite verbose */
3833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3834 "Receiving `%s' message from `%4s'.\n", "PONG",
3837 GNUNET_STATISTICS_update (stats,
3838 gettext_noop ("# PONG messages received"),
3841 if (GNUNET_SYSERR !=
3842 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3844 &check_pending_validation,
3847 /* This is *expected* to happen a lot since we send
3848 PONGs to *all* known addresses of the sender of
3849 the PING, so most likely we get multiple PONGs
3850 per PING, and all but the first PONG will end up
3851 here. So really we should not print anything here
3852 unless we want to be very, very verbose... */
3853 #if DEBUG_TRANSPORT > 2
3854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3855 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3867 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3869 * @param cls the 'struct ValidationEntry*'
3870 * @param neighbour neighbour to validate, NULL if validation failed
3873 transmit_hello_and_ping (void *cls,
3874 struct NeighbourList *neighbour)
3876 struct ValidationEntry *va = cls;
3877 struct ForeignAddressList *peer_address;
3878 struct TransportPingMessage ping;
3879 uint16_t hello_size;
3882 struct GNUNET_PeerIdentity id;
3885 GNUNET_CRYPTO_hash (&va->publicKey,
3886 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3888 if (neighbour == NULL)
3890 /* FIXME: stats... */
3891 GNUNET_break (GNUNET_OK ==
3892 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3895 abort_validation (NULL, NULL, va);
3898 neighbour->publicKey = va->publicKey;
3899 neighbour->public_key_valid = GNUNET_YES;
3900 peer_address = add_peer_address (neighbour,
3901 va->transport_name, NULL,
3902 (const void*) &va[1],
3904 if (peer_address == NULL)
3906 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3907 "Failed to add peer `%4s' for plugin `%s'\n",
3908 GNUNET_i2s (&neighbour->id),
3909 va->transport_name);
3910 GNUNET_break (GNUNET_OK ==
3911 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3914 abort_validation (NULL, NULL, va);
3917 hello_size = GNUNET_HELLO_size(our_hello);
3918 slen = strlen(va->transport_name) + 1;
3919 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3920 message_buf = GNUNET_malloc(tsize);
3921 ping.challenge = htonl(va->challenge);
3922 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3923 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3924 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3925 memcpy(message_buf, our_hello, hello_size);
3926 memcpy(&message_buf[hello_size],
3928 sizeof(struct TransportPingMessage));
3929 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3932 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3937 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3940 : a2s (va->transport_name,
3941 (const void*) &va[1], va->addrlen),
3943 GNUNET_i2s (&neighbour->id),
3944 "HELLO", hello_size,
3945 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3948 GNUNET_STATISTICS_update (stats,
3949 gettext_noop ("# PING messages sent for initial validation"),
3952 transmit_to_peer (NULL, peer_address,
3953 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3954 HELLO_VERIFICATION_TIMEOUT,
3956 GNUNET_YES, neighbour);
3957 GNUNET_free(message_buf);
3962 * Check if the given address is already being validated; if not,
3963 * append the given address to the list of entries that are being be
3964 * validated and initiate validation.
3966 * @param cls closure ('struct CheckHelloValidatedContext *')
3967 * @param tname name of the transport
3968 * @param expiration expiration time
3969 * @param addr the address
3970 * @param addrlen length of the address
3971 * @return GNUNET_OK (always)
3974 run_validation (void *cls,
3976 struct GNUNET_TIME_Absolute expiration,
3980 struct CheckHelloValidatedContext *chvc = cls;
3981 struct GNUNET_PeerIdentity id;
3982 struct TransportPlugin *tp;
3983 struct ValidationEntry *va;
3984 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3985 struct CheckAddressExistsClosure caec;
3986 struct OwnAddressList *oal;
3988 GNUNET_assert (addr != NULL);
3990 GNUNET_STATISTICS_update (stats,
3991 gettext_noop ("# peer addresses scheduled for validation"),
3994 tp = find_transport (tname);
3997 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3998 GNUNET_ERROR_TYPE_BULK,
4000 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4002 GNUNET_STATISTICS_update (stats,
4003 gettext_noop ("# peer addresses not validated (plugin not available)"),
4008 /* check if this is one of our own addresses */
4009 oal = tp->addresses;
4012 if ( (oal->addrlen == addrlen) &&
4013 (0 == memcmp (&oal[1],
4017 /* not plausible, this address is equivalent to our own address! */
4018 GNUNET_STATISTICS_update (stats,
4019 gettext_noop ("# peer addresses not validated (loopback)"),
4026 GNUNET_HELLO_get_key (chvc->hello, &pk);
4027 GNUNET_CRYPTO_hash (&pk,
4029 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4032 if (is_blacklisted(&id, tp))
4035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4036 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4044 caec.addrlen = addrlen;
4045 caec.session = NULL;
4047 caec.exists = GNUNET_NO;
4048 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4049 &check_address_exists,
4051 if (caec.exists == GNUNET_YES)
4053 /* During validation attempts we will likely trigger the other
4054 peer trying to validate our address which in turn will cause
4055 it to send us its HELLO, so we expect to hit this case rather
4056 frequently. Only print something if we are very verbose. */
4057 #if DEBUG_TRANSPORT > 1
4058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4059 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4060 a2s (tname, addr, addrlen),
4064 GNUNET_STATISTICS_update (stats,
4065 gettext_noop ("# peer addresses not validated (in progress)"),
4070 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4073 va->transport_name = GNUNET_strdup (tname);
4074 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4076 va->send_time = GNUNET_TIME_absolute_get();
4077 va->addr = (const void*) &va[1];
4078 memcpy (&va[1], addr, addrlen);
4079 va->addrlen = addrlen;
4080 GNUNET_HELLO_get_key (chvc->hello,
4082 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4083 &timeout_hello_validation,
4085 GNUNET_CONTAINER_multihashmap_put (validation_map,
4088 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4089 setup_peer_check_blacklist (&id, GNUNET_NO,
4090 &transmit_hello_and_ping,
4097 * Check if addresses in validated hello "h" overlap with
4098 * those in "chvc->hello" and validate the rest.
4100 * @param cls closure
4101 * @param peer id of the peer, NULL for last call
4102 * @param h hello message for the peer (can be NULL)
4103 * @param err_msg NULL if successful, otherwise contains error message
4106 check_hello_validated (void *cls,
4107 const struct GNUNET_PeerIdentity *peer,
4108 const struct GNUNET_HELLO_Message *h,
4109 const char *err_msg)
4111 struct CheckHelloValidatedContext *chvc = cls;
4112 struct GNUNET_HELLO_Message *plain_hello;
4113 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4114 struct GNUNET_PeerIdentity target;
4115 struct NeighbourList *n;
4117 if (err_msg != NULL)
4119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4120 _("Error in communication with PEERINFO service\n"));
4126 GNUNET_STATISTICS_update (stats,
4127 gettext_noop ("# outstanding peerinfo iterate requests"),
4131 if (GNUNET_NO == chvc->hello_known)
4133 /* notify PEERINFO about the peer now, so that we at least
4134 have the public key if some other component needs it */
4135 GNUNET_HELLO_get_key (chvc->hello, &pk);
4136 GNUNET_CRYPTO_hash (&pk,
4137 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4138 &target.hashPubKey);
4139 plain_hello = GNUNET_HELLO_create (&pk,
4142 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4143 GNUNET_free (plain_hello);
4144 #if DEBUG_TRANSPORT_HELLO
4145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4146 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4148 GNUNET_i2s (&target));
4150 GNUNET_STATISTICS_update (stats,
4151 gettext_noop ("# new HELLOs requiring full validation"),
4154 GNUNET_HELLO_iterate_addresses (chvc->hello,
4161 GNUNET_STATISTICS_update (stats,
4162 gettext_noop ("# duplicate HELLO (peer known)"),
4167 if (chvc->ve_count == 0)
4169 GNUNET_CONTAINER_DLL_remove (chvc_head,
4178 #if DEBUG_TRANSPORT_HELLO
4179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4180 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4184 chvc->hello_known = GNUNET_YES;
4185 n = find_neighbour (peer);
4188 #if DEBUG_TRANSPORT_HELLO
4189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4190 "Calling hello_iterate_addresses for %s!\n",
4193 GNUNET_HELLO_iterate_addresses (h,
4195 &add_to_foreign_address_list,
4197 try_transmission_to_peer (n);
4201 #if DEBUG_TRANSPORT_HELLO
4202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4203 "No existing neighbor record for %s!\n",
4206 GNUNET_STATISTICS_update (stats,
4207 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4211 GNUNET_STATISTICS_update (stats,
4212 gettext_noop ("# HELLO validations (update case)"),
4215 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4217 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4224 * Process HELLO-message.
4226 * @param plugin transport involved, may be NULL
4227 * @param message the actual message
4228 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4231 process_hello (struct TransportPlugin *plugin,
4232 const struct GNUNET_MessageHeader *message)
4235 struct GNUNET_PeerIdentity target;
4236 const struct GNUNET_HELLO_Message *hello;
4237 struct CheckHelloValidatedContext *chvc;
4238 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4239 #if DEBUG_TRANSPORT_HELLO > 2
4242 hsize = ntohs (message->size);
4243 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4244 (hsize < sizeof (struct GNUNET_MessageHeader)))
4247 return GNUNET_SYSERR;
4249 GNUNET_STATISTICS_update (stats,
4250 gettext_noop ("# HELLOs received for validation"),
4254 /* first, check if load is too high */
4255 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4257 GNUNET_STATISTICS_update (stats,
4258 gettext_noop ("# HELLOs ignored due to high load"),
4261 #if DEBUG_TRANSPORT_HELLO
4262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4263 "Ignoring `%s' for `%4s', load too high.\n",
4265 GNUNET_i2s (&target));
4269 hello = (const struct GNUNET_HELLO_Message *) message;
4270 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4272 #if DEBUG_TRANSPORT_HELLO
4273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4274 "Unable to get public key from `%s' for `%4s'!\n",
4276 GNUNET_i2s (&target));
4278 GNUNET_break_op (0);
4279 return GNUNET_SYSERR;
4282 GNUNET_CRYPTO_hash (&publicKey,
4283 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4284 &target.hashPubKey);
4286 #if DEBUG_TRANSPORT_HELLO
4287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4288 "Received `%s' message for `%4s'\n",
4290 GNUNET_i2s (&target));
4293 if (0 == memcmp (&my_identity,
4295 sizeof (struct GNUNET_PeerIdentity)))
4297 GNUNET_STATISTICS_update (stats,
4298 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4304 while (NULL != chvc)
4306 if (GNUNET_HELLO_equals (hello,
4308 GNUNET_TIME_absolute_get ()).abs_value > 0)
4310 #if DEBUG_TRANSPORT_HELLO > 2
4311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4312 "Received duplicate `%s' message for `%4s'; ignored\n",
4314 GNUNET_i2s (&target));
4316 return GNUNET_OK; /* validation already pending */
4318 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4319 GNUNET_break (0 != memcmp (hello, chvc->hello,
4320 GNUNET_HELLO_size(hello)));
4325 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4326 if ((NULL != temp_neighbor))
4328 fprintf(stderr, "Already know peer, ignoring hello\n");
4333 #if DEBUG_TRANSPORT_HELLO > 2
4336 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4338 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4341 GNUNET_i2s (&target),
4343 GNUNET_HELLO_size(hello));
4347 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4349 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4350 memcpy (&chvc[1], hello, hsize);
4351 GNUNET_CONTAINER_DLL_insert (chvc_head,
4354 /* finally, check if HELLO was previously validated
4355 (continuation will then schedule actual validation) */
4356 GNUNET_STATISTICS_update (stats,
4357 gettext_noop ("# peerinfo process hello iterate requests"),
4360 GNUNET_STATISTICS_update (stats,
4361 gettext_noop ("# outstanding peerinfo iterate requests"),
4364 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4366 HELLO_VERIFICATION_TIMEOUT,
4367 &check_hello_validated, chvc);
4373 * The peer specified by the given neighbour has timed-out or a plugin
4374 * has disconnected. We may either need to do nothing (other plugins
4375 * still up), or trigger a full disconnect and clean up. This
4376 * function updates our state and does the necessary notifications.
4377 * Also notifies our clients that the neighbour is now officially
4380 * @param n the neighbour list entry for the peer
4381 * @param check GNUNET_YES to check if ALL addresses for this peer
4382 * are gone, GNUNET_NO to force a disconnect of the peer
4383 * regardless of whether other addresses exist.
4386 disconnect_neighbour (struct NeighbourList *n, int check)
4388 struct ReadyList *rpos;
4389 struct NeighbourList *npos;
4390 struct NeighbourList *nprev;
4391 struct MessageQueue *mq;
4392 struct ForeignAddressList *peer_addresses;
4393 struct ForeignAddressList *peer_pos;
4395 if (GNUNET_YES == check)
4398 while (NULL != rpos)
4400 peer_addresses = rpos->addresses;
4401 while (peer_addresses != NULL)
4403 if (GNUNET_YES == peer_addresses->connected)
4405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4406 "NOT Disconnecting from `%4s', still have live addresses!\n",
4407 GNUNET_i2s (&n->id));
4408 return; /* still connected */
4410 peer_addresses = peer_addresses->next;
4416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4417 "Disconnecting from `%4s'\n",
4418 GNUNET_i2s (&n->id));
4420 /* remove n from neighbours list */
4423 while ((npos != NULL) && (npos != n))
4428 GNUNET_assert (npos != NULL);
4430 neighbours = n->next;
4432 nprev->next = n->next;
4434 /* notify all clients about disconnect */
4435 if (GNUNET_YES == n->received_pong)
4436 notify_clients_disconnect (&n->id);
4438 /* clean up all plugins, cancel connections and pending transmissions */
4439 while (NULL != (rpos = n->plugins))
4441 n->plugins = rpos->next;
4442 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4443 while (rpos->addresses != NULL)
4445 peer_pos = rpos->addresses;
4446 rpos->addresses = peer_pos->next;
4447 if (peer_pos->connected == GNUNET_YES)
4448 GNUNET_STATISTICS_update (stats,
4449 gettext_noop ("# connected addresses"),
4452 if (GNUNET_YES == peer_pos->validated)
4453 GNUNET_STATISTICS_update (stats,
4454 gettext_noop ("# peer addresses considered valid"),
4457 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4459 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4460 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4462 GNUNET_free(peer_pos);
4467 /* free all messages on the queue */
4468 while (NULL != (mq = n->messages_head))
4470 GNUNET_STATISTICS_update (stats,
4471 gettext_noop ("# bytes in message queue for other peers"),
4472 - (int64_t) mq->message_buf_size,
4474 GNUNET_STATISTICS_update (stats,
4475 gettext_noop ("# bytes discarded due to disconnect"),
4476 mq->message_buf_size,
4478 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4481 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4483 sizeof(struct GNUNET_PeerIdentity)));
4486 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4488 GNUNET_SCHEDULER_cancel (n->timeout_task);
4489 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4491 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4493 GNUNET_SCHEDULER_cancel (n->retry_task);
4494 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4496 if (n->piter != NULL)
4498 GNUNET_PEERINFO_iterate_cancel (n->piter);
4499 GNUNET_STATISTICS_update (stats,
4500 gettext_noop ("# outstanding peerinfo iterate requests"),
4505 /* finally, free n itself */
4506 GNUNET_STATISTICS_update (stats,
4507 gettext_noop ("# active neighbours"),
4510 GNUNET_free_non_null (n->pre_connect_message_buffer);
4516 * We have received a PING message from someone. Need to send a PONG message
4517 * in response to the peer by any means necessary.
4520 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4521 const struct GNUNET_PeerIdentity *peer,
4522 struct Session *session,
4523 const char *sender_address,
4524 uint16_t sender_address_len)
4526 struct TransportPlugin *plugin = cls;
4527 struct SessionHeader *session_header = (struct SessionHeader*) session;
4528 struct TransportPingMessage *ping;
4529 struct TransportPongMessage *pong;
4530 struct NeighbourList *n;
4531 struct ReadyList *rl;
4532 struct ForeignAddressList *fal;
4533 struct OwnAddressList *oal;
4538 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4540 GNUNET_break_op (0);
4541 return GNUNET_SYSERR;
4544 ping = (struct TransportPingMessage *) message;
4545 if (0 != memcmp (&ping->target,
4546 plugin->env.my_identity,
4547 sizeof (struct GNUNET_PeerIdentity)))
4549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4550 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4552 (sender_address != NULL)
4553 ? a2s (plugin->short_name,
4554 (const struct sockaddr *)sender_address,
4557 GNUNET_i2s (&ping->target));
4558 return GNUNET_SYSERR;
4561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4562 "Processing `%s' from `%s'\n",
4564 (sender_address != NULL)
4565 ? a2s (plugin->short_name,
4566 (const struct sockaddr *)sender_address,
4570 GNUNET_STATISTICS_update (stats,
4571 gettext_noop ("# PING messages received"),
4574 addr = (const char*) &ping[1];
4575 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4576 slen = strlen (plugin->short_name) + 1;
4579 /* peer wants to confirm that we have an outbound connection to him */
4580 if (session == NULL)
4582 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4583 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4585 return GNUNET_SYSERR;
4587 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4588 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4589 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4590 pong->purpose.size =
4591 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4593 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4594 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4595 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4596 pong->challenge = ping->challenge;
4597 pong->addrlen = htonl(sender_address_len + slen);
4600 sizeof(struct GNUNET_PeerIdentity));
4604 if ((sender_address!=NULL) && (sender_address_len > 0))
4605 memcpy (&((char*)&pong[1])[slen],
4607 sender_address_len);
4608 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4610 /* create / update cached sig */
4612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4613 "Creating PONG signature to indicate active connection.\n");
4615 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4616 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4617 GNUNET_assert (GNUNET_OK ==
4618 GNUNET_CRYPTO_rsa_sign (my_private_key,
4620 &session_header->pong_signature));
4624 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4626 memcpy (&pong->signature,
4627 &session_header->pong_signature,
4628 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4634 /* peer wants to confirm that this is one of our addresses */
4638 plugin->api->check_address (plugin->api->cls,
4642 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4643 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4644 a2s (plugin->short_name,
4649 oal = plugin->addresses;
4652 if ( (oal->addrlen == alen) &&
4659 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4660 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4661 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4662 pong->purpose.size =
4663 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4665 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4666 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4667 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4668 pong->challenge = ping->challenge;
4669 pong->addrlen = htonl(alen + slen);
4672 sizeof(struct GNUNET_PeerIdentity));
4673 memcpy (&pong[1], plugin->short_name, slen);
4674 memcpy (&((char*)&pong[1])[slen], addr, alen);
4675 if ( (oal != NULL) &&
4676 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4678 /* create / update cached sig */
4680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4681 "Creating PONG signature to indicate ownership.\n");
4683 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4684 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4685 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4686 GNUNET_assert (GNUNET_OK ==
4687 GNUNET_CRYPTO_rsa_sign (my_private_key,
4689 &oal->pong_signature));
4690 memcpy (&pong->signature,
4691 &oal->pong_signature,
4692 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4694 else if (oal == NULL)
4696 /* not using cache (typically DV-only) */
4697 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4698 GNUNET_assert (GNUNET_OK ==
4699 GNUNET_CRYPTO_rsa_sign (my_private_key,
4705 /* can used cached version */
4706 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4707 memcpy (&pong->signature,
4708 &oal->pong_signature,
4709 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4712 n = find_neighbour(peer);
4713 GNUNET_assert (n != NULL);
4714 /* first try reliable response transmission */
4718 fal = rl->addresses;
4721 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4724 ntohs (pong->header.size),
4725 TRANSPORT_PONG_PRIORITY,
4726 HELLO_VERIFICATION_TIMEOUT,
4734 GNUNET_STATISTICS_update (stats,
4735 gettext_noop ("# PONGs unicast via reliable transport"),
4745 /* no reliable method found, do multicast */
4746 GNUNET_STATISTICS_update (stats,
4747 gettext_noop ("# PONGs multicast to all available addresses"),
4753 fal = rl->addresses;
4756 transmit_to_peer(NULL, fal,
4757 TRANSPORT_PONG_PRIORITY,
4758 HELLO_VERIFICATION_TIMEOUT,
4760 ntohs(pong->header.size),
4773 * Function called by the plugin for each received message.
4774 * Update data volumes, possibly notify plugins about
4775 * reducing the rate at which they read from the socket
4776 * and generally forward to our receive callback.
4778 * @param cls the "struct TransportPlugin *" we gave to the plugin
4779 * @param peer (claimed) identity of the other peer
4780 * @param message the message, NULL if we only care about
4781 * learning about the delay until we should receive again
4782 * @param ats_data information for automatic transport selection
4783 * @param ats_count number of elements in ats not including 0-terminator
4784 * @param session identifier used for this session (can be NULL)
4785 * @param sender_address binary address of the sender (if observed)
4786 * @param sender_address_len number of bytes in sender_address
4787 * @return how long in ms the plugin should wait until receiving more data
4788 * (plugins that do not support this, can ignore the return value)
4790 static struct GNUNET_TIME_Relative
4791 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4792 const struct GNUNET_MessageHeader *message,
4793 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4795 struct Session *session,
4796 const char *sender_address,
4797 uint16_t sender_address_len)
4799 struct TransportPlugin *plugin = cls;
4800 struct ReadyList *service_context;
4801 struct ForeignAddressList *peer_address;
4803 struct NeighbourList *n;
4804 struct GNUNET_TIME_Relative ret;
4805 if (is_blacklisted (peer, plugin))
4806 return GNUNET_TIME_UNIT_FOREVER_REL;
4810 n = find_neighbour (peer);
4812 n = setup_new_neighbour (peer, GNUNET_YES);
4813 service_context = n->plugins;
4814 while ((service_context != NULL) && (plugin != service_context->plugin))
4815 service_context = service_context->next;
4816 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4817 peer_address = NULL;
4819 for (c=0; c<ats_count; c++)
4821 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4823 distance = ntohl(ats_data[c].value);
4826 /* notify ATS about incoming data */
4827 ats_notify_ats_data(peer, ats_data);
4829 if (message != NULL)
4831 if ( (session != NULL) ||
4832 (sender_address != NULL) )
4833 peer_address = add_peer_address (n,
4837 sender_address_len);
4838 if (peer_address != NULL)
4840 peer_address->distance = distance;
4841 if (GNUNET_YES == peer_address->validated)
4842 mark_address_connected (peer_address);
4843 peer_address->timeout
4845 GNUNET_TIME_relative_to_absolute
4846 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4847 schedule_next_ping (peer_address);
4849 /* update traffic received amount ... */
4850 msize = ntohs (message->size);
4851 GNUNET_STATISTICS_update (stats,
4852 gettext_noop ("# bytes received from other peers"),
4855 n->distance = distance;
4857 GNUNET_TIME_relative_to_absolute
4858 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4859 GNUNET_SCHEDULER_cancel (n->timeout_task);
4861 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4862 &neighbour_timeout_task, n);
4863 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4865 /* dropping message due to frequent inbound volume violations! */
4866 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4867 GNUNET_ERROR_TYPE_BULK,
4869 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4870 n->in_tracker.available_bytes_per_s__,
4871 n->quota_violation_count);
4872 GNUNET_STATISTICS_update (stats,
4873 gettext_noop ("# bandwidth quota violations by other peers"),
4876 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4881 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4882 ntohs (message->type),
4883 ntohs (message->size),
4886 switch (ntohs (message->type))
4888 case GNUNET_MESSAGE_TYPE_HELLO:
4889 GNUNET_STATISTICS_update (stats,
4890 gettext_noop ("# HELLO messages received from other peers"),
4893 process_hello (plugin, message);
4895 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4896 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4898 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4899 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4902 handle_payload_message (message, n);
4906 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4907 if (ret.rel_value > 0)
4909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4910 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4911 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4912 (unsigned int) n->in_tracker.available_bytes_per_s__,
4913 (unsigned long long) ret.rel_value);
4914 GNUNET_STATISTICS_update (stats,
4915 gettext_noop ("# ms throttling suggested"),
4916 (int64_t) ret.rel_value,
4923 * Handle START-message. This is the first message sent to us
4924 * by any client which causes us to add it to our list.
4926 * @param cls closure (always NULL)
4927 * @param client identification of the client
4928 * @param message the actual message
4931 handle_start (void *cls,
4932 struct GNUNET_SERVER_Client *client,
4933 const struct GNUNET_MessageHeader *message)
4935 const struct StartMessage *start;
4936 struct TransportClient *c;
4937 struct ConnectInfoMessage * cim;
4938 struct NeighbourList *n;
4942 start = (const struct StartMessage*) message;
4944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4945 "Received `%s' request from client\n", "START");
4950 if (c->client == client)
4952 /* client already on our list! */
4954 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4959 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4960 (0 != memcmp (&start->self,
4962 sizeof (struct GNUNET_PeerIdentity))) )
4964 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4965 _("Rejecting control connection from peer `%s', which is not me!\n"),
4966 GNUNET_i2s (&start->self));
4967 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4970 c = GNUNET_malloc (sizeof (struct TransportClient));
4974 if (our_hello != NULL)
4977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4978 "Sending our own `%s' to new client\n", "HELLO");
4980 transmit_to_client (c,
4981 (const struct GNUNET_MessageHeader *) our_hello,
4983 /* tell new client about all existing connections */
4985 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4986 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4990 cim = GNUNET_malloc (size);
4991 cim->header.size = htons (size);
4992 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4993 cim->ats_count = htonl(ats_count);
4994 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4995 (&(cim->ats))[2].value = htonl (0);
4999 if (GNUNET_YES == n->received_pong)
5001 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5002 (&(cim->ats))[0].value = htonl (n->distance);
5003 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5004 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5006 transmit_to_client (c, &cim->header, GNUNET_NO);
5012 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5017 * Handle HELLO-message.
5019 * @param cls closure (always NULL)
5020 * @param client identification of the client
5021 * @param message the actual message
5024 handle_hello (void *cls,
5025 struct GNUNET_SERVER_Client *client,
5026 const struct GNUNET_MessageHeader *message)
5030 GNUNET_STATISTICS_update (stats,
5031 gettext_noop ("# HELLOs received from clients"),
5034 ret = process_hello (NULL, message);
5035 GNUNET_SERVER_receive_done (client, ret);
5040 * Closure for 'transmit_client_message'; followed by
5041 * 'msize' bytes of the actual message.
5043 struct TransmitClientMessageContext
5046 * Client on whom's behalf we are sending.
5048 struct GNUNET_SERVER_Client *client;
5051 * Timeout for the transmission.
5053 struct GNUNET_TIME_Absolute timeout;
5061 * Size of the message in bytes.
5068 * Schedule transmission of a message we got from a client to a peer.
5070 * @param cls the 'struct TransmitClientMessageContext*'
5071 * @param n destination, or NULL on error (in that case, drop the message)
5074 transmit_client_message (void *cls,
5075 struct NeighbourList *n)
5077 struct TransmitClientMessageContext *tcmc = cls;
5078 struct TransportClient *tc;
5081 while ((tc != NULL) && (tc->client != tcmc->client))
5086 transmit_to_peer (tc, NULL, tcmc->priority,
5087 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5089 tcmc->msize, GNUNET_NO, n);
5091 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5092 GNUNET_SERVER_client_drop (tcmc->client);
5098 * Handle SEND-message.
5100 * @param cls closure (always NULL)
5101 * @param client identification of the client
5102 * @param message the actual message
5105 handle_send (void *cls,
5106 struct GNUNET_SERVER_Client *client,
5107 const struct GNUNET_MessageHeader *message)
5109 const struct OutboundMessage *obm;
5110 const struct GNUNET_MessageHeader *obmm;
5111 struct TransmitClientMessageContext *tcmc;
5115 size = ntohs (message->size);
5117 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5120 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5123 GNUNET_STATISTICS_update (stats,
5124 gettext_noop ("# payload received for other peers"),
5127 obm = (const struct OutboundMessage *) message;
5128 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5129 msize = size - sizeof (struct OutboundMessage);
5131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5132 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5133 "SEND", GNUNET_i2s (&obm->peer),
5137 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5138 tcmc->client = client;
5139 tcmc->priority = ntohl (obm->priority);
5140 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5141 tcmc->msize = msize;
5142 /* FIXME: this memcpy can be up to 7% of our total runtime */
5143 memcpy (&tcmc[1], obmm, msize);
5144 GNUNET_SERVER_client_keep (client);
5145 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5146 &transmit_client_message,
5152 * Handle request connect message
5154 * @param cls closure (always NULL)
5155 * @param client identification of the client
5156 * @param message the actual message
5159 handle_request_connect (void *cls,
5160 struct GNUNET_SERVER_Client *client,
5161 const struct GNUNET_MessageHeader *message)
5163 const struct TransportRequestConnectMessage *trcm =
5164 (const struct TransportRequestConnectMessage *) message;
5166 GNUNET_STATISTICS_update (stats,
5167 gettext_noop ("# REQUEST CONNECT messages received"),
5170 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5171 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5173 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5177 * Handle SET_QUOTA-message.
5179 * @param cls closure (always NULL)
5180 * @param client identification of the client
5181 * @param message the actual message
5184 handle_set_quota (void *cls,
5185 struct GNUNET_SERVER_Client *client,
5186 const struct GNUNET_MessageHeader *message)
5188 const struct QuotaSetMessage *qsm =
5189 (const struct QuotaSetMessage *) message;
5190 struct NeighbourList *n;
5192 GNUNET_STATISTICS_update (stats,
5193 gettext_noop ("# SET QUOTA messages received"),
5196 n = find_neighbour (&qsm->peer);
5199 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5200 GNUNET_STATISTICS_update (stats,
5201 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5208 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5210 (unsigned int) ntohl (qsm->quota.value__),
5211 (unsigned int) n->in_tracker.available_bytes_per_s__,
5212 GNUNET_i2s (&qsm->peer));
5214 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5216 if (0 == ntohl (qsm->quota.value__))
5218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5219 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5221 disconnect_neighbour (n, GNUNET_NO);
5223 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5228 * Take the given address and append it to the set of results sent back to
5231 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5232 * @param address the resolved name, NULL to indicate the last response
5235 transmit_address_to_client (void *cls, const char *address)
5237 struct GNUNET_SERVER_TransmitContext *tc = cls;
5240 if (NULL == address)
5243 slen = strlen (address) + 1;
5245 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5246 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5247 if (NULL == address)
5248 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5253 * Handle AddressLookup-message.
5255 * @param cls closure (always NULL)
5256 * @param client identification of the client
5257 * @param message the actual message
5260 handle_address_lookup (void *cls,
5261 struct GNUNET_SERVER_Client *client,
5262 const struct GNUNET_MessageHeader *message)
5264 const struct AddressLookupMessage *alum;
5265 struct TransportPlugin *lsPlugin;
5266 const char *nameTransport;
5267 const char *address;
5269 struct GNUNET_SERVER_TransmitContext *tc;
5270 struct GNUNET_TIME_Absolute timeout;
5271 struct GNUNET_TIME_Relative rtimeout;
5274 size = ntohs (message->size);
5275 if (size < sizeof (struct AddressLookupMessage))
5277 GNUNET_break_op (0);
5278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5281 alum = (const struct AddressLookupMessage *) message;
5282 uint32_t addressLen = ntohl (alum->addrlen);
5283 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5285 GNUNET_break_op (0);
5286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5289 address = (const char *) &alum[1];
5290 nameTransport = (const char *) &address[addressLen];
5292 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5294 GNUNET_break_op (0);
5295 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5298 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5299 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5300 numeric = ntohl (alum->numeric_only);
5301 lsPlugin = find_transport (nameTransport);
5302 if (NULL == lsPlugin)
5304 tc = GNUNET_SERVER_transmit_context_create (client);
5305 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5306 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5307 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5310 tc = GNUNET_SERVER_transmit_context_create (client);
5311 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5313 address, addressLen,
5316 &transmit_address_to_client, tc);
5321 * Setup the environment for this plugin.
5324 create_environment (struct TransportPlugin *plug)
5326 plug->env.cfg = cfg;
5327 plug->env.my_identity = &my_identity;
5328 plug->env.our_hello = &our_hello;
5329 plug->env.cls = plug;
5330 plug->env.receive = &plugin_env_receive;
5331 plug->env.notify_address = &plugin_env_notify_address;
5332 plug->env.session_end = &plugin_env_session_end;
5333 plug->env.max_connections = max_connect_per_transport;
5334 plug->env.stats = stats;
5339 * Start the specified transport (load the plugin).
5342 start_transport (struct GNUNET_SERVER_Handle *server,
5345 struct TransportPlugin *plug;
5348 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5349 _("Loading `%s' transport plugin\n"), name);
5350 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5351 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5352 create_environment (plug);
5353 plug->short_name = GNUNET_strdup (name);
5354 plug->lib_name = libname;
5355 plug->next = plugins;
5357 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5358 if (plug->api == NULL)
5360 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5361 _("Failed to load transport plugin for `%s'\n"), name);
5362 GNUNET_free (plug->short_name);
5363 plugins = plug->next;
5364 GNUNET_free (libname);
5371 * Called whenever a client is disconnected. Frees our
5372 * resources associated with that client.
5374 * @param cls closure
5375 * @param client identification of the client
5378 client_disconnect_notification (void *cls,
5379 struct GNUNET_SERVER_Client *client)
5381 struct TransportClient *pos;
5382 struct TransportClient *prev;
5383 struct ClientMessageQueueEntry *mqe;
5384 struct Blacklisters *bl;
5385 struct BlacklistCheck *bc;
5390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5391 "Client disconnected, cleaning up.\n");
5393 /* clean up blacklister */
5397 if (bl->client == client)
5402 if (bc->bl_pos == bl)
5404 bc->bl_pos = bl->next;
5407 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5410 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5411 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5417 GNUNET_CONTAINER_DLL_remove (bl_head,
5420 GNUNET_SERVER_client_drop (bl->client);
5426 /* clean up 'normal' clients */
5429 while ((pos != NULL) && (pos->client != client))
5436 while (NULL != (mqe = pos->message_queue_head))
5438 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5439 pos->message_queue_tail,
5441 pos->message_count--;
5445 clients = pos->next;
5447 prev->next = pos->next;
5448 if (GNUNET_YES == pos->tcs_pending)
5453 if (pos->th != NULL)
5455 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5458 GNUNET_break (0 == pos->message_count);
5464 * Function called when the service shuts down. Unloads our plugins
5465 * and cancels pending validations.
5467 * @param cls closure, unused
5468 * @param tc task context (unused)
5471 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5473 struct TransportPlugin *plug;
5474 struct OwnAddressList *al;
5475 struct CheckHelloValidatedContext *chvc;
5477 while (neighbours != NULL)
5479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5480 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5482 disconnect_neighbour (neighbours, GNUNET_NO);
5485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5486 "Transport service is unloading plugins...\n");
5488 while (NULL != (plug = plugins))
5490 plugins = plug->next;
5491 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5493 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5494 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5496 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5497 GNUNET_free (plug->lib_name);
5498 GNUNET_free (plug->short_name);
5499 while (NULL != (al = plug->addresses))
5501 plug->addresses = al->next;
5506 if (my_private_key != NULL)
5507 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5508 GNUNET_free_non_null (our_hello);
5510 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5513 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5514 validation_map = NULL;
5518 /* free 'chvc' data structure */
5519 while (NULL != (chvc = chvc_head))
5521 chvc_head = chvc->next;
5522 if (chvc->piter != NULL)
5524 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5525 GNUNET_STATISTICS_update (stats,
5526 gettext_noop ("# outstanding peerinfo iterate requests"),
5532 GNUNET_assert (chvc->ve_count == 0);
5539 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5542 if (peerinfo != NULL)
5544 GNUNET_PEERINFO_disconnect (peerinfo);
5547 /* Can we assume those are gone by now, or do we need to clean up
5549 GNUNET_break (bl_head == NULL);
5550 GNUNET_break (bc_head == NULL);
5553 struct ATS_transports
5560 #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)
5565 int result = GLP_UNDEF;
5570 int rows = 1 + (3*peers) + (transports);
5576 int ia[1+(rows*cols)], ja[1+(rows*cols)];
5577 double ar[1+(rows*cols)];
5580 /* Setting GLPK options */
5581 glp_smcp * options = GNUNET_malloc( sizeof (glp_smcp));
5582 glp_init_smcp(options);
5584 /* maximum iterations */
5585 options->it_lim = max_it;
5586 /* maximum durations */
5587 options->tm_lim = max_dur;
5590 options->msg_lev = GLP_MSG_ALL;
5592 options->msg_lev = GLP_MSG_OFF;
5594 if (DEBUG_ATS) 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);
5595 lp = glp_create_prob();
5596 glp_set_prob_name(lp, "gnunet ats bandwidth distribution");
5597 glp_set_obj_dir(lp, GLP_MAX);
5599 /* Adding transports and objective function coefficients*/
5600 glp_add_cols(lp, cols);
5601 for (c1=1; c1<=cols; c1++)
5603 GNUNET_asprintf(&peer_n,"%s",GNUNET_i2s(&pl[c1-1].peer));
5604 if (DEBUG_ATS) 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);
5605 /* add a single transport*/
5606 glp_set_col_name(lp, c1, peer_n);
5607 /* add a lower bound */
5608 glp_set_col_bnds(lp, c1, GLP_LO, 0.0, 0.0);
5609 /* set coefficient function */
5610 value = pl[c1-1].f/b_max;
5612 glp_set_obj_coef(lp, c1, value);
5613 GNUNET_free(peer_n);
5616 /* Adding constraints */
5617 glp_add_rows(lp, rows);
5620 /* constraint 1: Maximum bandwidth for all peers
5623 glp_set_row_bnds(lp, cur_row, GLP_UP, 0.0, b_max);
5624 for (index=1; index<=cols; index++)
5626 ia[index] = 1, ja[index] = index, ar[index] = 1.0;
5629 /* constraint 2: Maximum bandwidth per peer
5630 * V b_i in B: b_i <= b_max
5634 for (c1=0; c1<peers; c1++)
5636 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "row: %i \n", cur_row);
5637 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0, b_max);
5639 for (c2 = 1; c2 <= cols; c2++)
5641 ia[index] = cur_row;
5643 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5649 /* constraint 3: Minimum bandwidth
5650 * V b_i in B: b_i >= b_min
5653 for (c1=0; c1<peers; c1++)
5655 glp_set_row_bnds(lp, cur_row , GLP_LO, b_min, 0.0);
5657 for (c2 = 1; c2 <= cols; c2++)
5659 ia[index] = cur_row;
5661 ar[index] = ((c1+1 == c2) ? 1.0 : 0.0);
5667 /* constraint 4: Bandwidth assignment relativity to peer preference
5668 * V b_i in B: b_i >= b_min
5671 for (c1=0; c1<peers; c1++)
5674 value = pl[c1].f * r;
5675 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 /* constraint 4: transport capacity
5689 * sum of b * c_i < c_max */
5691 for (c1=0; c1<transports; c1++)
5694 value = tl[c1].c_max;
5695 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport %i: c_max %5.2f c_1 %5.2f \n", c1, value, tl[c1].c_1);
5696 glp_set_row_bnds(lp, cur_row , GLP_UP, 0.0 , value);
5698 for (c2 = 1; c2 <= cols; c2++)
5700 ia[index] = cur_row;
5702 ar[index] = ((pl[c1-1].t == tl[c1].id) ? (tl[c1].c_1) : 0.0);
5708 glp_load_matrix(lp, rows * cols, ia, ja, ar);
5709 result = glp_simplex(lp, options);
5713 case GLP_ESTOP : /* search terminated by application */
5714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Search terminated by application ");
5715 case GLP_EITLIM : /* iteration limit exceeded */
5716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration limit exceeded ");
5718 case GLP_ETMLIM : /* time limit exceeded */
5719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Time limit exceeded ");
5721 case GLP_ENOFEAS: /* no primal/dual feasible solution */
5722 case GLP_ENOCVG : /* no convergence */
5723 case GLP_ERANGE : /* result out of range */
5724 case GLP_ENOPFS : /* no primal feasible solution */
5725 case GLP_ENODFS : /* no dual feasible solution */
5726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No feasible solution");
5729 case GLP_EBADB : /* invalid basis */
5730 case GLP_ESING : /* singular matrix */
5731 case GLP_ECOND : /* ill-conditioned matrix */
5732 case GLP_EBOUND : /* invalid bounds */
5733 case GLP_EFAIL : /* solver failed */
5734 case GLP_EOBJLL : /* objective lower limit reached */
5735 case GLP_EOBJUL : /* objective upper limit reached */
5736 case GLP_EROOT : /* root LP optimum not provided */
5737 case GLP_EMIPGAP: /* relative mip gap tolerance reached */
5738 case GLP_EINSTAB: /* numerical instability */
5739 case GLP_EDATA : /* invalid data */
5740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Invalid Input data\n");
5745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Optimal solution\n");
5750 char * debug_solution = NULL;
5752 for (c1=1; c1<= peers; c1++ )
5754 old = debug_solution;
5755 GNUNET_asprintf(&debug_solution, "%s %s = %g;", (debug_solution!=NULL) ? debug_solution : "", GNUNET_i2s(&pl[c1-1].peer), glp_get_col_prim(lp, c1));
5756 if (old!=NULL) GNUNET_free(old);
5758 GNUNET_asprintf(&debug_solution, "%s z = %g; \n", debug_solution, glp_get_obj_val(lp));
5759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s \n",debug_solution);
5760 GNUNET_free(debug_solution);
5762 glp_delete_prob(lp);
5763 GNUNET_free(options);
5774 void ats_calculate_bandwidth_distribution ()
5776 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
5777 if (delta.rel_value < ats->min_delta.rel_value)
5780 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
5789 double b_max = 100.0;
5790 double r = 0.85;//1.0;
5795 //if (INT_MAX) ats.max_exec_duration.rel_value;
5797 struct ATS_transports * tl = GNUNET_malloc(transports * sizeof (struct ATS_peer));
5799 struct ATS_peer * pl = GNUNET_malloc(peers * sizeof (struct ATS_peer));
5803 pl[c].peer.hashPubKey.bits[0] = c+1;
5804 pl[c].f = 1 / (double) peers ;
5806 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %s %p \n",c , GNUNET_i2s(&list[c].peer), &list[c].peer);
5810 while (c < transports)
5825 ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur);
5830 ats->last = GNUNET_TIME_absolute_get();
5837 ats_schedule_calculation (void *cls,
5838 const struct GNUNET_SCHEDULER_TaskContext *tc)
5840 struct ATS_info *ats = (struct ATS_info *) cls;
5844 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5845 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
5849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
5851 ats_calculate_bandwidth_distribution (ats);
5853 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
5854 &ats_schedule_calculation, ats);
5858 int ats_map_remove_peer (void *cls,
5859 const GNUNET_HashCode * key,
5863 struct ATS_peer * p = (struct ATS_peer *) value;
5865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
5874 struct ATS_info * ats_init ()
5876 struct ATS_info * ats;
5878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
5880 ats = GNUNET_malloc(sizeof (struct ATS_info));
5881 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
5882 GNUNET_assert(ats->peers!=NULL);
5884 ats->min_delta = ATS_MIN_INTERVAL;
5885 ats->exec_intervall = ATS_EXEC_INTERVAL;
5886 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
5888 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5890 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5891 &schedule_calculation, NULL);
5893 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5894 &schedule_calculation, NULL);
5896 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
5902 void ats_shutdown ()
5905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
5907 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
5908 GNUNET_SCHEDULER_cancel(ats->ats_task);
5909 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5911 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
5912 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
5917 void ats_notify_peer_connect (
5918 const struct GNUNET_PeerIdentity *peer,
5919 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5923 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
5926 while (ntohl(ats_data[c].type)!=0)
5929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
5933 /* check if peer is already known */
5934 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
5936 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
5937 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
5938 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
5941 ats_calculate_bandwidth_distribution(ats);
5944 void ats_notify_peer_disconnect (
5945 const struct GNUNET_PeerIdentity *peer)
5948 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
5951 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
5953 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
5954 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
5957 ats_calculate_bandwidth_distribution (ats);
5961 void ats_notify_ats_data (
5962 const struct GNUNET_PeerIdentity *peer,
5963 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5966 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
5968 ats_calculate_bandwidth_distribution(ats);
5971 struct ForeignAddressList * ats_get_preferred_address (
5972 struct NeighbourList *n)
5975 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
5977 struct ReadyList *next = n->plugins;
5978 while (next != NULL)
5981 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
5985 return find_ready_address(n);
5989 * Initiate transport service.
5991 * @param cls closure
5992 * @param server the initialized server
5993 * @param c configuration to use
5997 struct GNUNET_SERVER_Handle *server,
5998 const struct GNUNET_CONFIGURATION_Handle *c)
6000 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6001 {&handle_start, NULL,
6002 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6003 {&handle_hello, NULL,
6004 GNUNET_MESSAGE_TYPE_HELLO, 0},
6005 {&handle_send, NULL,
6006 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6007 {&handle_request_connect, NULL,
6008 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6009 {&handle_set_quota, NULL,
6010 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6011 {&handle_address_lookup, NULL,
6012 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6014 {&handle_blacklist_init, NULL,
6015 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6016 {&handle_blacklist_reply, NULL,
6017 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6023 unsigned long long tneigh;
6027 stats = GNUNET_STATISTICS_create ("transport", cfg);
6028 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6029 /* parse configuration */
6031 GNUNET_CONFIGURATION_get_value_number (c,
6036 GNUNET_CONFIGURATION_get_value_filename (c,
6038 "HOSTKEY", &keyfile)))
6040 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6042 ("Transport service is lacking key configuration settings. Exiting.\n"));
6043 GNUNET_SCHEDULER_shutdown ();
6046 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6049 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6050 validation_map = NULL;
6054 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("HAVE\n"));
6056 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("NOT HAVE\n"));
6060 max_connect_per_transport = (uint32_t) tneigh;
6061 peerinfo = GNUNET_PEERINFO_connect (cfg);
6062 if (peerinfo == NULL)
6064 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6065 _("Could not access PEERINFO service. Exiting.\n"));
6066 GNUNET_SCHEDULER_shutdown ();
6069 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6072 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6073 validation_map = NULL;
6074 GNUNET_free (keyfile);
6077 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6078 GNUNET_free (keyfile);
6079 if (my_private_key == NULL)
6081 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6083 ("Transport service could not access hostkey. Exiting.\n"));
6084 GNUNET_SCHEDULER_shutdown ();
6087 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6090 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6091 validation_map = NULL;
6094 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6095 GNUNET_CRYPTO_hash (&my_public_key,
6096 sizeof (my_public_key), &my_identity.hashPubKey);
6097 /* setup notification */
6098 GNUNET_SERVER_disconnect_notify (server,
6099 &client_disconnect_notification, NULL);
6100 /* load plugins... */
6103 GNUNET_CONFIGURATION_get_value_string (c,
6104 "TRANSPORT", "PLUGINS", &plugs))
6106 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6107 _("Starting transport plugins `%s'\n"), plugs);
6108 pos = strtok (plugs, " ");
6111 start_transport (server, pos);
6113 pos = strtok (NULL, " ");
6115 GNUNET_free (plugs);
6117 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6118 &shutdown_task, NULL);
6123 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6125 /* If we have a blacklist file, read from it */
6126 read_blacklist_file(cfg);
6127 /* process client requests */
6128 GNUNET_SERVER_add_handlers (server, handlers);
6133 * The main function for the transport service.
6135 * @param argc number of arguments from the command line
6136 * @param argv command line arguments
6137 * @return 0 ok, 1 on error
6140 main (int argc, char *const *argv)
6142 a2s (NULL, NULL, 0); /* make compiler happy */
6143 return (GNUNET_OK ==
6144 GNUNET_SERVICE_run (argc,
6147 GNUNET_SERVICE_OPTION_NONE,
6148 &run, NULL)) ? 0 : 1;
6151 /* end of gnunet-service-transport.c */