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 validate *inbound* bi-directional transports (i.e., TCP)
28 * using PING-PONG and then SIGNAL 'connected' to core/etc.!
29 * (currently we neither validate those nor do we signal the
30 * connection); only after those, we should transmit data
31 * (we currently send and receive arbitrary data on inbound TCP
32 * connections even if they have not been validated and hand it
36 * - This code uses 'GNUNET_a2s' for debug printing in many places,
37 * which is technically wrong since it assumes we have IP+Port
38 * (v4/v6) addresses. Once we add transports like http or smtp
39 * this will have to be changed!
42 #include "gnunet_client_lib.h"
43 #include "gnunet_container_lib.h"
44 #include "gnunet_constants.h"
45 #include "gnunet_getopt_lib.h"
46 #include "gnunet_hello_lib.h"
47 #include "gnunet_os_lib.h"
48 #include "gnunet_peerinfo_service.h"
49 #include "gnunet_plugin_lib.h"
50 #include "gnunet_protocols.h"
51 #include "gnunet_service_lib.h"
52 #include "gnunet_signatures.h"
53 #include "plugin_transport.h"
54 #include "transport.h"
57 * Should we do some additional checks (to validate behavior
60 #define EXTRA_CHECKS GNUNET_YES
63 * How many messages can we have pending for a given client process
64 * before we start to drop incoming messages? We typically should
65 * have only one client and so this would be the primary buffer for
66 * messages, so the number should be chosen rather generously.
68 * The expectation here is that most of the time the queue is large
69 * enough so that a drop is virtually never required.
71 #define MAX_PENDING 128
74 * How often should we try to reconnect to a peer using a particular
75 * transport plugin before giving up? Note that the plugin may be
76 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
78 #define MAX_CONNECT_RETRY 3
81 * Limit on the number of ready-to-run tasks when validating
82 * HELLOs. If more tasks are ready to run, we will drop
83 * HELLOs instead of validating them.
85 #define MAX_HELLO_LOAD 4
88 * How often must a peer violate bandwidth quotas before we start
89 * to simply drop its messages?
91 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
94 * How long until a HELLO verification attempt should time out?
95 * Must be rather small, otherwise a partially successful HELLO
96 * validation (some addresses working) might not be available
97 * before a client's request for a connection fails for good.
98 * Besides, if a single request to an address takes a long time,
99 * then the peer is unlikely worthwhile anyway.
101 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
104 * Priority to use for PONG messages.
106 #define TRANSPORT_PONG_PRIORITY 4
109 * How often do we re-add (cheaper) plugins to our list of plugins
110 * to try for a given connected peer?
112 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
115 * After how long do we expire an address in a HELLO that we just
116 * validated? This value is also used for our own addresses when we
119 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
123 * How long before an existing address expires should we again try to
124 * validate it? Must be (significantly) smaller than
125 * HELLO_ADDRESS_EXPIRATION.
127 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
130 * Maximum frequency for re-evaluating latencies for all transport addresses.
132 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
135 * Maximum frequency for re-evaluating latencies for connected addresses.
137 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
141 * List of addresses of other peers
143 struct ForeignAddressList
146 * This is a linked list.
148 struct ForeignAddressList *next;
151 * Which ready list does this entry belong to.
153 struct ReadyList *ready_list;
156 * How long until we auto-expire this address (unless it is
157 * re-confirmed by the transport)?
159 struct GNUNET_TIME_Absolute expires;
162 * Task used to re-validate addresses, updates latencies and
165 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
178 * Session (or NULL if no valid session currently exists or if the
179 * plugin does not use sessions).
181 struct Session *session;
184 * What was the last latency observed for this address, plugin and peer?
186 struct GNUNET_TIME_Relative latency;
189 * If we did not successfully transmit a message to the given peer
190 * via this connection during the specified time, we should consider
191 * the connection to be dead. This is used in the case that a TCP
192 * transport simply stalls writing to the stream but does not
193 * formerly get a signal that the other peer died.
195 struct GNUNET_TIME_Absolute timeout;
198 * How often have we tried to connect using this plugin? Used to
199 * discriminate against addresses that do not work well.
200 * FIXME: not yet used, but should be!
202 unsigned int connect_attempts;
205 * DV distance to this peer (1 if no DV is used).
206 * FIXME: need to set this from transport plugins!
211 * Have we ever estimated the latency of this address? Used to
212 * ensure that the first time we add an address, we immediately
218 * Are we currently connected via this address? The first time we
219 * successfully transmit or receive data to a peer via a particular
220 * address, we set this to GNUNET_YES. If we later get an error
221 * (disconnect notification, transmission failure, timeout), we set
222 * it back to GNUNET_NO.
227 * Is this plugin currently busy transmitting to the specific target?
228 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
229 * messages do not count as 'in transmit'.
234 * Has this address been validated yet?
242 * Entry in linked list of network addresses for ourselves.
244 struct OwnAddressList
247 * This is a linked list.
249 struct OwnAddressList *next;
252 * The address, actually a pointer to the end
253 * of this struct. Do not free!
258 * How long until we auto-expire this address (unless it is
259 * re-confirmed by the transport)?
261 struct GNUNET_TIME_Absolute expires;
272 * Entry in linked list of all of our plugins.
274 struct TransportPlugin
278 * This is a linked list.
280 struct TransportPlugin *next;
283 * API of the transport as returned by the plugin's
284 * initialization function.
286 struct GNUNET_TRANSPORT_PluginFunctions *api;
289 * Short name for the plugin (i.e. "tcp").
294 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
299 * List of our known addresses for this transport.
301 struct OwnAddressList *addresses;
304 * Environment this transport service is using
307 struct GNUNET_TRANSPORT_PluginEnvironment env;
310 * ID of task that is used to clean up expired addresses.
312 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
315 * Set to GNUNET_YES if we need to scrap the existing list of
316 * "addresses" and start fresh when we receive the next address
317 * update from a transport. Set to GNUNET_NO if we should just add
318 * the new address to the list and wait for the commit call.
324 struct NeighbourList;
327 * For each neighbour we keep a list of messages
328 * that we still want to transmit to the neighbour.
334 * This is a doubly linked list.
336 struct MessageQueue *next;
339 * This is a doubly linked list.
341 struct MessageQueue *prev;
344 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
345 * stuck together in memory. Allocated at the end of this struct.
347 const char *message_buf;
350 * Size of the message buf
352 size_t message_buf_size;
355 * Client responsible for queueing the message;
356 * used to check that a client has no two messages
357 * pending for the same target. Can be NULL.
359 struct TransportClient *client;
362 * Using which specific address should we send this message?
364 struct ForeignAddressList *specific_address;
367 * Peer ID of the Neighbour this entry belongs to.
369 struct GNUNET_PeerIdentity neighbour_id;
372 * Plugin that we used for the transmission.
373 * NULL until we scheduled a transmission.
375 struct TransportPlugin *plugin;
378 * At what time should we fail?
380 struct GNUNET_TIME_Absolute timeout;
383 * Internal message of the transport system that should not be
384 * included in the usual SEND-SEND_OK transmission confirmation
385 * traffic management scheme. Typically, "internal_msg" will
386 * be set whenever "client" is NULL (but it is not strictly
392 * How important is the message?
394 unsigned int priority;
400 * For a given Neighbour, which plugins are available
401 * to talk to this peer and what are their costs?
406 * This is a linked list.
408 struct ReadyList *next;
411 * Which of our transport plugins does this entry
414 struct TransportPlugin *plugin;
417 * Transport addresses, latency, and readiness for
418 * this particular plugin.
420 struct ForeignAddressList *addresses;
423 * To which neighbour does this ready list belong to?
425 struct NeighbourList *neighbour;
431 * Entry in linked list of all of our current neighbours.
437 * This is a linked list.
439 struct NeighbourList *next;
442 * Which of our transports is connected to this peer
443 * and what is their status?
445 struct ReadyList *plugins;
448 * Head of list of messages we would like to send to this peer;
449 * must contain at most one message per client.
451 struct MessageQueue *messages_head;
454 * Tail of list of messages we would like to send to this peer; must
455 * contain at most one message per client.
457 struct MessageQueue *messages_tail;
460 * Context for peerinfo iteration.
461 * NULL after we are done processing peerinfo's information.
463 struct GNUNET_PEERINFO_IteratorContext *piter;
466 * Public key for this peer. Valid only if the respective flag is set below.
468 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
471 * Identity of this neighbour.
473 struct GNUNET_PeerIdentity id;
476 * ID of task scheduled to run when this peer is about to
477 * time out (will free resources associated with the peer).
479 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
482 * ID of task scheduled to run when we should retry transmitting
483 * the head of the message queue. Actually triggered when the
484 * transmission is timing out (we trigger instantly when we have
485 * a chance of success).
487 GNUNET_SCHEDULER_TaskIdentifier retry_task;
490 * How long until we should consider this peer dead
491 * (if we don't receive another message in the
494 struct GNUNET_TIME_Absolute peer_timeout;
497 * Tracker for inbound bandwidth.
499 struct GNUNET_BANDWIDTH_Tracker in_tracker;
502 * The latency we have seen for this particular address for
503 * this particular peer. This latency may have been calculated
504 * over multiple transports. This value reflects how long it took
505 * us to receive a response when SENDING via this particular
506 * transport/neighbour/address combination!
508 * FIXME: we need to periodically send PINGs to update this
509 * latency (at least more often than the current "huge" (11h?)
512 struct GNUNET_TIME_Relative latency;
515 * How often has the other peer (recently) violated the
516 * inbound traffic limit? Incremented by 10 per violation,
517 * decremented by 1 per non-violation (for each
520 unsigned int quota_violation_count;
523 * DV distance to this peer (1 if no DV is used).
528 * Have we seen an PONG from this neighbour in the past (and
529 * not had a disconnect since)?
534 * Do we have a valid public key for this neighbour?
536 int public_key_valid;
541 * Message used to ask a peer to validate receipt (to check an address
544 struct TransportPingMessage
548 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
550 struct GNUNET_MessageHeader header;
553 * Random challenge number (in network byte order).
555 uint32_t challenge GNUNET_PACKED;
558 * Who is the intended recipient?
560 struct GNUNET_PeerIdentity target;
566 * Message used to validate a HELLO. The challenge is included in the
567 * confirmation to make matching of replies to requests possible. The
568 * signature signs the original challenge number, our public key, the
569 * sender's address (so that the sender can check that the address we
570 * saw is plausible for him and possibly detect a MiM attack) and a
571 * timestamp (to limit replay).<p>
573 * This message is followed by the address of the
574 * client that we are observing (which is part of what
577 struct TransportPongMessage
581 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
583 struct GNUNET_MessageHeader header;
586 * For padding, always zero.
588 uint32_t reserved GNUNET_PACKED;
593 struct GNUNET_CRYPTO_RsaSignature signature;
596 * What are we signing and why?
598 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
601 * Random challenge number (in network byte order).
603 uint32_t challenge GNUNET_PACKED;
606 * Who signed this message?
608 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
611 * Size of address appended to this message
619 * Linked list of messages to be transmitted to the client. Each
620 * entry is followed by the actual message.
622 struct ClientMessageQueueEntry
625 * This is a doubly-linked list.
627 struct ClientMessageQueueEntry *next;
630 * This is a doubly-linked list.
632 struct ClientMessageQueueEntry *prev;
637 * Client connected to the transport service.
639 struct TransportClient
643 * This is a linked list.
645 struct TransportClient *next;
648 * Handle to the client.
650 struct GNUNET_SERVER_Client *client;
653 * Linked list of messages yet to be transmitted to
656 struct ClientMessageQueueEntry *message_queue_head;
659 * Tail of linked list of messages yet to be transmitted to the
662 struct ClientMessageQueueEntry *message_queue_tail;
665 * Current transmit request handle.
667 struct GNUNET_CONNECTION_TransmitHandle *th;
670 * Is a call to "transmit_send_continuation" pending? If so, we
671 * must not free this struct (even if the corresponding client
672 * disconnects) and instead only remove it from the linked list and
673 * set the "client" field to NULL.
678 * Length of the list of messages pending for this client.
680 unsigned int message_count;
686 * Entry in map of all HELLOs awaiting validation.
688 struct ValidationEntry
692 * The address, actually a pointer to the end
693 * of this struct. Do not free!
698 * Name of the transport.
700 char *transport_name;
703 * The public key of the peer.
705 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
708 * ID of task that will clean up this entry if we don't succeed
709 * with the validation first.
711 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
714 * At what time did we send this validation?
716 struct GNUNET_TIME_Absolute send_time;
724 * Challenge number we used.
732 * Context of currently active requests to peerinfo
733 * for validation of HELLOs.
735 struct CheckHelloValidatedContext
739 * This is a doubly-linked list.
741 struct CheckHelloValidatedContext *next;
744 * This is a doubly-linked list.
746 struct CheckHelloValidatedContext *prev;
749 * Hello that we are validating.
751 const struct GNUNET_HELLO_Message *hello;
754 * Context for peerinfo iteration.
755 * NULL after we are done processing peerinfo's information.
757 struct GNUNET_PEERINFO_IteratorContext *piter;
760 * Was a HELLO known for this peer to peerinfo?
770 static struct GNUNET_HELLO_Message *our_hello;
773 * "version" of "our_hello". Used to see if a given neighbour has
774 * already been sent the latest version of our HELLO message.
776 static unsigned int our_hello_version;
781 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
786 static struct GNUNET_PeerIdentity my_identity;
791 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
796 struct GNUNET_SCHEDULER_Handle *sched;
801 const struct GNUNET_CONFIGURATION_Handle *cfg;
804 * Linked list of all clients to this service.
806 static struct TransportClient *clients;
809 * All loaded plugins.
811 static struct TransportPlugin *plugins;
816 static struct GNUNET_SERVER_Handle *server;
819 * All known neighbours and their HELLOs.
821 static struct NeighbourList *neighbours;
824 * Number of neighbours we'd like to have.
826 static uint32_t max_connect_per_transport;
829 * Head of linked list.
831 static struct CheckHelloValidatedContext *chvc_head;
834 * Tail of linked list.
836 static struct CheckHelloValidatedContext *chvc_tail;
839 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
840 * of the given peer that we are currently validating).
842 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
845 * Handle for reporting statistics.
847 static struct GNUNET_STATISTICS_Handle *stats;
851 * The peer specified by the given neighbour has timed-out or a plugin
852 * has disconnected. We may either need to do nothing (other plugins
853 * still up), or trigger a full disconnect and clean up. This
854 * function updates our state and do the necessary notifications.
855 * Also notifies our clients that the neighbour is now officially
858 * @param n the neighbour list entry for the peer
859 * @param check should we just check if all plugins
860 * disconnected or must we ask all plugins to
863 static void disconnect_neighbour (struct NeighbourList *n, int check);
866 * Check the ready list for the given neighbour and if a plugin is
867 * ready for transmission (and if we have a message), do so!
869 * @param neighbour target peer for which to transmit
871 static void try_transmission_to_peer (struct NeighbourList *neighbour);
875 * Find an entry in the neighbour list for a particular peer.
877 * @return NULL if not found.
879 static struct NeighbourList *
880 find_neighbour (const struct GNUNET_PeerIdentity *key)
882 struct NeighbourList *head = neighbours;
884 while ((head != NULL) &&
885 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
892 * Find an entry in the transport list for a particular transport.
894 * @return NULL if not found.
896 static struct TransportPlugin *
897 find_transport (const char *short_name)
899 struct TransportPlugin *head = plugins;
900 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
907 * Function called to notify a client about the socket being ready to
908 * queue more data. "buf" will be NULL and "size" zero if the socket
909 * was closed for writing in the meantime.
912 * @param size number of bytes available in buf
913 * @param buf where the callee should write the message
914 * @return number of bytes written to buf
917 transmit_to_client_callback (void *cls, size_t size, void *buf)
919 struct TransportClient *client = cls;
920 struct ClientMessageQueueEntry *q;
923 const struct GNUNET_MessageHeader *msg;
929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
930 "Transmission to client failed, closing connection.\n");
931 /* fatal error with client, free message queue! */
932 while (NULL != (q = client->message_queue_head))
934 GNUNET_STATISTICS_update (stats,
935 gettext_noop ("# bytes discarded (could not transmit to client)"),
936 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
938 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
939 client->message_queue_tail,
943 client->message_count = 0;
948 while (NULL != (q = client->message_queue_head))
950 msg = (const struct GNUNET_MessageHeader *) &q[1];
951 msize = ntohs (msg->size);
952 if (msize + tsize > size)
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956 "Transmitting message of type %u to client.\n",
959 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
960 client->message_queue_tail,
962 memcpy (&cbuf[tsize], msg, msize);
965 client->message_count--;
969 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
970 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
972 GNUNET_TIME_UNIT_FOREVER_REL,
973 &transmit_to_client_callback,
975 GNUNET_assert (client->th != NULL);
982 * Send the specified message to the specified client. Since multiple
983 * messages may be pending for the same client at a time, this code
984 * makes sure that no message is lost.
986 * @param client client to transmit the message to
987 * @param msg the message to send
988 * @param may_drop can this message be dropped if the
989 * message queue for this client is getting far too large?
992 transmit_to_client (struct TransportClient *client,
993 const struct GNUNET_MessageHeader *msg, int may_drop)
995 struct ClientMessageQueueEntry *q;
998 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1000 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1002 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1003 client->message_count, MAX_PENDING);
1004 /* TODO: call to statistics... */
1007 msize = ntohs (msg->size);
1008 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1009 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1010 memcpy (&q[1], msg, msize);
1011 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1012 client->message_queue_tail,
1013 client->message_queue_tail,
1015 client->message_count++;
1016 if (client->th == NULL)
1018 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1020 GNUNET_TIME_UNIT_FOREVER_REL,
1021 &transmit_to_client_callback,
1023 GNUNET_assert (client->th != NULL);
1029 * Transmit a 'SEND_OK' notification to the given client for the
1032 * @param client who to notify
1033 * @param n neighbour to notify about
1034 * @param result status code for the transmission request
1037 transmit_send_ok (struct TransportClient *client,
1038 struct NeighbourList *n,
1041 struct SendOkMessage send_ok_msg;
1043 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1044 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1045 send_ok_msg.success = htonl (result);
1046 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1047 send_ok_msg.peer = n->id;
1048 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1053 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1054 * upon "completion" of a send request. This tells the API
1055 * that it is now legal to send another message to the given
1058 * @param cls closure, identifies the entry on the
1059 * message queue that was transmitted and the
1060 * client responsible for queueing the message
1061 * @param target the peer receiving the message
1062 * @param result GNUNET_OK on success, if the transmission
1063 * failed, we should not tell the client to transmit
1067 transmit_send_continuation (void *cls,
1068 const struct GNUNET_PeerIdentity *target,
1071 struct MessageQueue *mq = cls;
1072 struct NeighbourList *n;
1074 GNUNET_STATISTICS_update (stats,
1075 gettext_noop ("# bytes pending with plugins"),
1076 - (int64_t) mq->message_buf_size,
1078 if (result == GNUNET_OK)
1080 GNUNET_STATISTICS_update (stats,
1081 gettext_noop ("# bytes successfully transmitted by plugins"),
1082 mq->message_buf_size,
1087 GNUNET_STATISTICS_update (stats,
1088 gettext_noop ("# bytes with transmission failure by plugins"),
1089 mq->message_buf_size,
1092 n = find_neighbour(&mq->neighbour_id);
1093 GNUNET_assert (n != NULL);
1094 if (mq->specific_address != NULL)
1096 if (result == GNUNET_OK)
1098 mq->specific_address->timeout =
1099 GNUNET_TIME_relative_to_absolute
1100 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1101 if (mq->specific_address->connected != GNUNET_YES)
1103 GNUNET_STATISTICS_update (stats,
1104 gettext_noop ("# connected addresses"),
1107 mq->specific_address->connected = GNUNET_YES;
1112 if (mq->specific_address->connected != GNUNET_NO)
1114 GNUNET_STATISTICS_update (stats,
1115 gettext_noop ("# connected addresses"),
1118 mq->specific_address->connected = GNUNET_NO;
1121 if (! mq->internal_msg)
1122 mq->specific_address->in_transmit = GNUNET_NO;
1124 if (mq->client != NULL)
1125 transmit_send_ok (mq->client, n, result);
1127 try_transmission_to_peer (n);
1132 * Find an address in any of the available transports for
1133 * the given neighbour that would be good for message
1134 * transmission. This is essentially the transport selection
1137 * @param neighbour for whom to select an address
1138 * @return selected address, NULL if we have none
1140 struct ForeignAddressList *
1141 find_ready_address(struct NeighbourList *neighbour)
1143 struct ReadyList *head = neighbour->plugins;
1144 struct ForeignAddressList *addresses;
1145 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1146 struct ForeignAddressList *best_address;
1148 best_address = NULL;
1149 while (head != NULL)
1151 addresses = head->addresses;
1152 while (addresses != NULL)
1154 if ( (addresses->timeout.value < now.value) &&
1155 (addresses->connected == GNUNET_YES) )
1158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1159 "Marking long-time inactive connection to `%4s' as down.\n",
1160 GNUNET_i2s (&neighbour->id));
1162 GNUNET_STATISTICS_update (stats,
1163 gettext_noop ("# connected addresses"),
1166 addresses->connected = GNUNET_NO;
1168 addresses = addresses->next;
1171 addresses = head->addresses;
1172 while (addresses != NULL)
1174 #if DEBUG_TRANSPORT > 1
1175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1176 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1177 GNUNET_a2s (addresses->addr,
1178 addresses->addrlen),
1179 GNUNET_i2s (&neighbour->id),
1180 addresses->connected,
1181 addresses->in_transmit,
1182 addresses->validated,
1183 addresses->connect_attempts,
1184 (unsigned long long) addresses->timeout.value,
1185 (unsigned int) addresses->distance);
1187 if ( ( (best_address == NULL) ||
1188 (addresses->connected == GNUNET_YES) ||
1189 (best_address->connected == GNUNET_NO) ) &&
1190 (addresses->in_transmit == GNUNET_NO) &&
1191 ( (best_address == NULL) ||
1192 (addresses->latency.value < best_address->latency.value)) )
1193 best_address = addresses;
1194 /* FIXME: also give lower-latency addresses that are not
1195 connected a chance some times... */
1196 addresses = addresses->next;
1200 if (best_address != NULL)
1203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1204 "Best address found has latency of %llu ms.\n",
1205 best_address->latency.value);
1210 GNUNET_STATISTICS_update (stats,
1211 gettext_noop ("# transmission attempts failed (no address)"),
1215 return best_address;
1221 * We should re-try transmitting to the given peer,
1222 * hopefully we've learned something in the meantime.
1225 retry_transmission_task (void *cls,
1226 const struct GNUNET_SCHEDULER_TaskContext *tc)
1228 struct NeighbourList *n = cls;
1230 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1231 try_transmission_to_peer (n);
1236 * Check the ready list for the given neighbour and if a plugin is
1237 * ready for transmission (and if we have a message), do so!
1239 * @param neighbour target peer for which to transmit
1242 try_transmission_to_peer (struct NeighbourList *neighbour)
1244 struct ReadyList *rl;
1245 struct MessageQueue *mq;
1246 struct GNUNET_TIME_Relative timeout;
1250 if (neighbour->messages_head == NULL)
1253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1254 "Transmission queue for `%4s' is empty\n",
1255 GNUNET_i2s (&neighbour->id));
1257 return; /* nothing to do */
1260 mq = neighbour->messages_head;
1261 force_address = GNUNET_YES;
1262 if (mq->specific_address == NULL)
1264 mq->specific_address = find_ready_address(neighbour);
1265 GNUNET_STATISTICS_update (stats,
1266 gettext_noop ("# transport selected peer address freely"),
1269 force_address = GNUNET_NO;
1271 if (mq->specific_address == NULL)
1273 GNUNET_STATISTICS_update (stats,
1274 gettext_noop ("# transport failed to selected peer address"),
1277 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1278 if (timeout.value == 0)
1281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1282 "No destination address available to transmit message of size %u to peer `%4s'\n",
1283 mq->message_buf_size,
1284 GNUNET_i2s (&mq->neighbour_id));
1286 GNUNET_STATISTICS_update (stats,
1287 gettext_noop ("# bytes in message queue for other peers"),
1288 - (int64_t) mq->message_buf_size,
1290 GNUNET_STATISTICS_update (stats,
1291 gettext_noop ("# bytes discarded (no destination address available)"),
1292 mq->message_buf_size,
1294 if (mq->client != NULL)
1295 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1296 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1297 neighbour->messages_tail,
1300 return; /* nobody ready */
1302 GNUNET_STATISTICS_update (stats,
1303 gettext_noop ("# message delivery deferred (no address)"),
1306 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1307 GNUNET_SCHEDULER_cancel (sched,
1308 neighbour->retry_task);
1309 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1311 &retry_transmission_task,
1314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1315 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1316 mq->message_buf_size,
1317 GNUNET_i2s (&mq->neighbour_id),
1320 /* FIXME: might want to trigger peerinfo lookup here
1321 (unless that's already pending...) */
1324 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1325 neighbour->messages_tail,
1327 if (mq->specific_address->connected == GNUNET_NO)
1328 mq->specific_address->connect_attempts++;
1329 rl = mq->specific_address->ready_list;
1330 mq->plugin = rl->plugin;
1331 if (!mq->internal_msg)
1332 mq->specific_address->in_transmit = GNUNET_YES;
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1335 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1336 mq->message_buf_size,
1337 GNUNET_i2s (&neighbour->id),
1338 GNUNET_a2s (mq->specific_address->addr,
1339 mq->specific_address->addrlen),
1340 rl->plugin->short_name);
1342 GNUNET_STATISTICS_update (stats,
1343 gettext_noop ("# bytes in message queue for other peers"),
1344 - (int64_t) mq->message_buf_size,
1346 GNUNET_STATISTICS_update (stats,
1347 gettext_noop ("# bytes pending with plugins"),
1348 mq->message_buf_size,
1350 ret = rl->plugin->api->send (rl->plugin->api->cls,
1353 mq->message_buf_size,
1355 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1356 mq->specific_address->session,
1357 mq->specific_address->addr,
1358 mq->specific_address->addrlen,
1360 &transmit_send_continuation, mq);
1363 /* failure, but 'send' would not call continuation in this case,
1364 so we need to do it here! */
1365 transmit_send_continuation (mq,
1373 * Send the specified message to the specified peer.
1375 * @param client source of the transmission request (can be NULL)
1376 * @param peer_address ForeignAddressList where we should send this message
1377 * @param priority how important is the message
1378 * @param timeout how long do we have to transmit?
1379 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1380 * @param message_buf_size total size of all messages in message_buf
1381 * @param is_internal is this an internal message; these are pre-pended and
1382 * also do not count for plugins being "ready" to transmit
1383 * @param neighbour handle to the neighbour for transmission
1386 transmit_to_peer (struct TransportClient *client,
1387 struct ForeignAddressList *peer_address,
1388 unsigned int priority,
1389 struct GNUNET_TIME_Relative timeout,
1390 const char *message_buf,
1391 size_t message_buf_size,
1392 int is_internal, struct NeighbourList *neighbour)
1394 struct MessageQueue *mq;
1399 /* check for duplicate submission */
1400 mq = neighbour->messages_head;
1403 if (mq->client == client)
1405 /* client transmitted to same peer twice
1406 before getting SEND_OK! */
1414 GNUNET_STATISTICS_update (stats,
1415 gettext_noop ("# bytes in message queue for other peers"),
1418 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1419 mq->specific_address = peer_address;
1420 mq->client = client;
1421 memcpy (&mq[1], message_buf, message_buf_size);
1422 mq->message_buf = (const char*) &mq[1];
1423 mq->message_buf_size = message_buf_size;
1424 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1425 mq->internal_msg = is_internal;
1426 mq->priority = priority;
1427 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1429 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1430 neighbour->messages_tail,
1433 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1434 neighbour->messages_tail,
1435 neighbour->messages_tail,
1437 try_transmission_to_peer (neighbour);
1444 struct GeneratorContext
1446 struct TransportPlugin *plug_pos;
1447 struct OwnAddressList *addr_pos;
1448 struct GNUNET_TIME_Absolute expiration;
1456 address_generator (void *cls, size_t max, void *buf)
1458 struct GeneratorContext *gc = cls;
1461 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1463 gc->plug_pos = gc->plug_pos->next;
1464 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1466 if (NULL == gc->plug_pos)
1471 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1474 gc->addr_pos->addrlen, buf, max);
1475 gc->addr_pos = gc->addr_pos->next;
1481 * Construct our HELLO message from all of the addresses of
1482 * all of the transports.
1487 struct GNUNET_HELLO_Message *hello;
1488 struct TransportClient *cpos;
1489 struct NeighbourList *npos;
1490 struct GeneratorContext gc;
1492 gc.plug_pos = plugins;
1493 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1494 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1495 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1498 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1500 GNUNET_STATISTICS_update (stats,
1501 gettext_noop ("# refreshed my HELLO"),
1505 while (cpos != NULL)
1507 transmit_to_client (cpos,
1508 (const struct GNUNET_MessageHeader *) hello,
1513 GNUNET_free_non_null (our_hello);
1515 our_hello_version++;
1516 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1518 while (npos != NULL)
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1522 "Transmitting updated `%s' to neighbour `%4s'\n",
1523 "HELLO", GNUNET_i2s (&npos->id));
1525 GNUNET_STATISTICS_update (stats,
1526 gettext_noop ("# transmitted my HELLO to other peers"),
1529 transmit_to_peer (NULL, NULL, 0,
1530 HELLO_ADDRESS_EXPIRATION,
1531 (const char *) our_hello,
1532 GNUNET_HELLO_size(our_hello),
1540 * Task used to clean up expired addresses for a plugin.
1542 * @param cls closure
1546 expire_address_task (void *cls,
1547 const struct GNUNET_SCHEDULER_TaskContext *tc);
1551 * Update the list of addresses for this plugin,
1552 * expiring those that are past their expiration date.
1554 * @param plugin addresses of which plugin should be recomputed?
1555 * @param fresh set to GNUNET_YES if a new address was added
1556 * and we need to regenerate the HELLO even if nobody
1560 update_addresses (struct TransportPlugin *plugin, int fresh)
1562 static struct GNUNET_TIME_Absolute last_update;
1563 struct GNUNET_TIME_Relative min_remaining;
1564 struct GNUNET_TIME_Relative remaining;
1565 struct GNUNET_TIME_Absolute now;
1566 struct OwnAddressList *pos;
1567 struct OwnAddressList *prev;
1568 struct OwnAddressList *next;
1571 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1572 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1573 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1574 now = GNUNET_TIME_absolute_get ();
1575 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1576 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1578 pos = plugin->addresses;
1582 if (pos->expires.value < now.value)
1584 expired = GNUNET_YES;
1586 plugin->addresses = pos->next;
1588 prev->next = pos->next;
1593 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1594 if (remaining.value < min_remaining.value)
1595 min_remaining = remaining;
1601 if (expired || fresh)
1606 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1607 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1609 plugin->address_update_task
1610 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1612 &expire_address_task, plugin);
1617 * Task used to clean up expired addresses for a plugin.
1619 * @param cls closure
1623 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1625 struct TransportPlugin *plugin = cls;
1627 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1628 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1629 update_addresses (plugin, GNUNET_NO);
1634 * Function that will be called whenever the plugin internally
1635 * cleans up a session pointer and hence the service needs to
1636 * discard all of those sessions as well. Plugins that do not
1637 * use sessions can simply omit calling this function and always
1638 * use NULL wherever a session pointer is needed.
1640 * @param cls closure
1641 * @param peer which peer was the session for
1642 * @param session which session is being destoyed
1645 plugin_env_session_end (void *cls,
1646 const struct GNUNET_PeerIdentity *peer,
1647 struct Session *session)
1649 struct TransportPlugin *p = cls;
1650 struct NeighbourList *nl;
1651 struct ReadyList *rl;
1652 struct ForeignAddressList *pos;
1653 struct ForeignAddressList *prev;
1655 nl = find_neighbour (peer);
1661 if (rl->plugin == p)
1668 pos = rl->addresses;
1669 while ( (pos != NULL) &&
1670 (pos->session != session) )
1677 pos->session = NULL;
1678 if (pos->addrlen != 0)
1681 rl->addresses = pos->next;
1683 prev->next = pos->next;
1689 * Function that must be called by each plugin to notify the
1690 * transport service about the addresses under which the transport
1691 * provided by the plugin can be reached.
1693 * @param cls closure
1694 * @param name name of the transport that generated the address
1695 * @param addr one of the addresses of the host, NULL for the last address
1696 * the specific address format depends on the transport
1697 * @param addrlen length of the address
1698 * @param expires when should this address automatically expire?
1701 plugin_env_notify_address (void *cls,
1705 struct GNUNET_TIME_Relative expires)
1707 struct TransportPlugin *p = cls;
1708 struct OwnAddressList *al;
1709 struct GNUNET_TIME_Absolute abex;
1711 abex = GNUNET_TIME_relative_to_absolute (expires);
1712 GNUNET_assert (p == find_transport (name));
1717 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1719 if (al->expires.value < abex.value)
1726 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1728 al->next = p->addresses;
1731 al->addrlen = addrlen;
1732 memcpy (&al[1], addr, addrlen);
1733 update_addresses (p, GNUNET_YES);
1738 * Notify all of our clients about a peer connecting.
1741 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1742 struct GNUNET_TIME_Relative latency,
1745 struct ConnectInfoMessage cim;
1746 struct TransportClient *cpos;
1749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1750 "Notifying clients about connection from `%s'\n",
1753 GNUNET_STATISTICS_update (stats,
1754 gettext_noop ("# peers connected"),
1757 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1758 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1759 cim.distance = htonl (distance);
1760 cim.latency = GNUNET_TIME_relative_hton (latency);
1761 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1763 while (cpos != NULL)
1765 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1772 * Notify all of our clients about a peer disconnecting.
1775 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1777 struct DisconnectInfoMessage dim;
1778 struct TransportClient *cpos;
1781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1782 "Notifying clients about lost connection to `%s'\n",
1785 GNUNET_STATISTICS_update (stats,
1786 gettext_noop ("# peers connected"),
1789 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1790 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1791 dim.reserved = htonl (0);
1792 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1794 while (cpos != NULL)
1796 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1803 * Find a ForeignAddressList entry for the given neighbour
1804 * that matches the given address and transport.
1806 * @param neighbour which peer we care about
1807 * @param tname name of the transport plugin
1808 * @param session session to look for, NULL for 'any'; otherwise
1809 * can be used for the service to "learn" this session ID
1810 * @param addr binary address
1811 * @param addrlen length of addr
1812 * @return NULL if no such entry exists
1814 static struct ForeignAddressList *
1815 find_peer_address(struct NeighbourList *neighbour,
1817 struct Session *session,
1821 struct ReadyList *head;
1822 struct ForeignAddressList *address_head;
1824 head = neighbour->plugins;
1825 while (head != NULL)
1827 if (0 == strcmp (tname, head->plugin->short_name))
1834 address_head = head->addresses;
1835 while ( (address_head != NULL) &&
1836 ( (address_head->addrlen != addrlen) ||
1837 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1838 address_head = address_head->next;
1839 if (session != NULL)
1840 address_head->session = session; /* learn it! */
1841 return address_head;
1846 * Get the peer address struct for the given neighbour and
1847 * address. If it doesn't yet exist, create it.
1849 * @param neighbour which peer we care about
1850 * @param tname name of the transport plugin
1851 * @param session session of the plugin, or NULL for none
1852 * @param addr binary address
1853 * @param addrlen length of addr
1854 * @return NULL if we do not have a transport plugin for 'tname'
1856 static struct ForeignAddressList *
1857 add_peer_address (struct NeighbourList *neighbour,
1859 struct Session *session,
1863 struct ReadyList *head;
1864 struct ForeignAddressList *ret;
1866 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
1869 head = neighbour->plugins;
1870 while (head != NULL)
1872 if (0 == strcmp (tname, head->plugin->short_name))
1878 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1879 ret->session = session;
1880 ret->addr = (const char*) &ret[1];
1881 memcpy (&ret[1], addr, addrlen);
1882 ret->addrlen = addrlen;
1883 ret->expires = GNUNET_TIME_relative_to_absolute
1884 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1885 ret->latency = GNUNET_TIME_relative_get_forever();
1887 ret->timeout = GNUNET_TIME_relative_to_absolute
1888 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1889 ret->ready_list = head;
1890 ret->next = head->addresses;
1891 head->addresses = ret;
1897 * Closure for 'add_validated_address'.
1899 struct AddValidatedAddressContext
1902 * Entry that has been validated.
1904 const struct ValidationEntry *ve;
1907 * Flag set after we have added the address so
1908 * that we terminate the iteration next time.
1915 * Callback function used to fill a buffer of max bytes with a list of
1916 * addresses in the format used by HELLOs. Should use
1917 * "GNUNET_HELLO_add_address" as a helper function.
1919 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1920 * @param max maximum number of bytes that can be written to buf
1921 * @param buf where to write the address information
1922 * @return number of bytes written, 0 to signal the
1923 * end of the iteration.
1926 add_validated_address (void *cls,
1927 size_t max, void *buf)
1929 struct AddValidatedAddressContext *avac = cls;
1930 const struct ValidationEntry *ve = avac->ve;
1932 if (GNUNET_YES == avac->done)
1934 avac->done = GNUNET_YES;
1935 return GNUNET_HELLO_add_address (ve->transport_name,
1936 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1946 * Closure for 'check_address_exists'.
1948 struct CheckAddressExistsClosure
1951 * Address to check for.
1956 * Name of the transport.
1966 * Set to GNUNET_YES if the address exists.
1973 * Iterator over hash map entries. Checks if the given
1974 * validation entry is for the same address as what is given
1977 * @param cls the 'struct CheckAddressExistsClosure*'
1978 * @param key current key code (ignored)
1979 * @param value value in the hash map ('struct ValidationEntry')
1980 * @return GNUNET_YES if we should continue to
1981 * iterate (mismatch), GNUNET_NO if not (entry matched)
1984 check_address_exists (void *cls,
1985 const GNUNET_HashCode * key,
1988 struct CheckAddressExistsClosure *caec = cls;
1989 struct ValidationEntry *ve = value;
1990 if ( (0 == strcmp (caec->tname,
1991 ve->transport_name)) &&
1992 (caec->addrlen == ve->addrlen) &&
1993 (0 == memcmp (caec->addr,
1997 caec->exists = GNUNET_YES;
2005 * HELLO validation cleanup task (validation failed).
2007 * @param cls the 'struct ValidationEntry' that failed
2008 * @param tc scheduler context (unused)
2011 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2013 struct ValidationEntry *va = cls;
2014 struct GNUNET_PeerIdentity pid;
2016 GNUNET_STATISTICS_update (stats,
2017 gettext_noop ("# address validation timeouts"),
2020 GNUNET_CRYPTO_hash (&va->publicKey,
2022 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2024 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2027 GNUNET_free (va->transport_name);
2033 neighbour_timeout_task (void *cls,
2034 const struct GNUNET_SCHEDULER_TaskContext *tc)
2036 struct NeighbourList *n = cls;
2039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2040 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2042 GNUNET_STATISTICS_update (stats,
2043 gettext_noop ("# disconnects due to timeout"),
2046 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2047 disconnect_neighbour (n, GNUNET_NO);
2052 * Schedule the job that will cause us to send a PING to the
2053 * foreign address to evaluate its validity and latency.
2055 * @param fal address to PING
2058 schedule_next_ping (struct ForeignAddressList *fal);
2062 * Add the given address to the list of foreign addresses
2063 * available for the given peer (check for duplicates).
2065 * @param cls the respective 'struct NeighbourList' to update
2066 * @param tname name of the transport
2067 * @param expiration expiration time
2068 * @param addr the address
2069 * @param addrlen length of the address
2070 * @return GNUNET_OK (always)
2073 add_to_foreign_address_list (void *cls,
2075 struct GNUNET_TIME_Absolute expiration,
2076 const void *addr, size_t addrlen)
2078 struct NeighbourList *n = cls;
2079 struct ForeignAddressList *fal;
2082 GNUNET_STATISTICS_update (stats,
2083 gettext_noop ("# valid peer addresses returned by peerinfo"),
2087 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2092 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2093 GNUNET_a2s (addr, addrlen),
2095 GNUNET_i2s (&n->id),
2098 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2101 GNUNET_STATISTICS_update (stats,
2102 gettext_noop ("# previously validated addresses lacking transport"),
2108 fal->expires = GNUNET_TIME_absolute_max (expiration,
2110 schedule_next_ping (fal);
2116 fal->expires = GNUNET_TIME_absolute_max (expiration,
2121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2122 "Failed to add new address for `%4s'\n",
2123 GNUNET_i2s (&n->id));
2126 if (fal->validated == GNUNET_NO)
2128 fal->validated = GNUNET_YES;
2129 GNUNET_STATISTICS_update (stats,
2130 gettext_noop ("# peer addresses considered valid"),
2134 if (try == GNUNET_YES)
2136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2137 "Have new addresses, will try to trigger transmissions.\n");
2138 try_transmission_to_peer (n);
2145 * Add addresses in validated HELLO "h" to the set of addresses
2146 * we have for this peer.
2148 * @param cls closure ('struct NeighbourList*')
2149 * @param peer id of the peer, NULL for last call
2150 * @param h hello message for the peer (can be NULL)
2151 * @param trust amount of trust we have in the peer (not used)
2154 add_hello_for_peer (void *cls,
2155 const struct GNUNET_PeerIdentity *peer,
2156 const struct GNUNET_HELLO_Message *h,
2159 struct NeighbourList *n = cls;
2167 return; /* no HELLO available */
2169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2170 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2174 if (GNUNET_YES != n->public_key_valid)
2176 GNUNET_HELLO_get_key (h, &n->publicKey);
2177 n->public_key_valid = GNUNET_YES;
2179 GNUNET_HELLO_iterate_addresses (h,
2181 &add_to_foreign_address_list,
2187 * Create a fresh entry in our neighbour list for the given peer.
2188 * Will try to transmit our current HELLO to the new neighbour.
2190 * @param peer the peer for which we create the entry
2191 * @return the new neighbour list entry
2193 static struct NeighbourList *
2194 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2196 struct NeighbourList *n;
2197 struct TransportPlugin *tp;
2198 struct ReadyList *rl;
2200 GNUNET_assert (our_hello != NULL);
2201 GNUNET_STATISTICS_update (stats,
2202 gettext_noop ("# active neighbours"),
2205 n = GNUNET_malloc (sizeof (struct NeighbourList));
2206 n->next = neighbours;
2210 GNUNET_TIME_relative_to_absolute
2211 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2212 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2213 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2214 MAX_BANDWIDTH_CARRY_S);
2218 if (tp->api->send != NULL)
2220 rl = GNUNET_malloc (sizeof (struct ReadyList));
2222 rl->next = n->plugins;
2225 rl->addresses = NULL;
2229 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2231 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2232 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2233 &neighbour_timeout_task, n);
2234 n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2235 0, GNUNET_TIME_UNIT_FOREVER_REL,
2236 &add_hello_for_peer, n);
2237 transmit_to_peer (NULL, NULL, 0,
2238 HELLO_ADDRESS_EXPIRATION,
2239 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2246 * Send periodic PING messages to a give foreign address.
2248 * @param cls our 'struct PeriodicValidationContext*'
2249 * @param tc task context
2252 send_periodic_ping (void *cls,
2253 const struct GNUNET_SCHEDULER_TaskContext *tc)
2255 struct ForeignAddressList *peer_address = cls;
2256 struct TransportPlugin *tp;
2257 struct ValidationEntry *va;
2258 struct NeighbourList *neighbour;
2259 struct TransportPingMessage ping;
2260 struct CheckAddressExistsClosure caec;
2262 uint16_t hello_size;
2265 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2266 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2268 tp = peer_address->ready_list->plugin;
2269 neighbour = peer_address->ready_list->neighbour;
2270 if (GNUNET_YES != neighbour->public_key_valid)
2272 /* no public key yet, try again later */
2273 schedule_next_ping (peer_address);
2276 caec.addr = peer_address->addr;
2277 caec.addrlen = peer_address->addrlen;
2278 caec.tname = tp->short_name;
2279 caec.exists = GNUNET_NO;
2280 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2281 &check_address_exists,
2283 if (caec.exists == GNUNET_YES)
2285 /* During validation attempts we will likely trigger the other
2286 peer trying to validate our address which in turn will cause
2287 it to send us its HELLO, so we expect to hit this case rather
2288 frequently. Only print something if we are very verbose. */
2289 #if DEBUG_TRANSPORT > 1
2290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2291 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2292 GNUNET_a2s (peer_address->addr,
2293 peer_address->addrlen),
2295 GNUNET_i2s (&neighbour->id));
2297 schedule_next_ping (peer_address);
2300 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2301 va->transport_name = GNUNET_strdup (tp->short_name);
2302 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2304 va->send_time = GNUNET_TIME_absolute_get();
2305 va->addr = (const void*) &va[1];
2306 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2307 va->addrlen = peer_address->addrlen;
2309 memcpy(&va->publicKey,
2310 &neighbour->publicKey,
2311 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2313 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2314 HELLO_VERIFICATION_TIMEOUT,
2315 &timeout_hello_validation,
2317 GNUNET_CONTAINER_multihashmap_put (validation_map,
2318 &neighbour->id.hashPubKey,
2320 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2321 hello_size = GNUNET_HELLO_size(our_hello);
2322 tsize = sizeof(struct TransportPingMessage) + hello_size;
2323 message_buf = GNUNET_malloc(tsize);
2324 ping.challenge = htonl(va->challenge);
2325 ping.header.size = htons(sizeof(struct TransportPingMessage));
2326 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2327 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2328 memcpy(message_buf, our_hello, hello_size);
2329 memcpy(&message_buf[hello_size],
2331 sizeof(struct TransportPingMessage));
2332 #if DEBUG_TRANSPORT_REVALIDATION
2333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2334 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2335 GNUNET_a2s (peer_address->addr,
2336 peer_address->addrlen),
2338 GNUNET_i2s (&neighbour->id),
2339 "HELLO", hello_size,
2340 "PING", sizeof (struct TransportPingMessage));
2342 GNUNET_STATISTICS_update (stats,
2343 gettext_noop ("# PING messages sent for re-validation"),
2346 transmit_to_peer (NULL, peer_address,
2347 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2348 HELLO_VERIFICATION_TIMEOUT,
2350 GNUNET_YES, neighbour);
2351 GNUNET_free(message_buf);
2352 schedule_next_ping (peer_address);
2357 * Schedule the job that will cause us to send a PING to the
2358 * foreign address to evaluate its validity and latency.
2360 * @param fal address to PING
2363 schedule_next_ping (struct ForeignAddressList *fal)
2365 struct GNUNET_TIME_Relative delay;
2367 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2369 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2370 delay.value /= 2; /* do before expiration */
2371 delay = GNUNET_TIME_relative_min (delay,
2372 LATENCY_EVALUATION_MAX_DELAY);
2373 if (GNUNET_YES != fal->estimated)
2375 delay = GNUNET_TIME_UNIT_ZERO;
2376 fal->estimated = GNUNET_YES;
2378 if (GNUNET_YES == fal->connected)
2380 delay = GNUNET_TIME_relative_min (delay,
2381 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2383 /* FIXME: also adjust delay based on how close the last
2384 observed latency is to the latency of the best alternative */
2385 /* bound how fast we can go */
2386 delay = GNUNET_TIME_relative_max (delay,
2387 GNUNET_TIME_UNIT_SECONDS);
2388 /* randomize a bit (to avoid doing all at the same time) */
2389 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2390 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
2392 &send_periodic_ping,
2398 * Iterator over hash map entries. Checks if the given validation
2399 * entry is for the same challenge as what is given in the PONG.
2401 * @param cls the 'struct TransportPongMessage*'
2402 * @param key peer identity
2403 * @param value value in the hash map ('struct ValidationEntry')
2404 * @return GNUNET_YES if we should continue to
2405 * iterate (mismatch), GNUNET_NO if not (entry matched)
2408 check_pending_validation (void *cls,
2409 const GNUNET_HashCode * key,
2412 const struct TransportPongMessage *pong = cls;
2413 struct ValidationEntry *ve = value;
2414 struct AddValidatedAddressContext avac;
2415 unsigned int challenge = ntohl(pong->challenge);
2416 struct GNUNET_HELLO_Message *hello;
2417 struct GNUNET_PeerIdentity target;
2418 struct NeighbourList *n;
2419 struct ForeignAddressList *fal;
2421 if (ve->challenge != challenge)
2424 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
2429 GNUNET_break_op (0);
2434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2435 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2437 GNUNET_a2s ((const struct sockaddr *) ve->addr,
2439 ve->transport_name);
2441 GNUNET_STATISTICS_update (stats,
2442 gettext_noop ("# address validation successes"),
2445 /* create the updated HELLO */
2446 GNUNET_CRYPTO_hash (&ve->publicKey,
2447 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2448 &target.hashPubKey);
2449 avac.done = GNUNET_NO;
2451 hello = GNUNET_HELLO_create (&ve->publicKey,
2452 &add_validated_address,
2454 GNUNET_PEERINFO_add_peer (cfg, sched,
2457 GNUNET_free (hello);
2458 n = find_neighbour (&target);
2461 n->publicKey = ve->publicKey;
2462 n->public_key_valid = GNUNET_YES;
2463 fal = add_peer_address (n,
2468 GNUNET_assert (fal != NULL);
2469 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2470 fal->validated = GNUNET_YES;
2471 GNUNET_STATISTICS_update (stats,
2472 gettext_noop ("# peer addresses considered valid"),
2475 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2476 schedule_next_ping (fal);
2477 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2478 n->latency = fal->latency;
2480 n->latency.value = (fal->latency.value + n->latency.value) / 2;
2481 n->distance = fal->distance;
2482 if (GNUNET_NO == n->received_pong)
2484 n->received_pong = GNUNET_YES;
2485 notify_clients_connect (&target, n->latency, n->distance);
2487 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2489 GNUNET_SCHEDULER_cancel (sched,
2491 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2492 try_transmission_to_peer (n);
2496 /* clean up validation entry */
2497 GNUNET_assert (GNUNET_YES ==
2498 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2501 GNUNET_SCHEDULER_cancel (sched,
2503 GNUNET_free (ve->transport_name);
2510 * Function that will be called if we receive a validation
2511 * of an address challenge that we transmitted to another
2512 * peer. Note that the validation should only be considered
2513 * acceptable if the challenge matches AND if the sender
2514 * address is at least a plausible address for this peer
2515 * (otherwise we may be seeing a MiM attack).
2517 * @param cls closure
2518 * @param message the pong message
2519 * @param peer who responded to our challenge
2520 * @param sender_address string describing our sender address (as observed
2521 * by the other peer in binary format)
2522 * @param sender_address_len number of bytes in 'sender_address'
2525 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2526 const struct GNUNET_PeerIdentity *peer,
2527 const char *sender_address,
2528 size_t sender_address_len)
2530 #if DEBUG_TRANSPORT > 1
2531 /* we get tons of these that just get discarded, only log
2532 if we are quite verbose */
2533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2534 "Receiving `%s' message from `%4s'.\n", "PONG",
2537 GNUNET_STATISTICS_update (stats,
2538 gettext_noop ("# PONG messages received"),
2541 if (GNUNET_SYSERR !=
2542 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2544 &check_pending_validation,
2547 /* This is *expected* to happen a lot since we send
2548 PONGs to *all* known addresses of the sender of
2549 the PING, so most likely we get multiple PONGs
2550 per PING, and all but the first PONG will end up
2551 here. So really we should not print anything here
2552 unless we want to be very, very verbose... */
2553 #if DEBUG_TRANSPORT > 2
2554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2555 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2564 /* FIXME: add given address to potential pool of our addresses
2566 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2567 _("Another peer saw us using the address `%s' via `%s'.\n"),
2568 GNUNET_a2s ((const struct sockaddr *) &pong[1],
2569 ntohs(pong->addrlen)),
2570 va->transport_name);
2576 * Check if the given address is already being validated; if not,
2577 * append the given address to the list of entries that are being be
2578 * validated and initiate validation.
2580 * @param cls closure ('struct CheckHelloValidatedContext *')
2581 * @param tname name of the transport
2582 * @param expiration expiration time
2583 * @param addr the address
2584 * @param addrlen length of the address
2585 * @return GNUNET_OK (always)
2588 run_validation (void *cls,
2590 struct GNUNET_TIME_Absolute expiration,
2591 const void *addr, size_t addrlen)
2593 struct CheckHelloValidatedContext *chvc = cls;
2594 struct GNUNET_PeerIdentity id;
2595 struct TransportPlugin *tp;
2596 struct ValidationEntry *va;
2597 struct NeighbourList *neighbour;
2598 struct ForeignAddressList *peer_address;
2599 struct TransportPingMessage ping;
2600 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2601 struct CheckAddressExistsClosure caec;
2603 uint16_t hello_size;
2606 GNUNET_STATISTICS_update (stats,
2607 gettext_noop ("# peer addresses scheduled for validation"),
2610 tp = find_transport (tname);
2613 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2614 GNUNET_ERROR_TYPE_BULK,
2616 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2618 GNUNET_STATISTICS_update (stats,
2619 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2624 GNUNET_HELLO_get_key (chvc->hello, &pk);
2625 GNUNET_CRYPTO_hash (&pk,
2627 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2630 caec.addrlen = addrlen;
2632 caec.exists = GNUNET_NO;
2633 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2634 &check_address_exists,
2636 if (caec.exists == GNUNET_YES)
2638 /* During validation attempts we will likely trigger the other
2639 peer trying to validate our address which in turn will cause
2640 it to send us its HELLO, so we expect to hit this case rather
2641 frequently. Only print something if we are very verbose. */
2642 #if DEBUG_TRANSPORT > 1
2643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2644 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2645 GNUNET_a2s (addr, addrlen),
2649 GNUNET_STATISTICS_update (stats,
2650 gettext_noop ("# peer addresses not validated (in progress)"),
2655 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2656 va->transport_name = GNUNET_strdup (tname);
2657 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2659 va->send_time = GNUNET_TIME_absolute_get();
2660 va->addr = (const void*) &va[1];
2661 memcpy (&va[1], addr, addrlen);
2662 va->addrlen = addrlen;
2663 GNUNET_HELLO_get_key (chvc->hello,
2665 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2666 HELLO_VERIFICATION_TIMEOUT,
2667 &timeout_hello_validation,
2669 GNUNET_CONTAINER_multihashmap_put (validation_map,
2672 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2673 neighbour = find_neighbour(&id);
2674 if (neighbour == NULL)
2675 neighbour = setup_new_neighbour(&id);
2676 neighbour->publicKey = va->publicKey;
2677 neighbour->public_key_valid = GNUNET_YES;
2678 peer_address = add_peer_address(neighbour, tname, NULL, addr, addrlen);
2679 GNUNET_assert(peer_address != NULL);
2680 hello_size = GNUNET_HELLO_size(our_hello);
2681 tsize = sizeof(struct TransportPingMessage) + hello_size;
2682 message_buf = GNUNET_malloc(tsize);
2683 ping.challenge = htonl(va->challenge);
2684 ping.header.size = htons(sizeof(struct TransportPingMessage));
2685 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2686 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2687 memcpy(message_buf, our_hello, hello_size);
2688 memcpy(&message_buf[hello_size],
2690 sizeof(struct TransportPingMessage));
2692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2693 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2694 GNUNET_a2s (addr, addrlen),
2697 "HELLO", hello_size,
2698 "PING", sizeof (struct TransportPingMessage));
2700 GNUNET_STATISTICS_update (stats,
2701 gettext_noop ("# PING messages sent for initial validation"),
2704 transmit_to_peer (NULL, peer_address,
2705 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2706 HELLO_VERIFICATION_TIMEOUT,
2708 GNUNET_YES, neighbour);
2709 GNUNET_free(message_buf);
2715 * Check if addresses in validated hello "h" overlap with
2716 * those in "chvc->hello" and validate the rest.
2718 * @param cls closure
2719 * @param peer id of the peer, NULL for last call
2720 * @param h hello message for the peer (can be NULL)
2721 * @param trust amount of trust we have in the peer (not used)
2724 check_hello_validated (void *cls,
2725 const struct GNUNET_PeerIdentity *peer,
2726 const struct GNUNET_HELLO_Message *h,
2729 struct CheckHelloValidatedContext *chvc = cls;
2730 struct GNUNET_HELLO_Message *plain_hello;
2731 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2732 struct GNUNET_PeerIdentity target;
2733 struct NeighbourList *n;
2738 GNUNET_CONTAINER_DLL_remove (chvc_head,
2741 if (GNUNET_NO == chvc->hello_known)
2743 /* notify PEERINFO about the peer now, so that we at least
2744 have the public key if some other component needs it */
2745 GNUNET_HELLO_get_key (chvc->hello, &pk);
2746 GNUNET_CRYPTO_hash (&pk,
2747 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2748 &target.hashPubKey);
2749 plain_hello = GNUNET_HELLO_create (&pk,
2752 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2753 GNUNET_free (plain_hello);
2755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2756 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2758 GNUNET_i2s (&target));
2760 GNUNET_STATISTICS_update (stats,
2761 gettext_noop ("# new HELLOs requiring full validation"),
2764 GNUNET_HELLO_iterate_addresses (chvc->hello,
2771 GNUNET_STATISTICS_update (stats,
2772 gettext_noop ("# duplicate HELLO (peer known)"),
2782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2783 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2787 chvc->hello_known = GNUNET_YES;
2788 n = find_neighbour (peer);
2791 GNUNET_HELLO_iterate_addresses (h,
2793 &add_to_foreign_address_list,
2795 try_transmission_to_peer (n);
2799 GNUNET_STATISTICS_update (stats,
2800 gettext_noop ("# no existing neighbour record (validating HELLO)"),
2804 GNUNET_STATISTICS_update (stats,
2805 gettext_noop ("# HELLO validations (update case)"),
2808 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2810 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2816 * Process HELLO-message.
2818 * @param plugin transport involved, may be NULL
2819 * @param message the actual message
2820 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2823 process_hello (struct TransportPlugin *plugin,
2824 const struct GNUNET_MessageHeader *message)
2827 struct GNUNET_PeerIdentity target;
2828 const struct GNUNET_HELLO_Message *hello;
2829 struct CheckHelloValidatedContext *chvc;
2830 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2832 hsize = ntohs (message->size);
2833 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2834 (hsize < sizeof (struct GNUNET_MessageHeader)))
2837 return GNUNET_SYSERR;
2839 GNUNET_STATISTICS_update (stats,
2840 gettext_noop ("# HELLOs received for validation"),
2843 /* first, check if load is too high */
2844 if (GNUNET_SCHEDULER_get_load (sched,
2845 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2847 GNUNET_STATISTICS_update (stats,
2848 gettext_noop ("# HELLOs ignored due to high load"),
2853 hello = (const struct GNUNET_HELLO_Message *) message;
2854 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2856 GNUNET_break_op (0);
2857 return GNUNET_SYSERR;
2859 GNUNET_CRYPTO_hash (&publicKey,
2860 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2861 &target.hashPubKey);
2862 if (0 == memcmp (&my_identity,
2864 sizeof (struct GNUNET_PeerIdentity)))
2866 GNUNET_STATISTICS_update (stats,
2867 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2872 #if DEBUG_TRANSPORT > 1
2873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2874 "Processing `%s' message for `%4s' of size %u\n",
2876 GNUNET_i2s (&target),
2877 GNUNET_HELLO_size(hello));
2879 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2880 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2881 memcpy (&chvc[1], hello, hsize);
2882 GNUNET_CONTAINER_DLL_insert (chvc_head,
2885 /* finally, check if HELLO was previously validated
2886 (continuation will then schedule actual validation) */
2887 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2891 HELLO_VERIFICATION_TIMEOUT,
2892 &check_hello_validated, chvc);
2898 * The peer specified by the given neighbour has timed-out or a plugin
2899 * has disconnected. We may either need to do nothing (other plugins
2900 * still up), or trigger a full disconnect and clean up. This
2901 * function updates our state and does the necessary notifications.
2902 * Also notifies our clients that the neighbour is now officially
2905 * @param n the neighbour list entry for the peer
2906 * @param check should we just check if all plugins
2907 * disconnected or must we ask all plugins to
2911 disconnect_neighbour (struct NeighbourList *n, int check)
2913 struct ReadyList *rpos;
2914 struct NeighbourList *npos;
2915 struct NeighbourList *nprev;
2916 struct MessageQueue *mq;
2917 struct ForeignAddressList *peer_addresses;
2918 struct ForeignAddressList *peer_pos;
2920 if (GNUNET_YES == check)
2923 while (NULL != rpos)
2925 peer_addresses = rpos->addresses;
2926 while (peer_addresses != NULL)
2928 if (GNUNET_YES == peer_addresses->connected)
2929 return; /* still connected */
2930 peer_addresses = peer_addresses->next;
2936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2937 "Disconnecting from `%4s'\n",
2938 GNUNET_i2s (&n->id));
2940 /* remove n from neighbours list */
2943 while ((npos != NULL) && (npos != n))
2948 GNUNET_assert (npos != NULL);
2950 neighbours = n->next;
2952 nprev->next = n->next;
2954 /* notify all clients about disconnect */
2955 if (GNUNET_YES == n->received_pong)
2956 notify_clients_disconnect (&n->id);
2958 /* clean up all plugins, cancel connections and pending transmissions */
2959 while (NULL != (rpos = n->plugins))
2961 n->plugins = rpos->next;
2962 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2963 while (rpos->addresses != NULL)
2965 peer_pos = rpos->addresses;
2966 rpos->addresses = peer_pos->next;
2967 if (peer_pos->connected == GNUNET_YES)
2968 GNUNET_STATISTICS_update (stats,
2969 gettext_noop ("# connected addresses"),
2972 if (GNUNET_YES == peer_pos->validated)
2973 GNUNET_STATISTICS_update (stats,
2974 gettext_noop ("# peer addresses considered valid"),
2977 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
2979 GNUNET_SCHEDULER_cancel (sched,
2980 peer_pos->revalidate_task);
2981 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2983 GNUNET_free(peer_pos);
2988 /* free all messages on the queue */
2989 while (NULL != (mq = n->messages_head))
2991 GNUNET_STATISTICS_update (stats,
2992 gettext_noop ("# bytes in message queue for other peers"),
2993 - (int64_t) mq->message_buf_size,
2995 GNUNET_STATISTICS_update (stats,
2996 gettext_noop ("# bytes discarded due to disconnect"),
2997 mq->message_buf_size,
2999 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3002 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3004 sizeof(struct GNUNET_PeerIdentity)));
3007 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3009 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3010 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3012 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3014 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3015 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3017 if (n->piter != NULL)
3019 GNUNET_PEERINFO_iterate_cancel (n->piter);
3022 /* finally, free n itself */
3023 GNUNET_STATISTICS_update (stats,
3024 gettext_noop ("# active neighbours"),
3032 * We have received a PING message from someone. Need to send a PONG message
3033 * in response to the peer by any means necessary.
3036 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3037 const struct GNUNET_PeerIdentity *peer,
3038 const char *sender_address,
3039 size_t sender_address_len)
3041 struct TransportPlugin *plugin = cls;
3042 struct TransportPingMessage *ping;
3043 struct TransportPongMessage *pong;
3044 struct NeighbourList *n;
3045 struct ReadyList *rl;
3046 struct ForeignAddressList *fal;
3048 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3050 GNUNET_break_op (0);
3051 return GNUNET_SYSERR;
3053 ping = (struct TransportPingMessage *) message;
3054 if (0 != memcmp (&ping->target,
3055 plugin->env.my_identity,
3056 sizeof (struct GNUNET_PeerIdentity)))
3058 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3059 _("Received `%s' message not destined for me!\n"),
3061 return GNUNET_SYSERR;
3064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3065 "Processing `%s' from `%s'\n",
3067 GNUNET_a2s ((const struct sockaddr *)sender_address,
3068 sender_address_len));
3070 GNUNET_STATISTICS_update (stats,
3071 gettext_noop ("# PING messages received"),
3074 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3075 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3076 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3077 pong->purpose.size =
3078 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3080 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3081 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3082 pong->challenge = ping->challenge;
3083 pong->addrlen = htons(sender_address_len);
3084 memcpy(&pong->signer,
3086 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3087 memcpy (&pong[1], sender_address, sender_address_len);
3088 GNUNET_assert (GNUNET_OK ==
3089 GNUNET_CRYPTO_rsa_sign (my_private_key,
3090 &pong->purpose, &pong->signature));
3091 n = find_neighbour(peer);
3092 GNUNET_assert (n != NULL);
3093 /* first try reliable response transmission */
3097 fal = rl->addresses;
3100 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3103 ntohs (pong->header.size),
3104 TRANSPORT_PONG_PRIORITY,
3105 HELLO_VERIFICATION_TIMEOUT,
3113 GNUNET_STATISTICS_update (stats,
3114 gettext_noop ("# PONGs unicast via reliable transport"),
3124 /* no reliable method found, do multicast */
3125 GNUNET_STATISTICS_update (stats,
3126 gettext_noop ("# PONGs multicast to all available addresses"),
3132 fal = rl->addresses;
3135 transmit_to_peer(NULL, fal,
3136 TRANSPORT_PONG_PRIORITY,
3137 HELLO_VERIFICATION_TIMEOUT,
3139 ntohs(pong->header.size),
3152 * Function called by the plugin for each received message.
3153 * Update data volumes, possibly notify plugins about
3154 * reducing the rate at which they read from the socket
3155 * and generally forward to our receive callback.
3157 * @param cls the "struct TransportPlugin *" we gave to the plugin
3158 * @param peer (claimed) identity of the other peer
3159 * @param message the message, NULL if we only care about
3160 * learning about the delay until we should receive again
3161 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3162 * @param session identifier used for this session (can be NULL)
3163 * @param sender_address binary address of the sender (if observed)
3164 * @param sender_address_len number of bytes in sender_address
3165 * @return how long the plugin should wait until receiving more data
3166 * (plugins that do not support this, can ignore the return value)
3168 static struct GNUNET_TIME_Relative
3169 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3170 const struct GNUNET_MessageHeader *message,
3171 unsigned int distance,
3172 struct Session *session,
3173 const char *sender_address,
3174 size_t sender_address_len)
3176 struct TransportPlugin *plugin = cls;
3177 struct ReadyList *service_context;
3178 struct TransportClient *cpos;
3179 struct InboundMessage *im;
3180 struct ForeignAddressList *peer_address;
3182 struct NeighbourList *n;
3183 struct GNUNET_TIME_Relative ret;
3185 n = find_neighbour (peer);
3187 n = setup_new_neighbour (peer);
3188 service_context = n->plugins;
3189 while ((service_context != NULL) && (plugin != service_context->plugin))
3190 service_context = service_context->next;
3191 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3192 if (message != NULL)
3194 peer_address = add_peer_address(n,
3198 sender_address_len);
3199 if (peer_address != NULL)
3201 peer_address->distance = distance;
3202 if (peer_address->connected == GNUNET_NO)
3204 /* FIXME: be careful here to not mark
3205 MULTIPLE addresses as connected! */
3206 peer_address->connected = GNUNET_YES;
3207 GNUNET_STATISTICS_update (stats,
3208 gettext_noop ("# connected addresses"),
3212 peer_address->timeout
3214 GNUNET_TIME_relative_to_absolute
3215 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3216 schedule_next_ping (peer_address);
3218 /* update traffic received amount ... */
3219 msize = ntohs (message->size);
3220 GNUNET_STATISTICS_update (stats,
3221 gettext_noop ("# bytes received from other peers"),
3224 n->distance = distance;
3226 GNUNET_TIME_relative_to_absolute
3227 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3228 GNUNET_SCHEDULER_cancel (sched,
3231 GNUNET_SCHEDULER_add_delayed (sched,
3232 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3233 &neighbour_timeout_task, n);
3234 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3236 /* dropping message due to frequent inbound volume violations! */
3237 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3238 GNUNET_ERROR_TYPE_BULK,
3240 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
3241 n->in_tracker.available_bytes_per_s__,
3242 n->quota_violation_count);
3243 GNUNET_STATISTICS_update (stats,
3244 gettext_noop ("# bandwidth quota violations by other peers"),
3247 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
3249 switch (ntohs (message->type))
3251 case GNUNET_MESSAGE_TYPE_HELLO:
3252 GNUNET_STATISTICS_update (stats,
3253 gettext_noop ("# HELLO messages received from other peers"),
3256 process_hello (plugin, message);
3258 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3259 handle_ping (plugin, message, peer, sender_address, sender_address_len);
3261 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3262 handle_pong (plugin, message, peer, sender_address, sender_address_len);
3266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3267 "Received message of type %u from `%4s', sending to all clients.\n",
3268 ntohs (message->type), GNUNET_i2s (peer));
3270 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3273 n->quota_violation_count++;
3275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3276 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3277 n->in_tracker.available_bytes_per_s__,
3278 n->quota_violation_count);
3280 /* Discount 32k per violation */
3281 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3286 if (n->quota_violation_count > 0)
3288 /* try to add 32k back */
3289 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3291 n->quota_violation_count--;
3294 GNUNET_STATISTICS_update (stats,
3295 gettext_noop ("# payload received from other peers"),
3298 /* transmit message to all clients */
3299 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3300 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3301 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3302 im->latency = GNUNET_TIME_relative_hton (n->latency);
3304 memcpy (&im[1], message, msize);
3306 while (cpos != NULL)
3308 transmit_to_client (cpos, &im->header, GNUNET_YES);
3314 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3317 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3318 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3319 (unsigned long long) n->in_tracker.consumption_since_last_update__,
3320 (unsigned int) n->in_tracker.available_bytes_per_s__,
3321 (unsigned long long) ret.value);
3322 GNUNET_STATISTICS_update (stats,
3323 gettext_noop ("# ms throttling suggested"),
3324 (int64_t) ret.value,
3332 * Handle START-message. This is the first message sent to us
3333 * by any client which causes us to add it to our list.
3335 * @param cls closure (always NULL)
3336 * @param client identification of the client
3337 * @param message the actual message
3340 handle_start (void *cls,
3341 struct GNUNET_SERVER_Client *client,
3342 const struct GNUNET_MessageHeader *message)
3344 struct TransportClient *c;
3345 struct ConnectInfoMessage cim;
3346 struct NeighbourList *n;
3349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3350 "Received `%s' request from client\n", "START");
3355 if (c->client == client)
3357 /* client already on our list! */
3359 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3364 c = GNUNET_malloc (sizeof (struct TransportClient));
3368 if (our_hello != NULL)
3371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3372 "Sending our own `%s' to new client\n", "HELLO");
3374 transmit_to_client (c,
3375 (const struct GNUNET_MessageHeader *) our_hello,
3377 /* tell new client about all existing connections */
3378 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3379 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3383 if (GNUNET_YES == n->received_pong)
3386 cim.latency = GNUNET_TIME_relative_hton (n->latency);
3387 cim.distance = htonl (n->distance);
3388 transmit_to_client (c, &cim.header, GNUNET_NO);
3393 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3398 * Handle HELLO-message.
3400 * @param cls closure (always NULL)
3401 * @param client identification of the client
3402 * @param message the actual message
3405 handle_hello (void *cls,
3406 struct GNUNET_SERVER_Client *client,
3407 const struct GNUNET_MessageHeader *message)
3411 GNUNET_STATISTICS_update (stats,
3412 gettext_noop ("# HELLOs received from clients"),
3415 ret = process_hello (NULL, message);
3416 GNUNET_SERVER_receive_done (client, ret);
3421 * Handle SEND-message.
3423 * @param cls closure (always NULL)
3424 * @param client identification of the client
3425 * @param message the actual message
3428 handle_send (void *cls,
3429 struct GNUNET_SERVER_Client *client,
3430 const struct GNUNET_MessageHeader *message)
3432 struct TransportClient *tc;
3433 struct NeighbourList *n;
3434 const struct OutboundMessage *obm;
3435 const struct GNUNET_MessageHeader *obmm;
3439 size = ntohs (message->size);
3441 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3444 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3447 GNUNET_STATISTICS_update (stats,
3448 gettext_noop ("# payload received for other peers"),
3451 obm = (const struct OutboundMessage *) message;
3453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3454 "Received `%s' request from client with target `%4s'\n",
3455 "SEND", GNUNET_i2s (&obm->peer));
3457 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3458 msize = ntohs (obmm->size);
3459 if (size != msize + sizeof (struct OutboundMessage))
3462 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3465 n = find_neighbour (&obm->peer);
3467 n = setup_new_neighbour (&obm->peer);
3469 while ((tc != NULL) && (tc->client != client))
3473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3474 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3476 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3478 transmit_to_peer (tc, NULL, ntohl (obm->priority),
3479 GNUNET_TIME_relative_ntoh (obm->timeout),
3481 ntohs (obmm->size), GNUNET_NO, n);
3482 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3487 * Handle SET_QUOTA-message.
3489 * @param cls closure (always NULL)
3490 * @param client identification of the client
3491 * @param message the actual message
3494 handle_set_quota (void *cls,
3495 struct GNUNET_SERVER_Client *client,
3496 const struct GNUNET_MessageHeader *message)
3498 const struct QuotaSetMessage *qsm =
3499 (const struct QuotaSetMessage *) message;
3500 struct NeighbourList *n;
3502 GNUNET_STATISTICS_update (stats,
3503 gettext_noop ("# SET QUOTA messages received"),
3506 n = find_neighbour (&qsm->peer);
3509 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3510 GNUNET_STATISTICS_update (stats,
3511 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3518 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3520 (unsigned int) ntohl (qsm->quota.value__),
3521 (unsigned int) n->in_tracker.available_bytes_per_s__,
3522 GNUNET_i2s (&qsm->peer));
3524 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3526 if (0 == ntohl (qsm->quota.value__))
3527 disconnect_neighbour (n, GNUNET_NO);
3528 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3533 * Take the given address and append it to the set of results send back to
3536 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3537 * @param address the resolved name, NULL to indicate the last response
3540 transmit_address_to_client (void *cls, const char *address)
3542 struct GNUNET_SERVER_TransmitContext *tc = cls;
3545 if (NULL == address)
3548 slen = strlen (address) + 1;
3549 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3550 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3551 if (NULL == address)
3552 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3557 * Handle AddressLookup-message.
3559 * @param cls closure (always NULL)
3560 * @param client identification of the client
3561 * @param message the actual message
3564 handle_address_lookup (void *cls,
3565 struct GNUNET_SERVER_Client *client,
3566 const struct GNUNET_MessageHeader *message)
3568 const struct AddressLookupMessage *alum;
3569 struct TransportPlugin *lsPlugin;
3570 const char *nameTransport;
3571 const char *address;
3573 struct GNUNET_SERVER_TransmitContext *tc;
3574 struct GNUNET_TIME_Absolute timeout;
3575 struct GNUNET_TIME_Relative rtimeout;
3578 size = ntohs (message->size);
3579 if (size < sizeof (struct AddressLookupMessage))
3581 GNUNET_break_op (0);
3582 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3585 alum = (const struct AddressLookupMessage *) message;
3586 uint32_t addressLen = ntohl (alum->addrlen);
3587 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3589 GNUNET_break_op (0);
3590 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3593 address = (const char *) &alum[1];
3594 nameTransport = (const char *) &address[addressLen];
3596 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3598 GNUNET_break_op (0);
3599 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3602 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
3603 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
3604 numeric = ntohl (alum->numeric_only);
3605 lsPlugin = find_transport (nameTransport);
3606 if (NULL == lsPlugin)
3608 tc = GNUNET_SERVER_transmit_context_create (client);
3609 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3610 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3611 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3614 tc = GNUNET_SERVER_transmit_context_create (client);
3615 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
3617 address, addressLen,
3620 &transmit_address_to_client, tc);
3624 * List of handlers for the messages understood by this
3627 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3628 {&handle_start, NULL,
3629 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3630 {&handle_hello, NULL,
3631 GNUNET_MESSAGE_TYPE_HELLO, 0},
3632 {&handle_send, NULL,
3633 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3634 {&handle_set_quota, NULL,
3635 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3636 {&handle_address_lookup, NULL,
3637 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3644 * Setup the environment for this plugin.
3647 create_environment (struct TransportPlugin *plug)
3649 plug->env.cfg = cfg;
3650 plug->env.sched = sched;
3651 plug->env.my_identity = &my_identity;
3652 plug->env.cls = plug;
3653 plug->env.receive = &plugin_env_receive;
3654 plug->env.notify_address = &plugin_env_notify_address;
3655 plug->env.session_end = &plugin_env_session_end;
3656 plug->env.max_connections = max_connect_per_transport;
3657 plug->env.stats = stats;
3662 * Start the specified transport (load the plugin).
3665 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
3667 struct TransportPlugin *plug;
3670 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3671 _("Loading `%s' transport plugin\n"), name);
3672 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3673 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3674 create_environment (plug);
3675 plug->short_name = GNUNET_strdup (name);
3676 plug->lib_name = libname;
3677 plug->next = plugins;
3679 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3680 if (plug->api == NULL)
3682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3683 _("Failed to load transport plugin for `%s'\n"), name);
3684 GNUNET_free (plug->short_name);
3685 plugins = plug->next;
3686 GNUNET_free (libname);
3693 * Called whenever a client is disconnected. Frees our
3694 * resources associated with that client.
3696 * @param cls closure
3697 * @param client identification of the client
3700 client_disconnect_notification (void *cls,
3701 struct GNUNET_SERVER_Client *client)
3703 struct TransportClient *pos;
3704 struct TransportClient *prev;
3705 struct ClientMessageQueueEntry *mqe;
3710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3711 "Client disconnected, cleaning up.\n");
3715 while ((pos != NULL) && (pos->client != client))
3722 while (NULL != (mqe = pos->message_queue_head))
3724 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3725 pos->message_queue_tail,
3727 pos->message_count--;
3731 clients = pos->next;
3733 prev->next = pos->next;
3734 if (GNUNET_YES == pos->tcs_pending)
3739 if (pos->th != NULL)
3741 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3744 GNUNET_break (0 == pos->message_count);
3750 * Iterator to free entries in the validation_map.
3752 * @param cls closure (unused)
3753 * @param key current key code
3754 * @param value value in the hash map (validation to abort)
3755 * @return GNUNET_YES (always)
3758 abort_validation (void *cls,
3759 const GNUNET_HashCode * key,
3762 struct ValidationEntry *va = value;
3764 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3765 GNUNET_free (va->transport_name);
3772 * Function called when the service shuts down. Unloads our plugins
3773 * and cancels pending validations.
3775 * @param cls closure, unused
3776 * @param tc task context (unused)
3779 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3781 struct TransportPlugin *plug;
3782 struct OwnAddressList *al;
3783 struct CheckHelloValidatedContext *chvc;
3785 while (neighbours != NULL)
3786 disconnect_neighbour (neighbours, GNUNET_NO);
3788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3789 "Transport service is unloading plugins...\n");
3791 while (NULL != (plug = plugins))
3793 plugins = plug->next;
3794 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
3796 GNUNET_SCHEDULER_cancel (plug->env.sched,
3797 plug->address_update_task);
3798 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
3800 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3801 GNUNET_free (plug->lib_name);
3802 GNUNET_free (plug->short_name);
3803 while (NULL != (al = plug->addresses))
3805 plug->addresses = al->next;
3810 if (my_private_key != NULL)
3811 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3812 GNUNET_free_non_null (our_hello);
3814 /* free 'chvc' data structure */
3815 while (NULL != (chvc = chvc_head))
3817 chvc_head = chvc->next;
3818 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3823 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3826 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3827 validation_map = NULL;
3830 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3837 * Initiate transport service.
3839 * @param cls closure
3840 * @param s scheduler to use
3841 * @param serv the initialized server
3842 * @param c configuration to use
3846 struct GNUNET_SCHEDULER_Handle *s,
3847 struct GNUNET_SERVER_Handle *serv,
3848 const struct GNUNET_CONFIGURATION_Handle *c)
3853 unsigned long long tneigh;
3858 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3859 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3860 /* parse configuration */
3862 GNUNET_CONFIGURATION_get_value_number (c,
3867 GNUNET_CONFIGURATION_get_value_filename (c,
3869 "HOSTKEY", &keyfile)))
3871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3873 ("Transport service is lacking key configuration settings. Exiting.\n"));
3874 GNUNET_SCHEDULER_shutdown (s);
3877 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3880 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3881 validation_map = NULL;
3884 max_connect_per_transport = (uint32_t) tneigh;
3885 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3886 GNUNET_free (keyfile);
3887 if (my_private_key == NULL)
3889 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3891 ("Transport service could not access hostkey. Exiting.\n"));
3892 GNUNET_SCHEDULER_shutdown (s);
3895 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3898 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3899 validation_map = NULL;
3902 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3903 GNUNET_CRYPTO_hash (&my_public_key,
3904 sizeof (my_public_key), &my_identity.hashPubKey);
3905 /* setup notification */
3907 GNUNET_SERVER_disconnect_notify (server,
3908 &client_disconnect_notification, NULL);
3909 /* load plugins... */
3912 GNUNET_CONFIGURATION_get_value_string (c,
3913 "TRANSPORT", "PLUGINS", &plugs))
3915 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3916 _("Starting transport plugins `%s'\n"), plugs);
3917 pos = strtok (plugs, " ");
3920 start_transport (server, pos);
3922 pos = strtok (NULL, " ");
3924 GNUNET_free (plugs);
3926 GNUNET_SCHEDULER_add_delayed (sched,
3927 GNUNET_TIME_UNIT_FOREVER_REL,
3928 &shutdown_task, NULL);
3933 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3935 /* process client requests */
3936 GNUNET_SERVER_add_handlers (server, handlers);
3941 * The main function for the transport service.
3943 * @param argc number of arguments from the command line
3944 * @param argv command line arguments
3945 * @return 0 ok, 1 on error
3948 main (int argc, char *const *argv)
3950 return (GNUNET_OK ==
3951 GNUNET_SERVICE_run (argc,
3954 GNUNET_SERVICE_OPTION_NONE,
3955 &run, NULL)) ? 0 : 1;
3958 /* end of gnunet-service-transport.c */