2 This file is part of GNUnet.
3 (C) 2009 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 2, 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
27 * - Need to defer forwarding messages until after CONNECT message
28 * - CHECK that 'address' being NULL in 'struct ForeignAddressList' is
29 * tolerated in the code everywhere (could not happen before)
32 * - This code uses 'GNUNET_a2s' for debug printing in many places,
33 * which is technically wrong since it assumes we have IP+Port
34 * (v4/v6) addresses. Once we add transports like http or smtp
35 * this will have to be changed!
38 #include "gnunet_client_lib.h"
39 #include "gnunet_container_lib.h"
40 #include "gnunet_constants.h"
41 #include "gnunet_getopt_lib.h"
42 #include "gnunet_hello_lib.h"
43 #include "gnunet_os_lib.h"
44 #include "gnunet_peerinfo_service.h"
45 #include "gnunet_plugin_lib.h"
46 #include "gnunet_protocols.h"
47 #include "gnunet_service_lib.h"
48 #include "gnunet_signatures.h"
49 #include "plugin_transport.h"
50 #include "transport.h"
53 * Should we do some additional checks (to validate behavior
56 #define EXTRA_CHECKS GNUNET_YES
59 * How many messages can we have pending for a given client process
60 * before we start to drop incoming messages? We typically should
61 * have only one client and so this would be the primary buffer for
62 * messages, so the number should be chosen rather generously.
64 * The expectation here is that most of the time the queue is large
65 * enough so that a drop is virtually never required.
67 #define MAX_PENDING 128
70 * How often should we try to reconnect to a peer using a particular
71 * transport plugin before giving up? Note that the plugin may be
72 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
74 #define MAX_CONNECT_RETRY 3
77 * Limit on the number of ready-to-run tasks when validating
78 * HELLOs. If more tasks are ready to run, we will drop
79 * HELLOs instead of validating them.
81 #define MAX_HELLO_LOAD 4
84 * How often must a peer violate bandwidth quotas before we start
85 * to simply drop its messages?
87 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
90 * How long until a HELLO verification attempt should time out?
91 * Must be rather small, otherwise a partially successful HELLO
92 * validation (some addresses working) might not be available
93 * before a client's request for a connection fails for good.
94 * Besides, if a single request to an address takes a long time,
95 * then the peer is unlikely worthwhile anyway.
97 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
100 * Priority to use for PONG messages.
102 #define TRANSPORT_PONG_PRIORITY 4
105 * How often do we re-add (cheaper) plugins to our list of plugins
106 * to try for a given connected peer?
108 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
111 * After how long do we expire an address in a HELLO that we just
112 * validated? This value is also used for our own addresses when we
115 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
119 * How long before an existing address expires should we again try to
120 * validate it? Must be (significantly) smaller than
121 * HELLO_ADDRESS_EXPIRATION.
123 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
126 * Maximum frequency for re-evaluating latencies for all transport addresses.
128 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
131 * Maximum frequency for re-evaluating latencies for connected addresses.
133 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
137 * List of addresses of other peers
139 struct ForeignAddressList
142 * This is a linked list.
144 struct ForeignAddressList *next;
147 * Which ready list does this entry belong to.
149 struct ReadyList *ready_list;
152 * How long until we auto-expire this address (unless it is
153 * re-confirmed by the transport)?
155 struct GNUNET_TIME_Absolute expires;
158 * Task used to re-validate addresses, updates latencies and
161 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
174 * Session (or NULL if no valid session currently exists or if the
175 * plugin does not use sessions).
177 struct Session *session;
180 * What was the last latency observed for this address, plugin and peer?
182 struct GNUNET_TIME_Relative latency;
185 * If we did not successfully transmit a message to the given peer
186 * via this connection during the specified time, we should consider
187 * the connection to be dead. This is used in the case that a TCP
188 * transport simply stalls writing to the stream but does not
189 * formerly get a signal that the other peer died.
191 struct GNUNET_TIME_Absolute timeout;
194 * How often have we tried to connect using this plugin? Used to
195 * discriminate against addresses that do not work well.
196 * FIXME: not yet used, but should be!
198 unsigned int connect_attempts;
201 * DV distance to this peer (1 if no DV is used).
202 * FIXME: need to set this from transport plugins!
207 * Have we ever estimated the latency of this address? Used to
208 * ensure that the first time we add an address, we immediately
214 * Are we currently connected via this address? The first time we
215 * successfully transmit or receive data to a peer via a particular
216 * address, we set this to GNUNET_YES. If we later get an error
217 * (disconnect notification, transmission failure, timeout), we set
218 * it back to GNUNET_NO.
223 * Is this plugin currently busy transmitting to the specific target?
224 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
225 * messages do not count as 'in transmit'.
230 * Has this address been validated yet?
238 * Entry in linked list of network addresses for ourselves.
240 struct OwnAddressList
243 * This is a linked list.
245 struct OwnAddressList *next;
248 * The address, actually a pointer to the end
249 * of this struct. Do not free!
254 * How long until we auto-expire this address (unless it is
255 * re-confirmed by the transport)?
257 struct GNUNET_TIME_Absolute expires;
268 * Entry in linked list of all of our plugins.
270 struct TransportPlugin
274 * This is a linked list.
276 struct TransportPlugin *next;
279 * API of the transport as returned by the plugin's
280 * initialization function.
282 struct GNUNET_TRANSPORT_PluginFunctions *api;
285 * Short name for the plugin (i.e. "tcp").
290 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
295 * List of our known addresses for this transport.
297 struct OwnAddressList *addresses;
300 * Environment this transport service is using
303 struct GNUNET_TRANSPORT_PluginEnvironment env;
306 * ID of task that is used to clean up expired addresses.
308 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
311 * Set to GNUNET_YES if we need to scrap the existing list of
312 * "addresses" and start fresh when we receive the next address
313 * update from a transport. Set to GNUNET_NO if we should just add
314 * the new address to the list and wait for the commit call.
320 struct NeighbourList;
323 * For each neighbour we keep a list of messages
324 * that we still want to transmit to the neighbour.
330 * This is a doubly linked list.
332 struct MessageQueue *next;
335 * This is a doubly linked list.
337 struct MessageQueue *prev;
340 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
341 * stuck together in memory. Allocated at the end of this struct.
343 const char *message_buf;
346 * Size of the message buf
348 size_t message_buf_size;
351 * Client responsible for queueing the message;
352 * used to check that a client has no two messages
353 * pending for the same target. Can be NULL.
355 struct TransportClient *client;
358 * Using which specific address should we send this message?
360 struct ForeignAddressList *specific_address;
363 * Peer ID of the Neighbour this entry belongs to.
365 struct GNUNET_PeerIdentity neighbour_id;
368 * Plugin that we used for the transmission.
369 * NULL until we scheduled a transmission.
371 struct TransportPlugin *plugin;
374 * At what time should we fail?
376 struct GNUNET_TIME_Absolute timeout;
379 * Internal message of the transport system that should not be
380 * included in the usual SEND-SEND_OK transmission confirmation
381 * traffic management scheme. Typically, "internal_msg" will
382 * be set whenever "client" is NULL (but it is not strictly
388 * How important is the message?
390 unsigned int priority;
396 * For a given Neighbour, which plugins are available
397 * to talk to this peer and what are their costs?
402 * This is a linked list.
404 struct ReadyList *next;
407 * Which of our transport plugins does this entry
410 struct TransportPlugin *plugin;
413 * Transport addresses, latency, and readiness for
414 * this particular plugin.
416 struct ForeignAddressList *addresses;
419 * To which neighbour does this ready list belong to?
421 struct NeighbourList *neighbour;
427 * Entry in linked list of all of our current neighbours.
433 * This is a linked list.
435 struct NeighbourList *next;
438 * Which of our transports is connected to this peer
439 * and what is their status?
441 struct ReadyList *plugins;
444 * Head of list of messages we would like to send to this peer;
445 * must contain at most one message per client.
447 struct MessageQueue *messages_head;
450 * Tail of list of messages we would like to send to this peer; must
451 * contain at most one message per client.
453 struct MessageQueue *messages_tail;
456 * Context for peerinfo iteration.
457 * NULL after we are done processing peerinfo's information.
459 struct GNUNET_PEERINFO_IteratorContext *piter;
462 * Public key for this peer. Valid only if the respective flag is set below.
464 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
467 * Identity of this neighbour.
469 struct GNUNET_PeerIdentity id;
472 * ID of task scheduled to run when this peer is about to
473 * time out (will free resources associated with the peer).
475 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
478 * ID of task scheduled to run when we should retry transmitting
479 * the head of the message queue. Actually triggered when the
480 * transmission is timing out (we trigger instantly when we have
481 * a chance of success).
483 GNUNET_SCHEDULER_TaskIdentifier retry_task;
486 * How long until we should consider this peer dead
487 * (if we don't receive another message in the
490 struct GNUNET_TIME_Absolute peer_timeout;
493 * Tracker for inbound bandwidth.
495 struct GNUNET_BANDWIDTH_Tracker in_tracker;
498 * The latency we have seen for this particular address for
499 * this particular peer. This latency may have been calculated
500 * over multiple transports. This value reflects how long it took
501 * us to receive a response when SENDING via this particular
502 * transport/neighbour/address combination!
504 * FIXME: we need to periodically send PINGs to update this
505 * latency (at least more often than the current "huge" (11h?)
508 struct GNUNET_TIME_Relative latency;
511 * How often has the other peer (recently) violated the
512 * inbound traffic limit? Incremented by 10 per violation,
513 * decremented by 1 per non-violation (for each
516 unsigned int quota_violation_count;
519 * DV distance to this peer (1 if no DV is used).
524 * Have we seen an PONG from this neighbour in the past (and
525 * not had a disconnect since)?
530 * Do we have a valid public key for this neighbour?
532 int public_key_valid;
537 * Message used to ask a peer to validate receipt (to check an address
540 struct TransportPingMessage
544 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
546 struct GNUNET_MessageHeader header;
549 * Random challenge number (in network byte order).
551 uint32_t challenge GNUNET_PACKED;
554 * Who is the intended recipient?
556 struct GNUNET_PeerIdentity target;
562 * Message used to validate a HELLO. The challenge is included in the
563 * confirmation to make matching of replies to requests possible. The
564 * signature signs the original challenge number, our public key, the
565 * sender's address (so that the sender can check that the address we
566 * saw is plausible for him and possibly detect a MiM attack) and a
567 * timestamp (to limit replay).<p>
569 * This message is followed by the address of the
570 * client that we are observing (which is part of what
573 struct TransportPongMessage
577 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
579 struct GNUNET_MessageHeader header;
582 * For padding, always zero.
584 uint32_t reserved GNUNET_PACKED;
589 struct GNUNET_CRYPTO_RsaSignature signature;
592 * What are we signing and why?
594 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
597 * Random challenge number (in network byte order).
599 uint32_t challenge GNUNET_PACKED;
602 * Who signed this message?
604 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
607 * Size of address appended to this message
615 * Linked list of messages to be transmitted to the client. Each
616 * entry is followed by the actual message.
618 struct ClientMessageQueueEntry
621 * This is a doubly-linked list.
623 struct ClientMessageQueueEntry *next;
626 * This is a doubly-linked list.
628 struct ClientMessageQueueEntry *prev;
633 * Client connected to the transport service.
635 struct TransportClient
639 * This is a linked list.
641 struct TransportClient *next;
644 * Handle to the client.
646 struct GNUNET_SERVER_Client *client;
649 * Linked list of messages yet to be transmitted to
652 struct ClientMessageQueueEntry *message_queue_head;
655 * Tail of linked list of messages yet to be transmitted to the
658 struct ClientMessageQueueEntry *message_queue_tail;
661 * Current transmit request handle.
663 struct GNUNET_CONNECTION_TransmitHandle *th;
666 * Is a call to "transmit_send_continuation" pending? If so, we
667 * must not free this struct (even if the corresponding client
668 * disconnects) and instead only remove it from the linked list and
669 * set the "client" field to NULL.
674 * Length of the list of messages pending for this client.
676 unsigned int message_count;
682 * Entry in map of all HELLOs awaiting validation.
684 struct ValidationEntry
688 * The address, actually a pointer to the end
689 * of this struct. Do not free!
694 * Name of the transport.
696 char *transport_name;
699 * The public key of the peer.
701 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
704 * ID of task that will clean up this entry if we don't succeed
705 * with the validation first.
707 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
710 * At what time did we send this validation?
712 struct GNUNET_TIME_Absolute send_time;
715 * Session being validated (or NULL for none).
717 struct Session *session;
725 * Challenge number we used.
733 * Context of currently active requests to peerinfo
734 * for validation of HELLOs.
736 struct CheckHelloValidatedContext
740 * This is a doubly-linked list.
742 struct CheckHelloValidatedContext *next;
745 * This is a doubly-linked list.
747 struct CheckHelloValidatedContext *prev;
750 * Hello that we are validating.
752 const struct GNUNET_HELLO_Message *hello;
755 * Context for peerinfo iteration.
756 * NULL after we are done processing peerinfo's information.
758 struct GNUNET_PEERINFO_IteratorContext *piter;
761 * Was a HELLO known for this peer to peerinfo?
771 static struct GNUNET_HELLO_Message *our_hello;
774 * "version" of "our_hello". Used to see if a given neighbour has
775 * already been sent the latest version of our HELLO message.
777 static unsigned int our_hello_version;
782 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
787 static struct GNUNET_PeerIdentity my_identity;
792 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
797 struct GNUNET_SCHEDULER_Handle *sched;
802 const struct GNUNET_CONFIGURATION_Handle *cfg;
805 * Linked list of all clients to this service.
807 static struct TransportClient *clients;
810 * All loaded plugins.
812 static struct TransportPlugin *plugins;
817 static struct GNUNET_SERVER_Handle *server;
820 * All known neighbours and their HELLOs.
822 static struct NeighbourList *neighbours;
825 * Number of neighbours we'd like to have.
827 static uint32_t max_connect_per_transport;
830 * Head of linked list.
832 static struct CheckHelloValidatedContext *chvc_head;
835 * Tail of linked list.
837 static struct CheckHelloValidatedContext *chvc_tail;
840 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
841 * of the given peer that we are currently validating).
843 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
846 * Handle for reporting statistics.
848 static struct GNUNET_STATISTICS_Handle *stats;
852 * The peer specified by the given neighbour has timed-out or a plugin
853 * has disconnected. We may either need to do nothing (other plugins
854 * still up), or trigger a full disconnect and clean up. This
855 * function updates our state and do the necessary notifications.
856 * Also notifies our clients that the neighbour is now officially
859 * @param n the neighbour list entry for the peer
860 * @param check should we just check if all plugins
861 * disconnected or must we ask all plugins to
864 static void disconnect_neighbour (struct NeighbourList *n, int check);
867 * Check the ready list for the given neighbour and if a plugin is
868 * ready for transmission (and if we have a message), do so!
870 * @param neighbour target peer for which to transmit
872 static void try_transmission_to_peer (struct NeighbourList *neighbour);
876 * Find an entry in the neighbour list for a particular peer.
878 * @return NULL if not found.
880 static struct NeighbourList *
881 find_neighbour (const struct GNUNET_PeerIdentity *key)
883 struct NeighbourList *head = neighbours;
885 while ((head != NULL) &&
886 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
893 * Find an entry in the transport list for a particular transport.
895 * @return NULL if not found.
897 static struct TransportPlugin *
898 find_transport (const char *short_name)
900 struct TransportPlugin *head = plugins;
901 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
908 * Function called to notify a client about the socket being ready to
909 * queue more data. "buf" will be NULL and "size" zero if the socket
910 * was closed for writing in the meantime.
913 * @param size number of bytes available in buf
914 * @param buf where the callee should write the message
915 * @return number of bytes written to buf
918 transmit_to_client_callback (void *cls, size_t size, void *buf)
920 struct TransportClient *client = cls;
921 struct ClientMessageQueueEntry *q;
924 const struct GNUNET_MessageHeader *msg;
930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
931 "Transmission to client failed, closing connection.\n");
932 /* fatal error with client, free message queue! */
933 while (NULL != (q = client->message_queue_head))
935 GNUNET_STATISTICS_update (stats,
936 gettext_noop ("# bytes discarded (could not transmit to client)"),
937 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
939 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
940 client->message_queue_tail,
944 client->message_count = 0;
949 while (NULL != (q = client->message_queue_head))
951 msg = (const struct GNUNET_MessageHeader *) &q[1];
952 msize = ntohs (msg->size);
953 if (msize + tsize > size)
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957 "Transmitting message of type %u to client.\n",
960 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
961 client->message_queue_tail,
963 memcpy (&cbuf[tsize], msg, msize);
966 client->message_count--;
970 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
971 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
973 GNUNET_TIME_UNIT_FOREVER_REL,
974 &transmit_to_client_callback,
976 GNUNET_assert (client->th != NULL);
983 * Mark the given FAL entry as 'connected' (and hence preferred for
984 * sending); also mark all others for the same peer as 'not connected'
985 * (since only one can be preferred).
987 * @param fal address to set to 'connected'
990 mark_address_connected (struct ForeignAddressList *fal)
992 struct ForeignAddressList *pos;
995 GNUNET_assert (GNUNET_YES == fal->validated);
996 if (fal->connected == GNUNET_YES)
997 return; /* nothing to do */
999 pos = fal->ready_list->addresses;
1002 if (GNUNET_YES == pos->connected)
1004 GNUNET_break (cnt == GNUNET_YES);
1006 pos->connected = GNUNET_NO;
1010 fal->connected = GNUNET_YES;
1011 if (GNUNET_YES == cnt)
1013 GNUNET_STATISTICS_update (stats,
1014 gettext_noop ("# connected addresses"),
1022 * Send the specified message to the specified client. Since multiple
1023 * messages may be pending for the same client at a time, this code
1024 * makes sure that no message is lost.
1026 * @param client client to transmit the message to
1027 * @param msg the message to send
1028 * @param may_drop can this message be dropped if the
1029 * message queue for this client is getting far too large?
1032 transmit_to_client (struct TransportClient *client,
1033 const struct GNUNET_MessageHeader *msg, int may_drop)
1035 struct ClientMessageQueueEntry *q;
1038 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1040 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1042 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1043 client->message_count, MAX_PENDING);
1044 /* TODO: call to statistics... */
1047 msize = ntohs (msg->size);
1048 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1049 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1050 memcpy (&q[1], msg, msize);
1051 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1052 client->message_queue_tail,
1053 client->message_queue_tail,
1055 client->message_count++;
1056 if (client->th == NULL)
1058 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1060 GNUNET_TIME_UNIT_FOREVER_REL,
1061 &transmit_to_client_callback,
1063 GNUNET_assert (client->th != NULL);
1069 * Transmit a 'SEND_OK' notification to the given client for the
1072 * @param client who to notify
1073 * @param n neighbour to notify about
1074 * @param result status code for the transmission request
1077 transmit_send_ok (struct TransportClient *client,
1078 struct NeighbourList *n,
1081 struct SendOkMessage send_ok_msg;
1083 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1084 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1085 send_ok_msg.success = htonl (result);
1086 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1087 send_ok_msg.peer = n->id;
1088 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1093 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1094 * upon "completion" of a send request. This tells the API
1095 * that it is now legal to send another message to the given
1098 * @param cls closure, identifies the entry on the
1099 * message queue that was transmitted and the
1100 * client responsible for queueing the message
1101 * @param target the peer receiving the message
1102 * @param result GNUNET_OK on success, if the transmission
1103 * failed, we should not tell the client to transmit
1107 transmit_send_continuation (void *cls,
1108 const struct GNUNET_PeerIdentity *target,
1111 struct MessageQueue *mq = cls;
1112 struct NeighbourList *n;
1114 GNUNET_STATISTICS_update (stats,
1115 gettext_noop ("# bytes pending with plugins"),
1116 - (int64_t) mq->message_buf_size,
1118 if (result == GNUNET_OK)
1120 GNUNET_STATISTICS_update (stats,
1121 gettext_noop ("# bytes successfully transmitted by plugins"),
1122 mq->message_buf_size,
1127 GNUNET_STATISTICS_update (stats,
1128 gettext_noop ("# bytes with transmission failure by plugins"),
1129 mq->message_buf_size,
1132 n = find_neighbour(&mq->neighbour_id);
1133 GNUNET_assert (n != NULL);
1134 if (mq->specific_address != NULL)
1136 if (result == GNUNET_OK)
1138 mq->specific_address->timeout =
1139 GNUNET_TIME_relative_to_absolute
1140 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1141 if (mq->specific_address->validated == GNUNET_YES)
1142 mark_address_connected (mq->specific_address);
1146 if (mq->specific_address->connected != GNUNET_NO)
1148 GNUNET_STATISTICS_update (stats,
1149 gettext_noop ("# connected addresses"),
1152 mq->specific_address->connected = GNUNET_NO;
1155 if (! mq->internal_msg)
1156 mq->specific_address->in_transmit = GNUNET_NO;
1158 if (mq->client != NULL)
1159 transmit_send_ok (mq->client, n, result);
1161 try_transmission_to_peer (n);
1166 * Find an address in any of the available transports for
1167 * the given neighbour that would be good for message
1168 * transmission. This is essentially the transport selection
1171 * @param neighbour for whom to select an address
1172 * @return selected address, NULL if we have none
1174 struct ForeignAddressList *
1175 find_ready_address(struct NeighbourList *neighbour)
1177 struct ReadyList *head = neighbour->plugins;
1178 struct ForeignAddressList *addresses;
1179 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1180 struct ForeignAddressList *best_address;
1182 best_address = NULL;
1183 while (head != NULL)
1185 addresses = head->addresses;
1186 while (addresses != NULL)
1188 if ( (addresses->timeout.value < now.value) &&
1189 (addresses->connected == GNUNET_YES) )
1192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1193 "Marking long-time inactive connection to `%4s' as down.\n",
1194 GNUNET_i2s (&neighbour->id));
1196 GNUNET_STATISTICS_update (stats,
1197 gettext_noop ("# connected addresses"),
1200 addresses->connected = GNUNET_NO;
1202 addresses = addresses->next;
1205 addresses = head->addresses;
1206 while (addresses != NULL)
1208 #if DEBUG_TRANSPORT > 1
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1211 GNUNET_a2s (addresses->addr,
1212 addresses->addrlen),
1213 GNUNET_i2s (&neighbour->id),
1214 addresses->connected,
1215 addresses->in_transmit,
1216 addresses->validated,
1217 addresses->connect_attempts,
1218 (unsigned long long) addresses->timeout.value,
1219 (unsigned int) addresses->distance);
1221 if ( ( (best_address == NULL) ||
1222 (addresses->connected == GNUNET_YES) ||
1223 (best_address->connected == GNUNET_NO) ) &&
1224 (addresses->in_transmit == GNUNET_NO) &&
1225 ( (best_address == NULL) ||
1226 (addresses->latency.value < best_address->latency.value)) )
1227 best_address = addresses;
1228 /* FIXME: also give lower-latency addresses that are not
1229 connected a chance some times... */
1230 addresses = addresses->next;
1234 if (best_address != NULL)
1237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1238 "Best address found has latency of %llu ms.\n",
1239 best_address->latency.value);
1244 GNUNET_STATISTICS_update (stats,
1245 gettext_noop ("# transmission attempts failed (no address)"),
1249 return best_address;
1255 * We should re-try transmitting to the given peer,
1256 * hopefully we've learned something in the meantime.
1259 retry_transmission_task (void *cls,
1260 const struct GNUNET_SCHEDULER_TaskContext *tc)
1262 struct NeighbourList *n = cls;
1264 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1265 try_transmission_to_peer (n);
1270 * Check the ready list for the given neighbour and if a plugin is
1271 * ready for transmission (and if we have a message), do so!
1273 * @param neighbour target peer for which to transmit
1276 try_transmission_to_peer (struct NeighbourList *neighbour)
1278 struct ReadyList *rl;
1279 struct MessageQueue *mq;
1280 struct GNUNET_TIME_Relative timeout;
1284 if (neighbour->messages_head == NULL)
1287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288 "Transmission queue for `%4s' is empty\n",
1289 GNUNET_i2s (&neighbour->id));
1291 return; /* nothing to do */
1294 mq = neighbour->messages_head;
1295 force_address = GNUNET_YES;
1296 if (mq->specific_address == NULL)
1298 mq->specific_address = find_ready_address(neighbour);
1299 GNUNET_STATISTICS_update (stats,
1300 gettext_noop ("# transport selected peer address freely"),
1303 force_address = GNUNET_NO;
1305 if (mq->specific_address == NULL)
1307 GNUNET_STATISTICS_update (stats,
1308 gettext_noop ("# transport failed to selected peer address"),
1311 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1312 if (timeout.value == 0)
1315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1316 "No destination address available to transmit message of size %u to peer `%4s'\n",
1317 mq->message_buf_size,
1318 GNUNET_i2s (&mq->neighbour_id));
1320 GNUNET_STATISTICS_update (stats,
1321 gettext_noop ("# bytes in message queue for other peers"),
1322 - (int64_t) mq->message_buf_size,
1324 GNUNET_STATISTICS_update (stats,
1325 gettext_noop ("# bytes discarded (no destination address available)"),
1326 mq->message_buf_size,
1328 if (mq->client != NULL)
1329 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1330 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1331 neighbour->messages_tail,
1334 return; /* nobody ready */
1336 GNUNET_STATISTICS_update (stats,
1337 gettext_noop ("# message delivery deferred (no address)"),
1340 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1341 GNUNET_SCHEDULER_cancel (sched,
1342 neighbour->retry_task);
1343 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1345 &retry_transmission_task,
1348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1349 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1350 mq->message_buf_size,
1351 GNUNET_i2s (&mq->neighbour_id),
1354 /* FIXME: might want to trigger peerinfo lookup here
1355 (unless that's already pending...) */
1358 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1359 neighbour->messages_tail,
1361 if (mq->specific_address->connected == GNUNET_NO)
1362 mq->specific_address->connect_attempts++;
1363 rl = mq->specific_address->ready_list;
1364 mq->plugin = rl->plugin;
1365 if (!mq->internal_msg)
1366 mq->specific_address->in_transmit = GNUNET_YES;
1368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1369 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1370 mq->message_buf_size,
1371 GNUNET_i2s (&neighbour->id),
1372 GNUNET_a2s (mq->specific_address->addr,
1373 mq->specific_address->addrlen),
1374 rl->plugin->short_name);
1376 GNUNET_STATISTICS_update (stats,
1377 gettext_noop ("# bytes in message queue for other peers"),
1378 - (int64_t) mq->message_buf_size,
1380 GNUNET_STATISTICS_update (stats,
1381 gettext_noop ("# bytes pending with plugins"),
1382 mq->message_buf_size,
1384 ret = rl->plugin->api->send (rl->plugin->api->cls,
1387 mq->message_buf_size,
1389 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1390 mq->specific_address->session,
1391 mq->specific_address->addr,
1392 mq->specific_address->addrlen,
1394 &transmit_send_continuation, mq);
1397 /* failure, but 'send' would not call continuation in this case,
1398 so we need to do it here! */
1399 transmit_send_continuation (mq,
1407 * Send the specified message to the specified peer.
1409 * @param client source of the transmission request (can be NULL)
1410 * @param peer_address ForeignAddressList where we should send this message
1411 * @param priority how important is the message
1412 * @param timeout how long do we have to transmit?
1413 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1414 * @param message_buf_size total size of all messages in message_buf
1415 * @param is_internal is this an internal message; these are pre-pended and
1416 * also do not count for plugins being "ready" to transmit
1417 * @param neighbour handle to the neighbour for transmission
1420 transmit_to_peer (struct TransportClient *client,
1421 struct ForeignAddressList *peer_address,
1422 unsigned int priority,
1423 struct GNUNET_TIME_Relative timeout,
1424 const char *message_buf,
1425 size_t message_buf_size,
1426 int is_internal, struct NeighbourList *neighbour)
1428 struct MessageQueue *mq;
1433 /* check for duplicate submission */
1434 mq = neighbour->messages_head;
1437 if (mq->client == client)
1439 /* client transmitted to same peer twice
1440 before getting SEND_OK! */
1448 GNUNET_STATISTICS_update (stats,
1449 gettext_noop ("# bytes in message queue for other peers"),
1452 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1453 mq->specific_address = peer_address;
1454 mq->client = client;
1455 memcpy (&mq[1], message_buf, message_buf_size);
1456 mq->message_buf = (const char*) &mq[1];
1457 mq->message_buf_size = message_buf_size;
1458 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1459 mq->internal_msg = is_internal;
1460 mq->priority = priority;
1461 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1463 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1464 neighbour->messages_tail,
1467 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1468 neighbour->messages_tail,
1469 neighbour->messages_tail,
1471 try_transmission_to_peer (neighbour);
1478 struct GeneratorContext
1480 struct TransportPlugin *plug_pos;
1481 struct OwnAddressList *addr_pos;
1482 struct GNUNET_TIME_Absolute expiration;
1490 address_generator (void *cls, size_t max, void *buf)
1492 struct GeneratorContext *gc = cls;
1495 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1497 gc->plug_pos = gc->plug_pos->next;
1498 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1500 if (NULL == gc->plug_pos)
1505 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1508 gc->addr_pos->addrlen, buf, max);
1509 gc->addr_pos = gc->addr_pos->next;
1515 * Construct our HELLO message from all of the addresses of
1516 * all of the transports.
1521 struct GNUNET_HELLO_Message *hello;
1522 struct TransportClient *cpos;
1523 struct NeighbourList *npos;
1524 struct GeneratorContext gc;
1526 gc.plug_pos = plugins;
1527 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1528 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1529 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1532 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1534 GNUNET_STATISTICS_update (stats,
1535 gettext_noop ("# refreshed my HELLO"),
1539 while (cpos != NULL)
1541 transmit_to_client (cpos,
1542 (const struct GNUNET_MessageHeader *) hello,
1547 GNUNET_free_non_null (our_hello);
1549 our_hello_version++;
1550 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1552 while (npos != NULL)
1555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1556 "Transmitting updated `%s' to neighbour `%4s'\n",
1557 "HELLO", GNUNET_i2s (&npos->id));
1559 GNUNET_STATISTICS_update (stats,
1560 gettext_noop ("# transmitted my HELLO to other peers"),
1563 transmit_to_peer (NULL, NULL, 0,
1564 HELLO_ADDRESS_EXPIRATION,
1565 (const char *) our_hello,
1566 GNUNET_HELLO_size(our_hello),
1574 * Task used to clean up expired addresses for a plugin.
1576 * @param cls closure
1580 expire_address_task (void *cls,
1581 const struct GNUNET_SCHEDULER_TaskContext *tc);
1585 * Update the list of addresses for this plugin,
1586 * expiring those that are past their expiration date.
1588 * @param plugin addresses of which plugin should be recomputed?
1589 * @param fresh set to GNUNET_YES if a new address was added
1590 * and we need to regenerate the HELLO even if nobody
1594 update_addresses (struct TransportPlugin *plugin, int fresh)
1596 static struct GNUNET_TIME_Absolute last_update;
1597 struct GNUNET_TIME_Relative min_remaining;
1598 struct GNUNET_TIME_Relative remaining;
1599 struct GNUNET_TIME_Absolute now;
1600 struct OwnAddressList *pos;
1601 struct OwnAddressList *prev;
1602 struct OwnAddressList *next;
1605 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1606 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1607 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1608 now = GNUNET_TIME_absolute_get ();
1609 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1610 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1612 pos = plugin->addresses;
1616 if (pos->expires.value < now.value)
1618 expired = GNUNET_YES;
1620 plugin->addresses = pos->next;
1622 prev->next = pos->next;
1627 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1628 if (remaining.value < min_remaining.value)
1629 min_remaining = remaining;
1635 if (expired || fresh)
1640 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1641 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1643 plugin->address_update_task
1644 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1646 &expire_address_task, plugin);
1651 * Task used to clean up expired addresses for a plugin.
1653 * @param cls closure
1657 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1659 struct TransportPlugin *plugin = cls;
1661 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1662 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1663 update_addresses (plugin, GNUNET_NO);
1668 * Iterator over hash map entries that NULLs the session of validation
1669 * entries that match the given session.
1671 * @param cls closure (the 'struct Session*' to match against)
1672 * @param key current key code (peer ID, not used)
1673 * @param value value in the hash map ('struct ValidationEntry*')
1674 * @return GNUNET_YES (we should continue to iterate)
1677 remove_session_validations (void *cls,
1678 const GNUNET_HashCode * key,
1681 struct Session *session = cls;
1682 struct ValidationEntry *ve = value;
1684 if (session == ve->session)
1691 * Function that will be called whenever the plugin internally
1692 * cleans up a session pointer and hence the service needs to
1693 * discard all of those sessions as well. Plugins that do not
1694 * use sessions can simply omit calling this function and always
1695 * use NULL wherever a session pointer is needed.
1697 * @param cls closure
1698 * @param peer which peer was the session for
1699 * @param session which session is being destoyed
1702 plugin_env_session_end (void *cls,
1703 const struct GNUNET_PeerIdentity *peer,
1704 struct Session *session)
1706 struct TransportPlugin *p = cls;
1707 struct NeighbourList *nl;
1708 struct ReadyList *rl;
1709 struct ForeignAddressList *pos;
1710 struct ForeignAddressList *prev;
1712 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1713 &remove_session_validations,
1715 nl = find_neighbour (peer);
1721 if (rl->plugin == p)
1728 pos = rl->addresses;
1729 while ( (pos != NULL) &&
1730 (pos->session != session) )
1737 pos->session = NULL;
1738 if (pos->addrlen != 0)
1741 rl->addresses = pos->next;
1743 prev->next = pos->next;
1745 if (nl->received_pong == GNUNET_NO)
1746 return; /* nothing to do */
1747 /* check if we have any validated addresses left */
1748 pos = rl->addresses;
1755 /* no valid addresses left, signal disconnect! */
1756 disconnect_neighbour (nl, GNUNET_NO);
1761 * Function that must be called by each plugin to notify the
1762 * transport service about the addresses under which the transport
1763 * provided by the plugin can be reached.
1765 * @param cls closure
1766 * @param name name of the transport that generated the address
1767 * @param addr one of the addresses of the host, NULL for the last address
1768 * the specific address format depends on the transport
1769 * @param addrlen length of the address
1770 * @param expires when should this address automatically expire?
1773 plugin_env_notify_address (void *cls,
1777 struct GNUNET_TIME_Relative expires)
1779 struct TransportPlugin *p = cls;
1780 struct OwnAddressList *al;
1781 struct GNUNET_TIME_Absolute abex;
1783 abex = GNUNET_TIME_relative_to_absolute (expires);
1784 GNUNET_assert (p == find_transport (name));
1789 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1791 if (al->expires.value < abex.value)
1798 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1800 al->next = p->addresses;
1803 al->addrlen = addrlen;
1804 memcpy (&al[1], addr, addrlen);
1805 update_addresses (p, GNUNET_YES);
1810 * Notify all of our clients about a peer connecting.
1813 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1814 struct GNUNET_TIME_Relative latency,
1817 struct ConnectInfoMessage cim;
1818 struct TransportClient *cpos;
1821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1822 "Notifying clients about connection from `%s'\n",
1825 GNUNET_STATISTICS_update (stats,
1826 gettext_noop ("# peers connected"),
1829 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1830 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1831 cim.distance = htonl (distance);
1832 cim.latency = GNUNET_TIME_relative_hton (latency);
1833 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1835 while (cpos != NULL)
1837 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1844 * Notify all of our clients about a peer disconnecting.
1847 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1849 struct DisconnectInfoMessage dim;
1850 struct TransportClient *cpos;
1853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1854 "Notifying clients about lost connection to `%s'\n",
1857 GNUNET_STATISTICS_update (stats,
1858 gettext_noop ("# peers connected"),
1861 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1862 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1863 dim.reserved = htonl (0);
1864 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1866 while (cpos != NULL)
1868 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1875 * Find a ForeignAddressList entry for the given neighbour
1876 * that matches the given address and transport.
1878 * @param neighbour which peer we care about
1879 * @param tname name of the transport plugin
1880 * @param session session to look for, NULL for 'any'; otherwise
1881 * can be used for the service to "learn" this session ID
1882 * @param addr binary address
1883 * @param addrlen length of addr
1884 * @return NULL if no such entry exists
1886 static struct ForeignAddressList *
1887 find_peer_address(struct NeighbourList *neighbour,
1889 struct Session *session,
1893 struct ReadyList *head;
1894 struct ForeignAddressList *address_head;
1896 head = neighbour->plugins;
1897 while (head != NULL)
1899 if (0 == strcmp (tname, head->plugin->short_name))
1906 address_head = head->addresses;
1907 while ( (address_head != NULL) &&
1908 ( (address_head->addrlen != addrlen) ||
1909 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1910 address_head = address_head->next;
1911 if ( (session != NULL) && (address_head != NULL) )
1912 address_head->session = session; /* learn it! */
1913 return address_head;
1918 * Get the peer address struct for the given neighbour and
1919 * address. If it doesn't yet exist, create it.
1921 * @param neighbour which peer we care about
1922 * @param tname name of the transport plugin
1923 * @param session session of the plugin, or NULL for none
1924 * @param addr binary address
1925 * @param addrlen length of addr
1926 * @return NULL if we do not have a transport plugin for 'tname'
1928 static struct ForeignAddressList *
1929 add_peer_address (struct NeighbourList *neighbour,
1931 struct Session *session,
1935 struct ReadyList *head;
1936 struct ForeignAddressList *ret;
1938 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
1941 head = neighbour->plugins;
1942 while (head != NULL)
1944 if (0 == strcmp (tname, head->plugin->short_name))
1950 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1951 ret->session = session;
1954 ret->addr = (const char*) &ret[1];
1955 memcpy (&ret[1], addr, addrlen);
1961 ret->addrlen = addrlen;
1962 ret->expires = GNUNET_TIME_relative_to_absolute
1963 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1964 ret->latency = GNUNET_TIME_relative_get_forever();
1966 ret->timeout = GNUNET_TIME_relative_to_absolute
1967 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1968 ret->ready_list = head;
1969 ret->next = head->addresses;
1970 head->addresses = ret;
1976 * Closure for 'add_validated_address'.
1978 struct AddValidatedAddressContext
1981 * Entry that has been validated.
1983 const struct ValidationEntry *ve;
1986 * Flag set after we have added the address so
1987 * that we terminate the iteration next time.
1994 * Callback function used to fill a buffer of max bytes with a list of
1995 * addresses in the format used by HELLOs. Should use
1996 * "GNUNET_HELLO_add_address" as a helper function.
1998 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1999 * @param max maximum number of bytes that can be written to buf
2000 * @param buf where to write the address information
2001 * @return number of bytes written, 0 to signal the
2002 * end of the iteration.
2005 add_validated_address (void *cls,
2006 size_t max, void *buf)
2008 struct AddValidatedAddressContext *avac = cls;
2009 const struct ValidationEntry *ve = avac->ve;
2011 if (GNUNET_YES == avac->done)
2013 avac->done = GNUNET_YES;
2014 return GNUNET_HELLO_add_address (ve->transport_name,
2015 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2025 * Closure for 'check_address_exists'.
2027 struct CheckAddressExistsClosure
2030 * Address to check for.
2035 * Name of the transport.
2045 * Set to GNUNET_YES if the address exists.
2052 * Iterator over hash map entries. Checks if the given
2053 * validation entry is for the same address as what is given
2056 * @param cls the 'struct CheckAddressExistsClosure*'
2057 * @param key current key code (ignored)
2058 * @param value value in the hash map ('struct ValidationEntry')
2059 * @return GNUNET_YES if we should continue to
2060 * iterate (mismatch), GNUNET_NO if not (entry matched)
2063 check_address_exists (void *cls,
2064 const GNUNET_HashCode * key,
2067 struct CheckAddressExistsClosure *caec = cls;
2068 struct ValidationEntry *ve = value;
2069 if ( (0 == strcmp (caec->tname,
2070 ve->transport_name)) &&
2071 (caec->addrlen == ve->addrlen) &&
2072 (0 == memcmp (caec->addr,
2076 caec->exists = GNUNET_YES;
2084 * HELLO validation cleanup task (validation failed).
2086 * @param cls the 'struct ValidationEntry' that failed
2087 * @param tc scheduler context (unused)
2090 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2092 struct ValidationEntry *va = cls;
2093 struct GNUNET_PeerIdentity pid;
2095 GNUNET_STATISTICS_update (stats,
2096 gettext_noop ("# address validation timeouts"),
2099 GNUNET_CRYPTO_hash (&va->publicKey,
2101 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2103 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2106 GNUNET_free (va->transport_name);
2112 neighbour_timeout_task (void *cls,
2113 const struct GNUNET_SCHEDULER_TaskContext *tc)
2115 struct NeighbourList *n = cls;
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2119 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2121 GNUNET_STATISTICS_update (stats,
2122 gettext_noop ("# disconnects due to timeout"),
2125 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2126 disconnect_neighbour (n, GNUNET_NO);
2131 * Schedule the job that will cause us to send a PING to the
2132 * foreign address to evaluate its validity and latency.
2134 * @param fal address to PING
2137 schedule_next_ping (struct ForeignAddressList *fal);
2141 * Add the given address to the list of foreign addresses
2142 * available for the given peer (check for duplicates).
2144 * @param cls the respective 'struct NeighbourList' to update
2145 * @param tname name of the transport
2146 * @param expiration expiration time
2147 * @param addr the address
2148 * @param addrlen length of the address
2149 * @return GNUNET_OK (always)
2152 add_to_foreign_address_list (void *cls,
2154 struct GNUNET_TIME_Absolute expiration,
2155 const void *addr, size_t addrlen)
2157 struct NeighbourList *n = cls;
2158 struct ForeignAddressList *fal;
2161 GNUNET_STATISTICS_update (stats,
2162 gettext_noop ("# valid peer addresses returned by peerinfo"),
2166 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2171 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2172 GNUNET_a2s (addr, addrlen),
2174 GNUNET_i2s (&n->id),
2177 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2180 GNUNET_STATISTICS_update (stats,
2181 gettext_noop ("# previously validated addresses lacking transport"),
2187 fal->expires = GNUNET_TIME_absolute_max (expiration,
2189 schedule_next_ping (fal);
2195 fal->expires = GNUNET_TIME_absolute_max (expiration,
2200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2201 "Failed to add new address for `%4s'\n",
2202 GNUNET_i2s (&n->id));
2205 if (fal->validated == GNUNET_NO)
2207 fal->validated = GNUNET_YES;
2208 GNUNET_STATISTICS_update (stats,
2209 gettext_noop ("# peer addresses considered valid"),
2213 if (try == GNUNET_YES)
2215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216 "Have new addresses, will try to trigger transmissions.\n");
2217 try_transmission_to_peer (n);
2224 * Add addresses in validated HELLO "h" to the set of addresses
2225 * we have for this peer.
2227 * @param cls closure ('struct NeighbourList*')
2228 * @param peer id of the peer, NULL for last call
2229 * @param h hello message for the peer (can be NULL)
2230 * @param trust amount of trust we have in the peer (not used)
2233 add_hello_for_peer (void *cls,
2234 const struct GNUNET_PeerIdentity *peer,
2235 const struct GNUNET_HELLO_Message *h,
2238 struct NeighbourList *n = cls;
2246 return; /* no HELLO available */
2248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2249 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2253 if (GNUNET_YES != n->public_key_valid)
2255 GNUNET_HELLO_get_key (h, &n->publicKey);
2256 n->public_key_valid = GNUNET_YES;
2258 GNUNET_HELLO_iterate_addresses (h,
2260 &add_to_foreign_address_list,
2266 * Create a fresh entry in our neighbour list for the given peer.
2267 * Will try to transmit our current HELLO to the new neighbour.
2269 * @param peer the peer for which we create the entry
2270 * @return the new neighbour list entry
2272 static struct NeighbourList *
2273 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2275 struct NeighbourList *n;
2276 struct TransportPlugin *tp;
2277 struct ReadyList *rl;
2279 GNUNET_assert (our_hello != NULL);
2280 GNUNET_STATISTICS_update (stats,
2281 gettext_noop ("# active neighbours"),
2284 n = GNUNET_malloc (sizeof (struct NeighbourList));
2285 n->next = neighbours;
2289 GNUNET_TIME_relative_to_absolute
2290 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2291 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2292 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2293 MAX_BANDWIDTH_CARRY_S);
2297 if (tp->api->send != NULL)
2299 rl = GNUNET_malloc (sizeof (struct ReadyList));
2301 rl->next = n->plugins;
2304 rl->addresses = NULL;
2308 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2310 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2311 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2312 &neighbour_timeout_task, n);
2313 n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2314 0, GNUNET_TIME_UNIT_FOREVER_REL,
2315 &add_hello_for_peer, n);
2316 transmit_to_peer (NULL, NULL, 0,
2317 HELLO_ADDRESS_EXPIRATION,
2318 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2325 * Send periodic PING messages to a give foreign address.
2327 * @param cls our 'struct PeriodicValidationContext*'
2328 * @param tc task context
2331 send_periodic_ping (void *cls,
2332 const struct GNUNET_SCHEDULER_TaskContext *tc)
2334 struct ForeignAddressList *peer_address = cls;
2335 struct TransportPlugin *tp;
2336 struct ValidationEntry *va;
2337 struct NeighbourList *neighbour;
2338 struct TransportPingMessage ping;
2339 struct CheckAddressExistsClosure caec;
2341 uint16_t hello_size;
2344 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2345 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2347 tp = peer_address->ready_list->plugin;
2348 neighbour = peer_address->ready_list->neighbour;
2349 if (GNUNET_YES != neighbour->public_key_valid)
2351 /* no public key yet, try again later */
2352 schedule_next_ping (peer_address);
2355 caec.addr = peer_address->addr;
2356 caec.addrlen = peer_address->addrlen;
2357 caec.tname = tp->short_name;
2358 caec.exists = GNUNET_NO;
2359 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2360 &check_address_exists,
2362 if (caec.exists == GNUNET_YES)
2364 /* During validation attempts we will likely trigger the other
2365 peer trying to validate our address which in turn will cause
2366 it to send us its HELLO, so we expect to hit this case rather
2367 frequently. Only print something if we are very verbose. */
2368 #if DEBUG_TRANSPORT > 1
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2371 GNUNET_a2s (peer_address->addr,
2372 peer_address->addrlen),
2374 GNUNET_i2s (&neighbour->id));
2376 schedule_next_ping (peer_address);
2379 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2380 va->transport_name = GNUNET_strdup (tp->short_name);
2381 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2383 va->send_time = GNUNET_TIME_absolute_get();
2384 va->session = peer_address->session;
2385 va->addr = (const void*) &va[1];
2386 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2387 va->addrlen = peer_address->addrlen;
2389 memcpy(&va->publicKey,
2390 &neighbour->publicKey,
2391 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2393 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2394 HELLO_VERIFICATION_TIMEOUT,
2395 &timeout_hello_validation,
2397 GNUNET_CONTAINER_multihashmap_put (validation_map,
2398 &neighbour->id.hashPubKey,
2400 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2401 hello_size = GNUNET_HELLO_size(our_hello);
2402 tsize = sizeof(struct TransportPingMessage) + hello_size;
2403 message_buf = GNUNET_malloc(tsize);
2404 ping.challenge = htonl(va->challenge);
2405 ping.header.size = htons(sizeof(struct TransportPingMessage));
2406 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2407 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2408 memcpy(message_buf, our_hello, hello_size);
2409 memcpy(&message_buf[hello_size],
2411 sizeof(struct TransportPingMessage));
2412 #if DEBUG_TRANSPORT_REVALIDATION
2413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2414 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2415 GNUNET_a2s (peer_address->addr,
2416 peer_address->addrlen),
2418 GNUNET_i2s (&neighbour->id),
2419 "HELLO", hello_size,
2420 "PING", sizeof (struct TransportPingMessage));
2422 GNUNET_STATISTICS_update (stats,
2423 gettext_noop ("# PING messages sent for re-validation"),
2426 transmit_to_peer (NULL, peer_address,
2427 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2428 HELLO_VERIFICATION_TIMEOUT,
2430 GNUNET_YES, neighbour);
2431 GNUNET_free(message_buf);
2432 schedule_next_ping (peer_address);
2437 * Schedule the job that will cause us to send a PING to the
2438 * foreign address to evaluate its validity and latency.
2440 * @param fal address to PING
2443 schedule_next_ping (struct ForeignAddressList *fal)
2445 struct GNUNET_TIME_Relative delay;
2447 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2449 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2450 delay.value /= 2; /* do before expiration */
2451 delay = GNUNET_TIME_relative_min (delay,
2452 LATENCY_EVALUATION_MAX_DELAY);
2453 if (GNUNET_YES != fal->estimated)
2455 delay = GNUNET_TIME_UNIT_ZERO;
2456 fal->estimated = GNUNET_YES;
2458 if (GNUNET_YES == fal->connected)
2460 delay = GNUNET_TIME_relative_min (delay,
2461 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2463 /* FIXME: also adjust delay based on how close the last
2464 observed latency is to the latency of the best alternative */
2465 /* bound how fast we can go */
2466 delay = GNUNET_TIME_relative_max (delay,
2467 GNUNET_TIME_UNIT_SECONDS);
2468 /* randomize a bit (to avoid doing all at the same time) */
2469 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2470 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
2472 &send_periodic_ping,
2478 * Iterator over hash map entries. Checks if the given validation
2479 * entry is for the same challenge as what is given in the PONG.
2481 * @param cls the 'struct TransportPongMessage*'
2482 * @param key peer identity
2483 * @param value value in the hash map ('struct ValidationEntry')
2484 * @return GNUNET_YES if we should continue to
2485 * iterate (mismatch), GNUNET_NO if not (entry matched)
2488 check_pending_validation (void *cls,
2489 const GNUNET_HashCode * key,
2492 const struct TransportPongMessage *pong = cls;
2493 struct ValidationEntry *ve = value;
2494 struct AddValidatedAddressContext avac;
2495 unsigned int challenge = ntohl(pong->challenge);
2496 struct GNUNET_HELLO_Message *hello;
2497 struct GNUNET_PeerIdentity target;
2498 struct NeighbourList *n;
2499 struct ForeignAddressList *fal;
2501 if (ve->challenge != challenge)
2504 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
2509 GNUNET_break_op (0);
2514 if (ve->addr != NULL)
2515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2516 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2518 GNUNET_a2s ((const struct sockaddr *) ve->addr,
2520 ve->transport_name);
2522 GNUNET_STATISTICS_update (stats,
2523 gettext_noop ("# address validation successes"),
2526 /* create the updated HELLO */
2527 GNUNET_CRYPTO_hash (&ve->publicKey,
2528 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2529 &target.hashPubKey);
2530 avac.done = GNUNET_NO;
2532 hello = GNUNET_HELLO_create (&ve->publicKey,
2533 &add_validated_address,
2535 GNUNET_PEERINFO_add_peer (cfg, sched,
2538 GNUNET_free (hello);
2539 n = find_neighbour (&target);
2542 n->publicKey = ve->publicKey;
2543 n->public_key_valid = GNUNET_YES;
2544 fal = add_peer_address (n,
2549 GNUNET_assert (fal != NULL);
2550 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2551 fal->validated = GNUNET_YES;
2552 mark_address_connected (fal);
2553 GNUNET_STATISTICS_update (stats,
2554 gettext_noop ("# peer addresses considered valid"),
2557 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2558 schedule_next_ping (fal);
2559 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2560 n->latency = fal->latency;
2562 n->latency.value = (fal->latency.value + n->latency.value) / 2;
2563 n->distance = fal->distance;
2564 if (GNUNET_NO == n->received_pong)
2566 n->received_pong = GNUNET_YES;
2567 notify_clients_connect (&target, n->latency, n->distance);
2569 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2571 GNUNET_SCHEDULER_cancel (sched,
2573 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2574 try_transmission_to_peer (n);
2578 /* clean up validation entry */
2579 GNUNET_assert (GNUNET_YES ==
2580 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2583 GNUNET_SCHEDULER_cancel (sched,
2585 GNUNET_free (ve->transport_name);
2592 * Function that will be called if we receive a validation
2593 * of an address challenge that we transmitted to another
2594 * peer. Note that the validation should only be considered
2595 * acceptable if the challenge matches AND if the sender
2596 * address is at least a plausible address for this peer
2597 * (otherwise we may be seeing a MiM attack).
2599 * @param cls closure
2600 * @param message the pong message
2601 * @param peer who responded to our challenge
2602 * @param sender_address string describing our sender address (as observed
2603 * by the other peer in binary format)
2604 * @param sender_address_len number of bytes in 'sender_address'
2607 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2608 const struct GNUNET_PeerIdentity *peer,
2609 const char *sender_address,
2610 size_t sender_address_len)
2612 #if DEBUG_TRANSPORT > 1
2613 /* we get tons of these that just get discarded, only log
2614 if we are quite verbose */
2615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2616 "Receiving `%s' message from `%4s'.\n", "PONG",
2619 GNUNET_STATISTICS_update (stats,
2620 gettext_noop ("# PONG messages received"),
2623 if (GNUNET_SYSERR !=
2624 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2626 &check_pending_validation,
2629 /* This is *expected* to happen a lot since we send
2630 PONGs to *all* known addresses of the sender of
2631 the PING, so most likely we get multiple PONGs
2632 per PING, and all but the first PONG will end up
2633 here. So really we should not print anything here
2634 unless we want to be very, very verbose... */
2635 #if DEBUG_TRANSPORT > 2
2636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2637 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2646 /* FIXME: add given address to potential pool of our addresses
2648 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2649 _("Another peer saw us using the address `%s' via `%s'.\n"),
2650 GNUNET_a2s ((const struct sockaddr *) &pong[1],
2651 ntohs(pong->addrlen)),
2652 va->transport_name);
2658 * Check if the given address is already being validated; if not,
2659 * append the given address to the list of entries that are being be
2660 * validated and initiate validation.
2662 * @param cls closure ('struct CheckHelloValidatedContext *')
2663 * @param tname name of the transport
2664 * @param expiration expiration time
2665 * @param addr the address
2666 * @param addrlen length of the address
2667 * @return GNUNET_OK (always)
2670 run_validation (void *cls,
2672 struct GNUNET_TIME_Absolute expiration,
2673 const void *addr, size_t addrlen)
2675 struct CheckHelloValidatedContext *chvc = cls;
2676 struct GNUNET_PeerIdentity id;
2677 struct TransportPlugin *tp;
2678 struct ValidationEntry *va;
2679 struct NeighbourList *neighbour;
2680 struct ForeignAddressList *peer_address;
2681 struct TransportPingMessage ping;
2682 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2683 struct CheckAddressExistsClosure caec;
2685 uint16_t hello_size;
2688 GNUNET_STATISTICS_update (stats,
2689 gettext_noop ("# peer addresses scheduled for validation"),
2692 tp = find_transport (tname);
2695 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2696 GNUNET_ERROR_TYPE_BULK,
2698 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2700 GNUNET_STATISTICS_update (stats,
2701 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2706 GNUNET_HELLO_get_key (chvc->hello, &pk);
2707 GNUNET_CRYPTO_hash (&pk,
2709 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2712 caec.addrlen = addrlen;
2714 caec.exists = GNUNET_NO;
2715 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2716 &check_address_exists,
2718 if (caec.exists == GNUNET_YES)
2720 /* During validation attempts we will likely trigger the other
2721 peer trying to validate our address which in turn will cause
2722 it to send us its HELLO, so we expect to hit this case rather
2723 frequently. Only print something if we are very verbose. */
2724 #if DEBUG_TRANSPORT > 1
2725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2726 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2727 GNUNET_a2s (addr, addrlen),
2731 GNUNET_STATISTICS_update (stats,
2732 gettext_noop ("# peer addresses not validated (in progress)"),
2737 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2738 va->transport_name = GNUNET_strdup (tname);
2739 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2741 va->send_time = GNUNET_TIME_absolute_get();
2742 va->addr = (const void*) &va[1];
2743 memcpy (&va[1], addr, addrlen);
2744 va->addrlen = addrlen;
2745 GNUNET_HELLO_get_key (chvc->hello,
2747 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2748 HELLO_VERIFICATION_TIMEOUT,
2749 &timeout_hello_validation,
2751 GNUNET_CONTAINER_multihashmap_put (validation_map,
2754 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2755 neighbour = find_neighbour(&id);
2756 if (neighbour == NULL)
2757 neighbour = setup_new_neighbour(&id);
2758 neighbour->publicKey = va->publicKey;
2759 neighbour->public_key_valid = GNUNET_YES;
2760 peer_address = add_peer_address (neighbour, tname, NULL, addr, addrlen);
2761 GNUNET_assert(peer_address != NULL);
2762 hello_size = GNUNET_HELLO_size(our_hello);
2763 tsize = sizeof(struct TransportPingMessage) + hello_size;
2764 message_buf = GNUNET_malloc(tsize);
2765 ping.challenge = htonl(va->challenge);
2766 ping.header.size = htons(sizeof(struct TransportPingMessage));
2767 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2768 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2769 memcpy(message_buf, our_hello, hello_size);
2770 memcpy(&message_buf[hello_size],
2772 sizeof(struct TransportPingMessage));
2774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2775 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2776 GNUNET_a2s (addr, addrlen),
2779 "HELLO", hello_size,
2780 "PING", sizeof (struct TransportPingMessage));
2782 GNUNET_STATISTICS_update (stats,
2783 gettext_noop ("# PING messages sent for initial validation"),
2786 transmit_to_peer (NULL, peer_address,
2787 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2788 HELLO_VERIFICATION_TIMEOUT,
2790 GNUNET_YES, neighbour);
2791 GNUNET_free(message_buf);
2797 * Check if addresses in validated hello "h" overlap with
2798 * those in "chvc->hello" and validate the rest.
2800 * @param cls closure
2801 * @param peer id of the peer, NULL for last call
2802 * @param h hello message for the peer (can be NULL)
2803 * @param trust amount of trust we have in the peer (not used)
2806 check_hello_validated (void *cls,
2807 const struct GNUNET_PeerIdentity *peer,
2808 const struct GNUNET_HELLO_Message *h,
2811 struct CheckHelloValidatedContext *chvc = cls;
2812 struct GNUNET_HELLO_Message *plain_hello;
2813 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2814 struct GNUNET_PeerIdentity target;
2815 struct NeighbourList *n;
2820 GNUNET_CONTAINER_DLL_remove (chvc_head,
2823 if (GNUNET_NO == chvc->hello_known)
2825 /* notify PEERINFO about the peer now, so that we at least
2826 have the public key if some other component needs it */
2827 GNUNET_HELLO_get_key (chvc->hello, &pk);
2828 GNUNET_CRYPTO_hash (&pk,
2829 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2830 &target.hashPubKey);
2831 plain_hello = GNUNET_HELLO_create (&pk,
2834 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2835 GNUNET_free (plain_hello);
2837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2838 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2840 GNUNET_i2s (&target));
2842 GNUNET_STATISTICS_update (stats,
2843 gettext_noop ("# new HELLOs requiring full validation"),
2846 GNUNET_HELLO_iterate_addresses (chvc->hello,
2853 GNUNET_STATISTICS_update (stats,
2854 gettext_noop ("# duplicate HELLO (peer known)"),
2864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2865 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2869 chvc->hello_known = GNUNET_YES;
2870 n = find_neighbour (peer);
2873 GNUNET_HELLO_iterate_addresses (h,
2875 &add_to_foreign_address_list,
2877 try_transmission_to_peer (n);
2881 GNUNET_STATISTICS_update (stats,
2882 gettext_noop ("# no existing neighbour record (validating HELLO)"),
2886 GNUNET_STATISTICS_update (stats,
2887 gettext_noop ("# HELLO validations (update case)"),
2890 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2892 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2898 * Process HELLO-message.
2900 * @param plugin transport involved, may be NULL
2901 * @param message the actual message
2902 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2905 process_hello (struct TransportPlugin *plugin,
2906 const struct GNUNET_MessageHeader *message)
2909 struct GNUNET_PeerIdentity target;
2910 const struct GNUNET_HELLO_Message *hello;
2911 struct CheckHelloValidatedContext *chvc;
2912 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2914 hsize = ntohs (message->size);
2915 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2916 (hsize < sizeof (struct GNUNET_MessageHeader)))
2919 return GNUNET_SYSERR;
2921 GNUNET_STATISTICS_update (stats,
2922 gettext_noop ("# HELLOs received for validation"),
2925 /* first, check if load is too high */
2926 if (GNUNET_SCHEDULER_get_load (sched,
2927 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2929 GNUNET_STATISTICS_update (stats,
2930 gettext_noop ("# HELLOs ignored due to high load"),
2935 hello = (const struct GNUNET_HELLO_Message *) message;
2936 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2938 GNUNET_break_op (0);
2939 return GNUNET_SYSERR;
2941 GNUNET_CRYPTO_hash (&publicKey,
2942 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2943 &target.hashPubKey);
2944 if (0 == memcmp (&my_identity,
2946 sizeof (struct GNUNET_PeerIdentity)))
2948 GNUNET_STATISTICS_update (stats,
2949 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2954 #if DEBUG_TRANSPORT > 1
2955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2956 "Processing `%s' message for `%4s' of size %u\n",
2958 GNUNET_i2s (&target),
2959 GNUNET_HELLO_size(hello));
2961 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2962 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2963 memcpy (&chvc[1], hello, hsize);
2964 GNUNET_CONTAINER_DLL_insert (chvc_head,
2967 /* finally, check if HELLO was previously validated
2968 (continuation will then schedule actual validation) */
2969 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2973 HELLO_VERIFICATION_TIMEOUT,
2974 &check_hello_validated, chvc);
2980 * The peer specified by the given neighbour has timed-out or a plugin
2981 * has disconnected. We may either need to do nothing (other plugins
2982 * still up), or trigger a full disconnect and clean up. This
2983 * function updates our state and does the necessary notifications.
2984 * Also notifies our clients that the neighbour is now officially
2987 * @param n the neighbour list entry for the peer
2988 * @param check should we just check if all plugins
2989 * disconnected or must we ask all plugins to
2993 disconnect_neighbour (struct NeighbourList *n, int check)
2995 struct ReadyList *rpos;
2996 struct NeighbourList *npos;
2997 struct NeighbourList *nprev;
2998 struct MessageQueue *mq;
2999 struct ForeignAddressList *peer_addresses;
3000 struct ForeignAddressList *peer_pos;
3002 if (GNUNET_YES == check)
3005 while (NULL != rpos)
3007 peer_addresses = rpos->addresses;
3008 while (peer_addresses != NULL)
3010 if (GNUNET_YES == peer_addresses->connected)
3011 return; /* still connected */
3012 peer_addresses = peer_addresses->next;
3018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3019 "Disconnecting from `%4s'\n",
3020 GNUNET_i2s (&n->id));
3022 /* remove n from neighbours list */
3025 while ((npos != NULL) && (npos != n))
3030 GNUNET_assert (npos != NULL);
3032 neighbours = n->next;
3034 nprev->next = n->next;
3036 /* notify all clients about disconnect */
3037 if (GNUNET_YES == n->received_pong)
3038 notify_clients_disconnect (&n->id);
3040 /* clean up all plugins, cancel connections and pending transmissions */
3041 while (NULL != (rpos = n->plugins))
3043 n->plugins = rpos->next;
3044 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3045 while (rpos->addresses != NULL)
3047 peer_pos = rpos->addresses;
3048 rpos->addresses = peer_pos->next;
3049 if (peer_pos->connected == GNUNET_YES)
3050 GNUNET_STATISTICS_update (stats,
3051 gettext_noop ("# connected addresses"),
3054 if (GNUNET_YES == peer_pos->validated)
3055 GNUNET_STATISTICS_update (stats,
3056 gettext_noop ("# peer addresses considered valid"),
3059 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3061 GNUNET_SCHEDULER_cancel (sched,
3062 peer_pos->revalidate_task);
3063 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3065 GNUNET_free(peer_pos);
3070 /* free all messages on the queue */
3071 while (NULL != (mq = n->messages_head))
3073 GNUNET_STATISTICS_update (stats,
3074 gettext_noop ("# bytes in message queue for other peers"),
3075 - (int64_t) mq->message_buf_size,
3077 GNUNET_STATISTICS_update (stats,
3078 gettext_noop ("# bytes discarded due to disconnect"),
3079 mq->message_buf_size,
3081 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3084 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3086 sizeof(struct GNUNET_PeerIdentity)));
3089 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3091 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3092 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3094 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3096 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3097 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3099 if (n->piter != NULL)
3101 GNUNET_PEERINFO_iterate_cancel (n->piter);
3104 /* finally, free n itself */
3105 GNUNET_STATISTICS_update (stats,
3106 gettext_noop ("# active neighbours"),
3114 * We have received a PING message from someone. Need to send a PONG message
3115 * in response to the peer by any means necessary.
3118 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3119 const struct GNUNET_PeerIdentity *peer,
3120 const char *sender_address,
3121 size_t sender_address_len)
3123 struct TransportPlugin *plugin = cls;
3124 struct TransportPingMessage *ping;
3125 struct TransportPongMessage *pong;
3126 struct NeighbourList *n;
3127 struct ReadyList *rl;
3128 struct ForeignAddressList *fal;
3130 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3132 GNUNET_break_op (0);
3133 return GNUNET_SYSERR;
3135 ping = (struct TransportPingMessage *) message;
3136 if (0 != memcmp (&ping->target,
3137 plugin->env.my_identity,
3138 sizeof (struct GNUNET_PeerIdentity)))
3140 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3141 _("Received `%s' message not destined for me!\n"),
3143 return GNUNET_SYSERR;
3146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3147 "Processing `%s' from `%s'\n",
3149 GNUNET_a2s ((const struct sockaddr *)sender_address,
3150 sender_address_len));
3152 GNUNET_STATISTICS_update (stats,
3153 gettext_noop ("# PING messages received"),
3156 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3157 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3158 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3159 pong->purpose.size =
3160 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3162 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3163 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3164 pong->challenge = ping->challenge;
3165 pong->addrlen = htons(sender_address_len);
3166 memcpy(&pong->signer,
3168 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3169 memcpy (&pong[1], sender_address, sender_address_len);
3170 GNUNET_assert (GNUNET_OK ==
3171 GNUNET_CRYPTO_rsa_sign (my_private_key,
3172 &pong->purpose, &pong->signature));
3173 n = find_neighbour(peer);
3174 GNUNET_assert (n != NULL);
3175 /* first try reliable response transmission */
3179 fal = rl->addresses;
3182 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3185 ntohs (pong->header.size),
3186 TRANSPORT_PONG_PRIORITY,
3187 HELLO_VERIFICATION_TIMEOUT,
3195 GNUNET_STATISTICS_update (stats,
3196 gettext_noop ("# PONGs unicast via reliable transport"),
3206 /* no reliable method found, do multicast */
3207 GNUNET_STATISTICS_update (stats,
3208 gettext_noop ("# PONGs multicast to all available addresses"),
3214 fal = rl->addresses;
3217 transmit_to_peer(NULL, fal,
3218 TRANSPORT_PONG_PRIORITY,
3219 HELLO_VERIFICATION_TIMEOUT,
3221 ntohs(pong->header.size),
3234 * Function called by the plugin for each received message.
3235 * Update data volumes, possibly notify plugins about
3236 * reducing the rate at which they read from the socket
3237 * and generally forward to our receive callback.
3239 * @param cls the "struct TransportPlugin *" we gave to the plugin
3240 * @param peer (claimed) identity of the other peer
3241 * @param message the message, NULL if we only care about
3242 * learning about the delay until we should receive again
3243 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3244 * @param session identifier used for this session (can be NULL)
3245 * @param sender_address binary address of the sender (if observed)
3246 * @param sender_address_len number of bytes in sender_address
3247 * @return how long the plugin should wait until receiving more data
3248 * (plugins that do not support this, can ignore the return value)
3250 static struct GNUNET_TIME_Relative
3251 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3252 const struct GNUNET_MessageHeader *message,
3253 unsigned int distance,
3254 struct Session *session,
3255 const char *sender_address,
3256 size_t sender_address_len)
3258 struct TransportPlugin *plugin = cls;
3259 struct ReadyList *service_context;
3260 struct TransportClient *cpos;
3261 struct InboundMessage *im;
3262 struct ForeignAddressList *peer_address;
3264 struct NeighbourList *n;
3265 struct GNUNET_TIME_Relative ret;
3267 n = find_neighbour (peer);
3269 n = setup_new_neighbour (peer);
3270 service_context = n->plugins;
3271 while ((service_context != NULL) && (plugin != service_context->plugin))
3272 service_context = service_context->next;
3273 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3274 peer_address = NULL;
3275 if (message != NULL)
3277 if ( (session != NULL) ||
3278 (sender_address != NULL) )
3279 peer_address = add_peer_address (n,
3283 sender_address_len);
3284 if (peer_address != NULL)
3286 peer_address->distance = distance;
3287 if (GNUNET_YES == peer_address->validated)
3288 mark_address_connected (peer_address);
3289 peer_address->timeout
3291 GNUNET_TIME_relative_to_absolute
3292 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3293 schedule_next_ping (peer_address);
3295 /* update traffic received amount ... */
3296 msize = ntohs (message->size);
3297 GNUNET_STATISTICS_update (stats,
3298 gettext_noop ("# bytes received from other peers"),
3301 n->distance = distance;
3303 GNUNET_TIME_relative_to_absolute
3304 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3305 GNUNET_SCHEDULER_cancel (sched,
3308 GNUNET_SCHEDULER_add_delayed (sched,
3309 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3310 &neighbour_timeout_task, n);
3311 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3313 /* dropping message due to frequent inbound volume violations! */
3314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3315 GNUNET_ERROR_TYPE_BULK,
3317 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
3318 n->in_tracker.available_bytes_per_s__,
3319 n->quota_violation_count);
3320 GNUNET_STATISTICS_update (stats,
3321 gettext_noop ("# bandwidth quota violations by other peers"),
3324 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
3326 switch (ntohs (message->type))
3328 case GNUNET_MESSAGE_TYPE_HELLO:
3329 GNUNET_STATISTICS_update (stats,
3330 gettext_noop ("# HELLO messages received from other peers"),
3333 process_hello (plugin, message);
3335 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3336 handle_ping (plugin, message, peer, sender_address, sender_address_len);
3338 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3339 handle_pong (plugin, message, peer, sender_address, sender_address_len);
3343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3344 "Received message of type %u from `%4s', sending to all clients.\n",
3345 ntohs (message->type), GNUNET_i2s (peer));
3347 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3350 n->quota_violation_count++;
3352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3353 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3354 n->in_tracker.available_bytes_per_s__,
3355 n->quota_violation_count);
3357 /* Discount 32k per violation */
3358 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3363 if (n->quota_violation_count > 0)
3365 /* try to add 32k back */
3366 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3368 n->quota_violation_count--;
3371 GNUNET_STATISTICS_update (stats,
3372 gettext_noop ("# payload received from other peers"),
3375 /* transmit message to all clients */
3376 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3377 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3378 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3379 im->latency = GNUNET_TIME_relative_hton (n->latency);
3381 memcpy (&im[1], message, msize);
3383 while (cpos != NULL)
3385 transmit_to_client (cpos, &im->header, GNUNET_YES);
3391 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3394 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3395 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3396 (unsigned long long) n->in_tracker.consumption_since_last_update__,
3397 (unsigned int) n->in_tracker.available_bytes_per_s__,
3398 (unsigned long long) ret.value);
3399 GNUNET_STATISTICS_update (stats,
3400 gettext_noop ("# ms throttling suggested"),
3401 (int64_t) ret.value,
3409 * Handle START-message. This is the first message sent to us
3410 * by any client which causes us to add it to our list.
3412 * @param cls closure (always NULL)
3413 * @param client identification of the client
3414 * @param message the actual message
3417 handle_start (void *cls,
3418 struct GNUNET_SERVER_Client *client,
3419 const struct GNUNET_MessageHeader *message)
3421 struct TransportClient *c;
3422 struct ConnectInfoMessage cim;
3423 struct NeighbourList *n;
3426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3427 "Received `%s' request from client\n", "START");
3432 if (c->client == client)
3434 /* client already on our list! */
3436 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3441 c = GNUNET_malloc (sizeof (struct TransportClient));
3445 if (our_hello != NULL)
3448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3449 "Sending our own `%s' to new client\n", "HELLO");
3451 transmit_to_client (c,
3452 (const struct GNUNET_MessageHeader *) our_hello,
3454 /* tell new client about all existing connections */
3455 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3456 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3460 if (GNUNET_YES == n->received_pong)
3463 cim.latency = GNUNET_TIME_relative_hton (n->latency);
3464 cim.distance = htonl (n->distance);
3465 transmit_to_client (c, &cim.header, GNUNET_NO);
3470 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3475 * Handle HELLO-message.
3477 * @param cls closure (always NULL)
3478 * @param client identification of the client
3479 * @param message the actual message
3482 handle_hello (void *cls,
3483 struct GNUNET_SERVER_Client *client,
3484 const struct GNUNET_MessageHeader *message)
3488 GNUNET_STATISTICS_update (stats,
3489 gettext_noop ("# HELLOs received from clients"),
3492 ret = process_hello (NULL, message);
3493 GNUNET_SERVER_receive_done (client, ret);
3498 * Handle SEND-message.
3500 * @param cls closure (always NULL)
3501 * @param client identification of the client
3502 * @param message the actual message
3505 handle_send (void *cls,
3506 struct GNUNET_SERVER_Client *client,
3507 const struct GNUNET_MessageHeader *message)
3509 struct TransportClient *tc;
3510 struct NeighbourList *n;
3511 const struct OutboundMessage *obm;
3512 const struct GNUNET_MessageHeader *obmm;
3516 size = ntohs (message->size);
3518 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3521 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3524 GNUNET_STATISTICS_update (stats,
3525 gettext_noop ("# payload received for other peers"),
3528 obm = (const struct OutboundMessage *) message;
3530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3531 "Received `%s' request from client with target `%4s'\n",
3532 "SEND", GNUNET_i2s (&obm->peer));
3534 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3535 msize = ntohs (obmm->size);
3536 if (size != msize + sizeof (struct OutboundMessage))
3539 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3542 n = find_neighbour (&obm->peer);
3544 n = setup_new_neighbour (&obm->peer);
3546 while ((tc != NULL) && (tc->client != client))
3550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3551 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3553 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3555 transmit_to_peer (tc, NULL, ntohl (obm->priority),
3556 GNUNET_TIME_relative_ntoh (obm->timeout),
3558 ntohs (obmm->size), GNUNET_NO, n);
3559 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3564 * Handle SET_QUOTA-message.
3566 * @param cls closure (always NULL)
3567 * @param client identification of the client
3568 * @param message the actual message
3571 handle_set_quota (void *cls,
3572 struct GNUNET_SERVER_Client *client,
3573 const struct GNUNET_MessageHeader *message)
3575 const struct QuotaSetMessage *qsm =
3576 (const struct QuotaSetMessage *) message;
3577 struct NeighbourList *n;
3579 GNUNET_STATISTICS_update (stats,
3580 gettext_noop ("# SET QUOTA messages received"),
3583 n = find_neighbour (&qsm->peer);
3586 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3587 GNUNET_STATISTICS_update (stats,
3588 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3595 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3597 (unsigned int) ntohl (qsm->quota.value__),
3598 (unsigned int) n->in_tracker.available_bytes_per_s__,
3599 GNUNET_i2s (&qsm->peer));
3601 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3603 if (0 == ntohl (qsm->quota.value__))
3604 disconnect_neighbour (n, GNUNET_NO);
3605 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3610 * Take the given address and append it to the set of results send back to
3613 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3614 * @param address the resolved name, NULL to indicate the last response
3617 transmit_address_to_client (void *cls, const char *address)
3619 struct GNUNET_SERVER_TransmitContext *tc = cls;
3622 if (NULL == address)
3625 slen = strlen (address) + 1;
3626 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3627 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3628 if (NULL == address)
3629 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3634 * Handle AddressLookup-message.
3636 * @param cls closure (always NULL)
3637 * @param client identification of the client
3638 * @param message the actual message
3641 handle_address_lookup (void *cls,
3642 struct GNUNET_SERVER_Client *client,
3643 const struct GNUNET_MessageHeader *message)
3645 const struct AddressLookupMessage *alum;
3646 struct TransportPlugin *lsPlugin;
3647 const char *nameTransport;
3648 const char *address;
3650 struct GNUNET_SERVER_TransmitContext *tc;
3651 struct GNUNET_TIME_Absolute timeout;
3652 struct GNUNET_TIME_Relative rtimeout;
3655 size = ntohs (message->size);
3656 if (size < sizeof (struct AddressLookupMessage))
3658 GNUNET_break_op (0);
3659 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3662 alum = (const struct AddressLookupMessage *) message;
3663 uint32_t addressLen = ntohl (alum->addrlen);
3664 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3666 GNUNET_break_op (0);
3667 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3670 address = (const char *) &alum[1];
3671 nameTransport = (const char *) &address[addressLen];
3673 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3675 GNUNET_break_op (0);
3676 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3679 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
3680 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
3681 numeric = ntohl (alum->numeric_only);
3682 lsPlugin = find_transport (nameTransport);
3683 if (NULL == lsPlugin)
3685 tc = GNUNET_SERVER_transmit_context_create (client);
3686 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3687 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3688 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3691 tc = GNUNET_SERVER_transmit_context_create (client);
3692 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
3694 address, addressLen,
3697 &transmit_address_to_client, tc);
3701 * List of handlers for the messages understood by this
3704 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3705 {&handle_start, NULL,
3706 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3707 {&handle_hello, NULL,
3708 GNUNET_MESSAGE_TYPE_HELLO, 0},
3709 {&handle_send, NULL,
3710 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3711 {&handle_set_quota, NULL,
3712 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3713 {&handle_address_lookup, NULL,
3714 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3721 * Setup the environment for this plugin.
3724 create_environment (struct TransportPlugin *plug)
3726 plug->env.cfg = cfg;
3727 plug->env.sched = sched;
3728 plug->env.my_identity = &my_identity;
3729 plug->env.cls = plug;
3730 plug->env.receive = &plugin_env_receive;
3731 plug->env.notify_address = &plugin_env_notify_address;
3732 plug->env.session_end = &plugin_env_session_end;
3733 plug->env.max_connections = max_connect_per_transport;
3734 plug->env.stats = stats;
3739 * Start the specified transport (load the plugin).
3742 start_transport (struct GNUNET_SERVER_Handle *server,
3745 struct TransportPlugin *plug;
3748 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3749 _("Loading `%s' transport plugin\n"), name);
3750 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3751 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3752 create_environment (plug);
3753 plug->short_name = GNUNET_strdup (name);
3754 plug->lib_name = libname;
3755 plug->next = plugins;
3757 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3758 if (plug->api == NULL)
3760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3761 _("Failed to load transport plugin for `%s'\n"), name);
3762 GNUNET_free (plug->short_name);
3763 plugins = plug->next;
3764 GNUNET_free (libname);
3771 * Called whenever a client is disconnected. Frees our
3772 * resources associated with that client.
3774 * @param cls closure
3775 * @param client identification of the client
3778 client_disconnect_notification (void *cls,
3779 struct GNUNET_SERVER_Client *client)
3781 struct TransportClient *pos;
3782 struct TransportClient *prev;
3783 struct ClientMessageQueueEntry *mqe;
3788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3789 "Client disconnected, cleaning up.\n");
3793 while ((pos != NULL) && (pos->client != client))
3800 while (NULL != (mqe = pos->message_queue_head))
3802 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3803 pos->message_queue_tail,
3805 pos->message_count--;
3809 clients = pos->next;
3811 prev->next = pos->next;
3812 if (GNUNET_YES == pos->tcs_pending)
3817 if (pos->th != NULL)
3819 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3822 GNUNET_break (0 == pos->message_count);
3828 * Iterator to free entries in the validation_map.
3830 * @param cls closure (unused)
3831 * @param key current key code
3832 * @param value value in the hash map (validation to abort)
3833 * @return GNUNET_YES (always)
3836 abort_validation (void *cls,
3837 const GNUNET_HashCode * key,
3840 struct ValidationEntry *va = value;
3842 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3843 GNUNET_free (va->transport_name);
3850 * Function called when the service shuts down. Unloads our plugins
3851 * and cancels pending validations.
3853 * @param cls closure, unused
3854 * @param tc task context (unused)
3857 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3859 struct TransportPlugin *plug;
3860 struct OwnAddressList *al;
3861 struct CheckHelloValidatedContext *chvc;
3863 while (neighbours != NULL)
3864 disconnect_neighbour (neighbours, GNUNET_NO);
3866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3867 "Transport service is unloading plugins...\n");
3869 while (NULL != (plug = plugins))
3871 plugins = plug->next;
3872 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
3874 GNUNET_SCHEDULER_cancel (plug->env.sched,
3875 plug->address_update_task);
3876 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
3878 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3879 GNUNET_free (plug->lib_name);
3880 GNUNET_free (plug->short_name);
3881 while (NULL != (al = plug->addresses))
3883 plug->addresses = al->next;
3888 if (my_private_key != NULL)
3889 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3890 GNUNET_free_non_null (our_hello);
3892 /* free 'chvc' data structure */
3893 while (NULL != (chvc = chvc_head))
3895 chvc_head = chvc->next;
3896 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3901 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3904 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3905 validation_map = NULL;
3908 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3915 * Initiate transport service.
3917 * @param cls closure
3918 * @param s scheduler to use
3919 * @param serv the initialized server
3920 * @param c configuration to use
3924 struct GNUNET_SCHEDULER_Handle *s,
3925 struct GNUNET_SERVER_Handle *serv,
3926 const struct GNUNET_CONFIGURATION_Handle *c)
3931 unsigned long long tneigh;
3936 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3937 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3938 /* parse configuration */
3940 GNUNET_CONFIGURATION_get_value_number (c,
3945 GNUNET_CONFIGURATION_get_value_filename (c,
3947 "HOSTKEY", &keyfile)))
3949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3951 ("Transport service is lacking key configuration settings. Exiting.\n"));
3952 GNUNET_SCHEDULER_shutdown (s);
3955 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3958 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3959 validation_map = NULL;
3962 max_connect_per_transport = (uint32_t) tneigh;
3963 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3964 GNUNET_free (keyfile);
3965 if (my_private_key == NULL)
3967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3969 ("Transport service could not access hostkey. Exiting.\n"));
3970 GNUNET_SCHEDULER_shutdown (s);
3973 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3976 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3977 validation_map = NULL;
3980 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3981 GNUNET_CRYPTO_hash (&my_public_key,
3982 sizeof (my_public_key), &my_identity.hashPubKey);
3983 /* setup notification */
3985 GNUNET_SERVER_disconnect_notify (server,
3986 &client_disconnect_notification, NULL);
3987 /* load plugins... */
3990 GNUNET_CONFIGURATION_get_value_string (c,
3991 "TRANSPORT", "PLUGINS", &plugs))
3993 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3994 _("Starting transport plugins `%s'\n"), plugs);
3995 pos = strtok (plugs, " ");
3998 start_transport (server, pos);
4000 pos = strtok (NULL, " ");
4002 GNUNET_free (plugs);
4004 GNUNET_SCHEDULER_add_delayed (sched,
4005 GNUNET_TIME_UNIT_FOREVER_REL,
4006 &shutdown_task, NULL);
4011 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4013 /* process client requests */
4014 GNUNET_SERVER_add_handlers (server, handlers);
4019 * The main function for the transport service.
4021 * @param argc number of arguments from the command line
4022 * @param argv command line arguments
4023 * @return 0 ok, 1 on error
4026 main (int argc, char *const *argv)
4028 return (GNUNET_OK ==
4029 GNUNET_SERVICE_run (argc,
4032 GNUNET_SERVICE_OPTION_NONE,
4033 &run, NULL)) ? 0 : 1;
4036 /* end of gnunet-service-transport.c */