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 * - bi-directional nature of TCP is not exploited
30 * - This code uses 'GNUNET_a2s' for debug printing in many places,
31 * which is technically wrong since it assumes we have IP+Port
32 * (v4/v6) addresses. Once we add transports like http or smtp
33 * this will have to be changed!
36 #include "gnunet_client_lib.h"
37 #include "gnunet_container_lib.h"
38 #include "gnunet_constants.h"
39 #include "gnunet_getopt_lib.h"
40 #include "gnunet_hello_lib.h"
41 #include "gnunet_os_lib.h"
42 #include "gnunet_peerinfo_service.h"
43 #include "gnunet_plugin_lib.h"
44 #include "gnunet_protocols.h"
45 #include "gnunet_service_lib.h"
46 #include "gnunet_signatures.h"
47 #include "plugin_transport.h"
48 #include "transport.h"
51 * Should we do some additional checks (to validate behavior
54 #define EXTRA_CHECKS GNUNET_YES
57 * How many messages can we have pending for a given client process
58 * before we start to drop incoming messages? We typically should
59 * have only one client and so this would be the primary buffer for
60 * messages, so the number should be chosen rather generously.
62 * The expectation here is that most of the time the queue is large
63 * enough so that a drop is virtually never required.
65 #define MAX_PENDING 128
68 * How often should we try to reconnect to a peer using a particular
69 * transport plugin before giving up? Note that the plugin may be
70 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
72 #define MAX_CONNECT_RETRY 3
75 * Limit on the number of ready-to-run tasks when validating
76 * HELLOs. If more tasks are ready to run, we will drop
77 * HELLOs instead of validating them.
79 #define MAX_HELLO_LOAD 4
82 * How often must a peer violate bandwidth quotas before we start
83 * to simply drop its messages?
85 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
88 * How long until a HELLO verification attempt should time out?
89 * Must be rather small, otherwise a partially successful HELLO
90 * validation (some addresses working) might not be available
91 * before a client's request for a connection fails for good.
92 * Besides, if a single request to an address takes a long time,
93 * then the peer is unlikely worthwhile anyway.
95 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
98 * How long will we allow sending of a ping to be delayed?
100 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
103 * Priority to use for PONG messages.
105 #define TRANSPORT_PONG_PRIORITY 4
108 * How often do we re-add (cheaper) plugins to our list of plugins
109 * to try for a given connected peer?
111 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
114 * After how long do we expire an address in a HELLO that we just
115 * validated? This value is also used for our own addresses when we
118 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
122 * How long before an existing address expires should we again try to
123 * validate it? Must be (significantly) smaller than
124 * HELLO_ADDRESS_EXPIRATION.
126 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
129 * Maximum frequency for re-evaluating latencies for all transport addresses.
131 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
134 * Maximum frequency for re-evaluating latencies for connected addresses.
136 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
140 * List of addresses of other peers
142 struct ForeignAddressList
145 * This is a linked list.
147 struct ForeignAddressList *next;
150 * Which ready list does this entry belong to.
152 struct ReadyList *ready_list;
155 * How long until we auto-expire this address (unless it is
156 * re-confirmed by the transport)?
158 struct GNUNET_TIME_Absolute expires;
161 * Task used to re-validate addresses, updates latencies and
164 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
177 * What was the last latency observed for this address, plugin and peer?
179 struct GNUNET_TIME_Relative latency;
182 * If we did not successfully transmit a message to the given peer
183 * via this connection during the specified time, we should consider
184 * the connection to be dead. This is used in the case that a TCP
185 * transport simply stalls writing to the stream but does not
186 * formerly get a signal that the other peer died.
188 struct GNUNET_TIME_Absolute timeout;
191 * How often have we tried to connect using this plugin? Used to
192 * discriminate against addresses that do not work well.
193 * FIXME: not yet used, but should be!
195 unsigned int connect_attempts;
198 * DV distance to this peer (1 if no DV is used).
199 * FIXME: need to set this from transport plugins!
204 * Have we ever estimated the latency of this address? Used to
205 * ensure that the first time we add an address, we immediately
211 * Are we currently connected via this address? The first time we
212 * successfully transmit or receive data to a peer via a particular
213 * address, we set this to GNUNET_YES. If we later get an error
214 * (disconnect notification, transmission failure, timeout), we set
215 * it back to GNUNET_NO.
220 * Is this plugin currently busy transmitting to the specific target?
221 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
222 * messages do not count as 'in transmit'.
227 * Has this address been validated yet?
235 * Entry in linked list of network addresses for ourselves.
237 struct OwnAddressList
240 * This is a linked list.
242 struct OwnAddressList *next;
245 * The address, actually a pointer to the end
246 * of this struct. Do not free!
251 * How long until we auto-expire this address (unless it is
252 * re-confirmed by the transport)?
254 struct GNUNET_TIME_Absolute expires;
265 * Entry in linked list of all of our plugins.
267 struct TransportPlugin
271 * This is a linked list.
273 struct TransportPlugin *next;
276 * API of the transport as returned by the plugin's
277 * initialization function.
279 struct GNUNET_TRANSPORT_PluginFunctions *api;
282 * Short name for the plugin (i.e. "tcp").
287 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
292 * List of our known addresses for this transport.
294 struct OwnAddressList *addresses;
297 * Environment this transport service is using
300 struct GNUNET_TRANSPORT_PluginEnvironment env;
303 * ID of task that is used to clean up expired addresses.
305 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
308 * Set to GNUNET_YES if we need to scrap the existing list of
309 * "addresses" and start fresh when we receive the next address
310 * update from a transport. Set to GNUNET_NO if we should just add
311 * the new address to the list and wait for the commit call.
317 struct NeighbourList;
320 * For each neighbour we keep a list of messages
321 * that we still want to transmit to the neighbour.
327 * This is a doubly linked list.
329 struct MessageQueue *next;
332 * This is a doubly linked list.
334 struct MessageQueue *prev;
337 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
338 * stuck together in memory. Allocated at the end of this struct.
340 const char *message_buf;
343 * Size of the message buf
345 size_t message_buf_size;
348 * Client responsible for queueing the message;
349 * used to check that a client has no two messages
350 * pending for the same target. Can be NULL.
352 struct TransportClient *client;
355 * Using which specific address should we send this message?
357 struct ForeignAddressList *specific_address;
360 * Peer ID of the Neighbour this entry belongs to.
362 struct GNUNET_PeerIdentity neighbour_id;
365 * Plugin that we used for the transmission.
366 * NULL until we scheduled a transmission.
368 struct TransportPlugin *plugin;
371 * At what time should we fail?
373 struct GNUNET_TIME_Absolute timeout;
376 * Internal message of the transport system that should not be
377 * included in the usual SEND-SEND_OK transmission confirmation
378 * traffic management scheme. Typically, "internal_msg" will
379 * be set whenever "client" is NULL (but it is not strictly
385 * How important is the message?
387 unsigned int priority;
393 * For a given Neighbour, which plugins are available
394 * to talk to this peer and what are their costs?
399 * This is a linked list.
401 struct ReadyList *next;
404 * Which of our transport plugins does this entry
407 struct TransportPlugin *plugin;
410 * Transport addresses, latency, and readiness for
411 * this particular plugin.
413 struct ForeignAddressList *addresses;
416 * To which neighbour does this ready list belong to?
418 struct NeighbourList *neighbour;
424 * Entry in linked list of all of our current neighbours.
430 * This is a linked list.
432 struct NeighbourList *next;
435 * Which of our transports is connected to this peer
436 * and what is their status?
438 struct ReadyList *plugins;
441 * Head of list of messages we would like to send to this peer;
442 * must contain at most one message per client.
444 struct MessageQueue *messages_head;
447 * Tail of list of messages we would like to send to this peer; must
448 * contain at most one message per client.
450 struct MessageQueue *messages_tail;
453 * Context for peerinfo iteration.
454 * NULL after we are done processing peerinfo's information.
456 struct GNUNET_PEERINFO_IteratorContext *piter;
459 * Public key for this peer. Valid only if the respective flag is set below.
461 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
464 * Identity of this neighbour.
466 struct GNUNET_PeerIdentity id;
469 * ID of task scheduled to run when this peer is about to
470 * time out (will free resources associated with the peer).
472 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
475 * ID of task scheduled to run when we should retry transmitting
476 * the head of the message queue. Actually triggered when the
477 * transmission is timing out (we trigger instantly when we have
478 * a chance of success).
480 GNUNET_SCHEDULER_TaskIdentifier retry_task;
483 * How long until we should consider this peer dead
484 * (if we don't receive another message in the
487 struct GNUNET_TIME_Absolute peer_timeout;
490 * Tracker for inbound bandwidth.
492 struct GNUNET_BANDWIDTH_Tracker in_tracker;
495 * The latency we have seen for this particular address for
496 * this particular peer. This latency may have been calculated
497 * over multiple transports. This value reflects how long it took
498 * us to receive a response when SENDING via this particular
499 * transport/neighbour/address combination!
501 * FIXME: we need to periodically send PINGs to update this
502 * latency (at least more often than the current "huge" (11h?)
505 struct GNUNET_TIME_Relative latency;
508 * How often has the other peer (recently) violated the
509 * inbound traffic limit? Incremented by 10 per violation,
510 * decremented by 1 per non-violation (for each
513 unsigned int quota_violation_count;
516 * DV distance to this peer (1 if no DV is used).
521 * Have we seen an PONG from this neighbour in the past (and
522 * not had a disconnect since)?
527 * Do we have a valid public key for this neighbour?
529 int public_key_valid;
534 * Message used to ask a peer to validate receipt (to check an address
537 struct TransportPingMessage
541 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
543 struct GNUNET_MessageHeader header;
546 * Random challenge number (in network byte order).
548 uint32_t challenge GNUNET_PACKED;
551 * Who is the intended recipient?
553 struct GNUNET_PeerIdentity target;
559 * Message used to validate a HELLO. The challenge is included in the
560 * confirmation to make matching of replies to requests possible. The
561 * signature signs the original challenge number, our public key, the
562 * sender's address (so that the sender can check that the address we
563 * saw is plausible for him and possibly detect a MiM attack) and a
564 * timestamp (to limit replay).<p>
566 * This message is followed by the address of the
567 * client that we are observing (which is part of what
570 struct TransportPongMessage
574 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
576 struct GNUNET_MessageHeader header;
579 * For padding, always zero.
581 uint32_t reserved GNUNET_PACKED;
586 struct GNUNET_CRYPTO_RsaSignature signature;
589 * What are we signing and why?
591 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
594 * Random challenge number (in network byte order).
596 uint32_t challenge GNUNET_PACKED;
599 * Who signed this message?
601 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
604 * Size of address appended to this message
612 * Linked list of messages to be transmitted to the client. Each
613 * entry is followed by the actual message.
615 struct ClientMessageQueueEntry
618 * This is a doubly-linked list.
620 struct ClientMessageQueueEntry *next;
623 * This is a doubly-linked list.
625 struct ClientMessageQueueEntry *prev;
630 * Client connected to the transport service.
632 struct TransportClient
636 * This is a linked list.
638 struct TransportClient *next;
641 * Handle to the client.
643 struct GNUNET_SERVER_Client *client;
646 * Linked list of messages yet to be transmitted to
649 struct ClientMessageQueueEntry *message_queue_head;
652 * Tail of linked list of messages yet to be transmitted to the
655 struct ClientMessageQueueEntry *message_queue_tail;
658 * Current transmit request handle.
660 struct GNUNET_CONNECTION_TransmitHandle *th;
663 * Is a call to "transmit_send_continuation" pending? If so, we
664 * must not free this struct (even if the corresponding client
665 * disconnects) and instead only remove it from the linked list and
666 * set the "client" field to NULL.
671 * Length of the list of messages pending for this client.
673 unsigned int message_count;
679 * Entry in map of all HELLOs awaiting validation.
681 struct ValidationEntry
685 * The address, actually a pointer to the end
686 * of this struct. Do not free!
691 * Name of the transport.
693 char *transport_name;
696 * The public key of the peer.
698 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
701 * ID of task that will clean up this entry if we don't succeed
702 * with the validation first.
704 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
707 * At what time did we send this validation?
709 struct GNUNET_TIME_Absolute send_time;
717 * Challenge number we used.
725 * Context of currently active requests to peerinfo
726 * for validation of HELLOs.
728 struct CheckHelloValidatedContext
732 * This is a doubly-linked list.
734 struct CheckHelloValidatedContext *next;
737 * This is a doubly-linked list.
739 struct CheckHelloValidatedContext *prev;
742 * Hello that we are validating.
744 const struct GNUNET_HELLO_Message *hello;
747 * Context for peerinfo iteration.
748 * NULL after we are done processing peerinfo's information.
750 struct GNUNET_PEERINFO_IteratorContext *piter;
753 * Was a HELLO known for this peer to peerinfo?
763 static struct GNUNET_HELLO_Message *our_hello;
766 * "version" of "our_hello". Used to see if a given neighbour has
767 * already been sent the latest version of our HELLO message.
769 static unsigned int our_hello_version;
774 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
779 static struct GNUNET_PeerIdentity my_identity;
784 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
789 struct GNUNET_SCHEDULER_Handle *sched;
794 const struct GNUNET_CONFIGURATION_Handle *cfg;
797 * Linked list of all clients to this service.
799 static struct TransportClient *clients;
802 * All loaded plugins.
804 static struct TransportPlugin *plugins;
809 static struct GNUNET_SERVER_Handle *server;
812 * All known neighbours and their HELLOs.
814 static struct NeighbourList *neighbours;
817 * Number of neighbours we'd like to have.
819 static uint32_t max_connect_per_transport;
822 * Head of linked list.
824 static struct CheckHelloValidatedContext *chvc_head;
827 * Tail of linked list.
829 static struct CheckHelloValidatedContext *chvc_tail;
832 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
833 * of the given peer that we are currently validating).
835 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
838 * Handle for reporting statistics.
840 static struct GNUNET_STATISTICS_Handle *stats;
844 * The peer specified by the given neighbour has timed-out or a plugin
845 * has disconnected. We may either need to do nothing (other plugins
846 * still up), or trigger a full disconnect and clean up. This
847 * function updates our state and do the necessary notifications.
848 * Also notifies our clients that the neighbour is now officially
851 * @param n the neighbour list entry for the peer
852 * @param check should we just check if all plugins
853 * disconnected or must we ask all plugins to
856 static void disconnect_neighbour (struct NeighbourList *n, int check);
859 * Check the ready list for the given neighbour and if a plugin is
860 * ready for transmission (and if we have a message), do so!
862 * @param neighbour target peer for which to transmit
864 static void try_transmission_to_peer (struct NeighbourList *neighbour);
868 * Find an entry in the neighbour list for a particular peer.
869 * if sender_address is not specified (NULL) then return the
870 * first matching entry. If sender_address is specified, then
871 * make sure that the address and address_len also matches.
873 * FIXME: This description does not fit the function.
875 * @return NULL if not found.
877 static struct NeighbourList *
878 find_neighbour (const struct GNUNET_PeerIdentity *key)
880 struct NeighbourList *head = neighbours;
882 while ((head != NULL) &&
883 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
890 * Find an entry in the transport list for a particular transport.
892 * @return NULL if not found.
894 static struct TransportPlugin *
895 find_transport (const char *short_name)
897 struct TransportPlugin *head = plugins;
898 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
905 * Function called to notify a client about the socket being ready to
906 * queue more data. "buf" will be NULL and "size" zero if the socket
907 * was closed for writing in the meantime.
910 * @param size number of bytes available in buf
911 * @param buf where the callee should write the message
912 * @return number of bytes written to buf
915 transmit_to_client_callback (void *cls, size_t size, void *buf)
917 struct TransportClient *client = cls;
918 struct ClientMessageQueueEntry *q;
921 const struct GNUNET_MessageHeader *msg;
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "Transmission to client failed, closing connection.\n");
929 /* fatal error with client, free message queue! */
930 while (NULL != (q = client->message_queue_head))
932 GNUNET_STATISTICS_update (stats,
933 gettext_noop ("# bytes discarded (could not transmit to client)"),
934 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
936 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
937 client->message_queue_tail,
941 client->message_count = 0;
946 while (NULL != (q = client->message_queue_head))
948 msg = (const struct GNUNET_MessageHeader *) &q[1];
949 msize = ntohs (msg->size);
950 if (msize + tsize > size)
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "Transmitting message of type %u to client.\n",
957 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
958 client->message_queue_tail,
960 memcpy (&cbuf[tsize], msg, msize);
963 client->message_count--;
967 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
968 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
970 GNUNET_TIME_UNIT_FOREVER_REL,
971 &transmit_to_client_callback,
973 GNUNET_assert (client->th != NULL);
980 * Send the specified message to the specified client. Since multiple
981 * messages may be pending for the same client at a time, this code
982 * makes sure that no message is lost.
984 * @param client client to transmit the message to
985 * @param msg the message to send
986 * @param may_drop can this message be dropped if the
987 * message queue for this client is getting far too large?
990 transmit_to_client (struct TransportClient *client,
991 const struct GNUNET_MessageHeader *msg, int may_drop)
993 struct ClientMessageQueueEntry *q;
996 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
998 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1000 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1001 client->message_count, MAX_PENDING);
1002 /* TODO: call to statistics... */
1005 msize = ntohs (msg->size);
1006 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1007 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1008 memcpy (&q[1], msg, msize);
1009 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1010 client->message_queue_tail,
1011 client->message_queue_tail,
1013 client->message_count++;
1014 if (client->th == NULL)
1016 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1018 GNUNET_TIME_UNIT_FOREVER_REL,
1019 &transmit_to_client_callback,
1021 GNUNET_assert (client->th != NULL);
1027 * Transmit a 'SEND_OK' notification to the given client for the
1030 * @param client who to notify
1031 * @param n neighbour to notify about
1032 * @param result status code for the transmission request
1035 transmit_send_ok (struct TransportClient *client,
1036 struct NeighbourList *n,
1039 struct SendOkMessage send_ok_msg;
1041 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1042 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1043 send_ok_msg.success = htonl (result);
1044 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1045 send_ok_msg.peer = n->id;
1046 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1051 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1052 * upon "completion" of a send request. This tells the API
1053 * that it is now legal to send another message to the given
1056 * @param cls closure, identifies the entry on the
1057 * message queue that was transmitted and the
1058 * client responsible for queueing the message
1059 * @param target the peer receiving the message
1060 * @param result GNUNET_OK on success, if the transmission
1061 * failed, we should not tell the client to transmit
1065 transmit_send_continuation (void *cls,
1066 const struct GNUNET_PeerIdentity *target,
1069 struct MessageQueue *mq = cls;
1070 struct NeighbourList *n;
1072 GNUNET_STATISTICS_update (stats,
1073 gettext_noop ("# bytes pending with plugins"),
1074 - (int64_t) mq->message_buf_size,
1076 if (result == GNUNET_OK)
1078 GNUNET_STATISTICS_update (stats,
1079 gettext_noop ("# bytes successfully transmitted by plugins"),
1080 mq->message_buf_size,
1085 GNUNET_STATISTICS_update (stats,
1086 gettext_noop ("# bytes with transmission failure by plugins"),
1087 mq->message_buf_size,
1090 n = find_neighbour(&mq->neighbour_id);
1091 GNUNET_assert (n != NULL);
1092 if (mq->specific_address != NULL)
1094 if (result == GNUNET_OK)
1096 mq->specific_address->timeout =
1097 GNUNET_TIME_relative_to_absolute
1098 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1099 if (mq->specific_address->connected != GNUNET_YES)
1101 GNUNET_STATISTICS_update (stats,
1102 gettext_noop ("# connected addresses"),
1105 mq->specific_address->connected = GNUNET_YES;
1110 if (mq->specific_address->connected != GNUNET_NO)
1112 GNUNET_STATISTICS_update (stats,
1113 gettext_noop ("# connected addresses"),
1116 mq->specific_address->connected = GNUNET_NO;
1119 if (! mq->internal_msg)
1120 mq->specific_address->in_transmit = GNUNET_NO;
1122 if (mq->client != NULL)
1123 transmit_send_ok (mq->client, n, result);
1125 try_transmission_to_peer (n);
1130 * Find an address in any of the available transports for
1131 * the given neighbour that would be good for message
1132 * transmission. This is essentially the transport selection
1135 * @param neighbour for whom to select an address
1136 * @return selected address, NULL if we have none
1138 struct ForeignAddressList *
1139 find_ready_address(struct NeighbourList *neighbour)
1141 struct ReadyList *head = neighbour->plugins;
1142 struct ForeignAddressList *addresses;
1143 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1144 struct ForeignAddressList *best_address;
1146 best_address = NULL;
1147 while (head != NULL)
1149 addresses = head->addresses;
1150 while (addresses != NULL)
1152 if ( (addresses->timeout.value < now.value) &&
1153 (addresses->connected == GNUNET_YES) )
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 "Marking long-time inactive connection to `%4s' as down.\n",
1158 GNUNET_i2s (&neighbour->id));
1160 GNUNET_STATISTICS_update (stats,
1161 gettext_noop ("# connected addresses"),
1164 addresses->connected = GNUNET_NO;
1166 addresses = addresses->next;
1169 addresses = head->addresses;
1170 while (addresses != NULL)
1172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1174 GNUNET_a2s (addresses->addr,
1175 addresses->addrlen),
1176 GNUNET_i2s (&neighbour->id),
1177 addresses->connected,
1178 addresses->in_transmit,
1179 addresses->validated,
1180 addresses->connect_attempts,
1181 (unsigned long long) addresses->timeout.value,
1182 (unsigned int) addresses->distance);
1183 if ( ( (best_address == NULL) ||
1184 (addresses->connected == GNUNET_YES) ||
1185 (best_address->connected == GNUNET_NO) ) &&
1186 (addresses->in_transmit == GNUNET_NO) &&
1187 ( (best_address == NULL) ||
1188 (addresses->latency.value < best_address->latency.value)) )
1189 best_address = addresses;
1190 /* FIXME: also give lower-latency addresses that are not
1191 connected a chance some times... */
1192 addresses = addresses->next;
1196 if (best_address != NULL)
1199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1200 "Best address found has latency of %llu ms.\n",
1201 best_address->latency.value);
1206 GNUNET_STATISTICS_update (stats,
1207 gettext_noop ("# transmission attempts failed (no address)"),
1211 return best_address;
1217 * We should re-try transmitting to the given peer,
1218 * hopefully we've learned something in the meantime.
1221 retry_transmission_task (void *cls,
1222 const struct GNUNET_SCHEDULER_TaskContext *tc)
1224 struct NeighbourList *n = cls;
1226 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1227 try_transmission_to_peer (n);
1232 * Check the ready list for the given neighbour and if a plugin is
1233 * ready for transmission (and if we have a message), do so!
1235 * @param neighbour target peer for which to transmit
1238 try_transmission_to_peer (struct NeighbourList *neighbour)
1240 struct ReadyList *rl;
1241 struct MessageQueue *mq;
1242 struct GNUNET_TIME_Relative timeout;
1245 if (neighbour->messages_head == NULL)
1247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1248 "Transmission queue for `%4s' is empty\n",
1249 GNUNET_i2s (&neighbour->id));
1250 return; /* nothing to do */
1253 mq = neighbour->messages_head;
1254 /* FIXME: support bi-directional use of TCP */
1255 if (mq->specific_address == NULL)
1257 mq->specific_address = find_ready_address(neighbour);
1258 GNUNET_STATISTICS_update (stats,
1259 gettext_noop ("# transport selected peer address freely"),
1263 if (mq->specific_address == NULL)
1265 GNUNET_STATISTICS_update (stats,
1266 gettext_noop ("# transport failed to selected peer address"),
1269 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1270 if (timeout.value == 0)
1273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1274 "No destination address available to transmit message of size %u to peer `%4s'\n",
1275 mq->message_buf_size,
1276 GNUNET_i2s (&mq->neighbour_id));
1278 GNUNET_STATISTICS_update (stats,
1279 gettext_noop ("# bytes in message queue for other peers"),
1280 - (int64_t) mq->message_buf_size,
1282 GNUNET_STATISTICS_update (stats,
1283 gettext_noop ("# bytes discarded (no destination address available)"),
1284 mq->message_buf_size,
1286 if (mq->client != NULL)
1287 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1288 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1289 neighbour->messages_tail,
1292 return; /* nobody ready */
1294 GNUNET_STATISTICS_update (stats,
1295 gettext_noop ("# message delivery deferred (no address)"),
1298 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1299 GNUNET_SCHEDULER_cancel (sched,
1300 neighbour->retry_task);
1301 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1303 &retry_transmission_task,
1306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1308 mq->message_buf_size,
1309 GNUNET_i2s (&mq->neighbour_id),
1312 /* FIXME: might want to trigger peerinfo lookup here
1313 (unless that's already pending...) */
1316 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1317 neighbour->messages_tail,
1319 if (mq->specific_address->connected == GNUNET_NO)
1320 mq->specific_address->connect_attempts++;
1321 rl = mq->specific_address->ready_list;
1322 mq->plugin = rl->plugin;
1323 if (!mq->internal_msg)
1324 mq->specific_address->in_transmit = GNUNET_YES;
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1328 mq->message_buf_size,
1329 GNUNET_i2s (&neighbour->id),
1330 GNUNET_a2s (mq->specific_address->addr,
1331 mq->specific_address->addrlen),
1332 rl->plugin->short_name);
1334 GNUNET_STATISTICS_update (stats,
1335 gettext_noop ("# bytes in message queue for other peers"),
1336 - (int64_t) mq->message_buf_size,
1338 GNUNET_STATISTICS_update (stats,
1339 gettext_noop ("# bytes pending with plugins"),
1340 mq->message_buf_size,
1342 ret = rl->plugin->api->send (rl->plugin->api->cls,
1345 mq->message_buf_size,
1347 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1348 mq->specific_address->addr,
1349 mq->specific_address->addrlen,
1350 GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1351 &transmit_send_continuation, mq);
1354 /* failure, but 'send' would not call continuation in this case,
1355 so we need to do it here! */
1356 transmit_send_continuation (mq,
1364 * Send the specified message to the specified peer.
1366 * @param client source of the transmission request (can be NULL)
1367 * @param peer_address ForeignAddressList where we should send this message
1368 * @param priority how important is the message
1369 * @param timeout how long do we have to transmit?
1370 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1371 * @param message_buf_size total size of all messages in message_buf
1372 * @param is_internal is this an internal message; these are pre-pended and
1373 * also do not count for plugins being "ready" to transmit
1374 * @param neighbour handle to the neighbour for transmission
1377 transmit_to_peer (struct TransportClient *client,
1378 struct ForeignAddressList *peer_address,
1379 unsigned int priority,
1380 struct GNUNET_TIME_Relative timeout,
1381 const char *message_buf,
1382 size_t message_buf_size,
1383 int is_internal, struct NeighbourList *neighbour)
1385 struct MessageQueue *mq;
1390 /* check for duplicate submission */
1391 mq = neighbour->messages_head;
1394 if (mq->client == client)
1396 /* client transmitted to same peer twice
1397 before getting SEND_OK! */
1405 GNUNET_STATISTICS_update (stats,
1406 gettext_noop ("# bytes in message queue for other peers"),
1409 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1410 mq->specific_address = peer_address;
1411 mq->client = client;
1412 memcpy (&mq[1], message_buf, message_buf_size);
1413 mq->message_buf = (const char*) &mq[1];
1414 mq->message_buf_size = message_buf_size;
1415 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1416 mq->internal_msg = is_internal;
1417 mq->priority = priority;
1418 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1420 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1421 neighbour->messages_tail,
1424 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1425 neighbour->messages_tail,
1426 neighbour->messages_tail,
1428 try_transmission_to_peer (neighbour);
1435 struct GeneratorContext
1437 struct TransportPlugin *plug_pos;
1438 struct OwnAddressList *addr_pos;
1439 struct GNUNET_TIME_Absolute expiration;
1447 address_generator (void *cls, size_t max, void *buf)
1449 struct GeneratorContext *gc = cls;
1452 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1454 gc->plug_pos = gc->plug_pos->next;
1455 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1457 if (NULL == gc->plug_pos)
1462 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1465 gc->addr_pos->addrlen, buf, max);
1466 gc->addr_pos = gc->addr_pos->next;
1472 * Construct our HELLO message from all of the addresses of
1473 * all of the transports.
1478 struct GNUNET_HELLO_Message *hello;
1479 struct TransportClient *cpos;
1480 struct NeighbourList *npos;
1481 struct GeneratorContext gc;
1483 gc.plug_pos = plugins;
1484 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1485 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1486 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1489 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1491 GNUNET_STATISTICS_update (stats,
1492 gettext_noop ("# refreshed my HELLO"),
1496 while (cpos != NULL)
1498 transmit_to_client (cpos,
1499 (const struct GNUNET_MessageHeader *) hello,
1504 GNUNET_free_non_null (our_hello);
1506 our_hello_version++;
1507 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1509 while (npos != NULL)
1512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1513 "Transmitting updated `%s' to neighbour `%4s'\n",
1514 "HELLO", GNUNET_i2s (&npos->id));
1516 GNUNET_STATISTICS_update (stats,
1517 gettext_noop ("# transmitted my HELLO to other peers"),
1520 transmit_to_peer (NULL, NULL, 0,
1521 HELLO_ADDRESS_EXPIRATION,
1522 (const char *) our_hello,
1523 GNUNET_HELLO_size(our_hello),
1531 * Task used to clean up expired addresses for a plugin.
1533 * @param cls closure
1537 expire_address_task (void *cls,
1538 const struct GNUNET_SCHEDULER_TaskContext *tc);
1542 * Update the list of addresses for this plugin,
1543 * expiring those that are past their expiration date.
1545 * @param plugin addresses of which plugin should be recomputed?
1546 * @param fresh set to GNUNET_YES if a new address was added
1547 * and we need to regenerate the HELLO even if nobody
1551 update_addresses (struct TransportPlugin *plugin, int fresh)
1553 struct GNUNET_TIME_Relative min_remaining;
1554 struct GNUNET_TIME_Relative remaining;
1555 struct GNUNET_TIME_Absolute now;
1556 struct OwnAddressList *pos;
1557 struct OwnAddressList *prev;
1558 struct OwnAddressList *next;
1561 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1562 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1563 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1564 now = GNUNET_TIME_absolute_get ();
1565 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1566 expired = GNUNET_NO;
1568 pos = plugin->addresses;
1572 if (pos->expires.value < now.value)
1574 expired = GNUNET_YES;
1576 plugin->addresses = pos->next;
1578 prev->next = pos->next;
1585 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1586 if (remaining.value < min_remaining.value)
1587 min_remaining = remaining;
1593 if (expired || fresh)
1595 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1596 plugin->address_update_task
1597 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1599 &expire_address_task, plugin);
1605 * Task used to clean up expired addresses for a plugin.
1607 * @param cls closure
1611 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1613 struct TransportPlugin *plugin = cls;
1614 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1615 update_addresses (plugin, GNUNET_NO);
1620 * Function that must be called by each plugin to notify the
1621 * transport service about the addresses under which the transport
1622 * provided by the plugin can be reached.
1624 * @param cls closure
1625 * @param name name of the transport that generated the address
1626 * @param addr one of the addresses of the host, NULL for the last address
1627 * the specific address format depends on the transport
1628 * @param addrlen length of the address
1629 * @param expires when should this address automatically expire?
1632 plugin_env_notify_address (void *cls,
1636 struct GNUNET_TIME_Relative expires)
1638 struct TransportPlugin *p = cls;
1639 struct OwnAddressList *al;
1640 struct GNUNET_TIME_Absolute abex;
1642 abex = GNUNET_TIME_relative_to_absolute (expires);
1643 GNUNET_assert (p == find_transport (name));
1648 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1650 if (al->expires.value < abex.value)
1657 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1659 al->next = p->addresses;
1662 al->addrlen = addrlen;
1663 memcpy (&al[1], addr, addrlen);
1664 update_addresses (p, GNUNET_YES);
1669 * Notify all of our clients about a peer connecting.
1672 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1673 struct GNUNET_TIME_Relative latency,
1676 struct ConnectInfoMessage cim;
1677 struct TransportClient *cpos;
1680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1681 "Notifying clients about connection from `%s'\n",
1684 GNUNET_STATISTICS_update (stats,
1685 gettext_noop ("# peers connected"),
1688 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1689 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1690 cim.distance = htonl (distance);
1691 cim.latency = GNUNET_TIME_relative_hton (latency);
1692 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1694 while (cpos != NULL)
1696 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1703 * Notify all of our clients about a peer disconnecting.
1706 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1708 struct DisconnectInfoMessage dim;
1709 struct TransportClient *cpos;
1712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1713 "Notifying clients about lost connection to `%s'\n",
1716 GNUNET_STATISTICS_update (stats,
1717 gettext_noop ("# peers connected"),
1720 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1721 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1722 dim.reserved = htonl (0);
1723 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1725 while (cpos != NULL)
1727 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1734 * Find a ForeignAddressList entry for the given neighbour
1735 * that matches the given address and transport.
1737 * @param neighbour which peer we care about
1738 * @param tname name of the transport plugin
1739 * @param addr binary address
1740 * @param addrlen length of addr
1741 * @return NULL if no such entry exists
1743 static struct ForeignAddressList *
1744 find_peer_address(struct NeighbourList *neighbour,
1749 struct ReadyList *head;
1750 struct ForeignAddressList *address_head;
1752 head = neighbour->plugins;
1753 while (head != NULL)
1755 if (0 == strcmp (tname, head->plugin->short_name))
1762 address_head = head->addresses;
1763 while ( (address_head != NULL) &&
1764 ( (address_head->addrlen != addrlen) ||
1765 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1766 address_head = address_head->next;
1767 return address_head;
1772 * Get the peer address struct for the given neighbour and
1773 * address. If it doesn't yet exist, create it.
1775 * @param neighbour which peer we care about
1776 * @param tname name of the transport plugin
1777 * @param addr binary address
1778 * @param addrlen length of addr
1779 * @return NULL if we do not have a transport plugin for 'tname'
1781 static struct ForeignAddressList *
1782 add_peer_address (struct NeighbourList *neighbour,
1787 struct ReadyList *head;
1788 struct ForeignAddressList *ret;
1790 ret = find_peer_address (neighbour, tname, addr, addrlen);
1793 head = neighbour->plugins;
1794 while (head != NULL)
1796 if (0 == strcmp (tname, head->plugin->short_name))
1802 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1803 ret->addr = (const char*) &ret[1];
1804 memcpy (&ret[1], addr, addrlen);
1805 ret->addrlen = addrlen;
1806 ret->expires = GNUNET_TIME_relative_to_absolute
1807 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1808 ret->latency = GNUNET_TIME_relative_get_forever();
1810 ret->timeout = GNUNET_TIME_relative_to_absolute
1811 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1812 ret->ready_list = head;
1813 ret->next = head->addresses;
1814 head->addresses = ret;
1820 * Closure for 'add_validated_address'.
1822 struct AddValidatedAddressContext
1825 * Entry that has been validated.
1827 const struct ValidationEntry *ve;
1830 * Flag set after we have added the address so
1831 * that we terminate the iteration next time.
1838 * Callback function used to fill a buffer of max bytes with a list of
1839 * addresses in the format used by HELLOs. Should use
1840 * "GNUNET_HELLO_add_address" as a helper function.
1842 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1843 * @param max maximum number of bytes that can be written to buf
1844 * @param buf where to write the address information
1845 * @return number of bytes written, 0 to signal the
1846 * end of the iteration.
1849 add_validated_address (void *cls,
1850 size_t max, void *buf)
1852 struct AddValidatedAddressContext *avac = cls;
1853 const struct ValidationEntry *ve = avac->ve;
1855 if (GNUNET_YES == avac->done)
1857 avac->done = GNUNET_YES;
1858 return GNUNET_HELLO_add_address (ve->transport_name,
1859 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1869 * Closure for 'check_address_exists'.
1871 struct CheckAddressExistsClosure
1874 * Address to check for.
1879 * Name of the transport.
1889 * Set to GNUNET_YES if the address exists.
1896 * Iterator over hash map entries. Checks if the given
1897 * validation entry is for the same address as what is given
1900 * @param cls the 'struct CheckAddressExistsClosure*'
1901 * @param key current key code (ignored)
1902 * @param value value in the hash map ('struct ValidationEntry')
1903 * @return GNUNET_YES if we should continue to
1904 * iterate (mismatch), GNUNET_NO if not (entry matched)
1907 check_address_exists (void *cls,
1908 const GNUNET_HashCode * key,
1911 struct CheckAddressExistsClosure *caec = cls;
1912 struct ValidationEntry *ve = value;
1913 if ( (0 == strcmp (caec->tname,
1914 ve->transport_name)) &&
1915 (caec->addrlen == ve->addrlen) &&
1916 (0 == memcmp (caec->addr,
1920 caec->exists = GNUNET_YES;
1928 * HELLO validation cleanup task (validation failed).
1930 * @param cls the 'struct ValidationEntry' that failed
1931 * @param tc scheduler context (unused)
1934 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1936 struct ValidationEntry *va = cls;
1937 struct GNUNET_PeerIdentity pid;
1939 GNUNET_STATISTICS_update (stats,
1940 gettext_noop ("# address validation timeouts"),
1943 GNUNET_CRYPTO_hash (&va->publicKey,
1945 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1947 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1950 GNUNET_free (va->transport_name);
1956 neighbour_timeout_task (void *cls,
1957 const struct GNUNET_SCHEDULER_TaskContext *tc)
1959 struct NeighbourList *n = cls;
1962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1963 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1965 GNUNET_STATISTICS_update (stats,
1966 gettext_noop ("# disconnects due to timeout"),
1969 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1970 disconnect_neighbour (n, GNUNET_NO);
1975 * Schedule the job that will cause us to send a PING to the
1976 * foreign address to evaluate its validity and latency.
1978 * @param fal address to PING
1981 schedule_next_ping (struct ForeignAddressList *fal);
1985 * Add the given address to the list of foreign addresses
1986 * available for the given peer (check for duplicates).
1988 * @param cls the respective 'struct NeighbourList' to update
1989 * @param tname name of the transport
1990 * @param expiration expiration time
1991 * @param addr the address
1992 * @param addrlen length of the address
1993 * @return GNUNET_OK (always)
1996 add_to_foreign_address_list (void *cls,
1998 struct GNUNET_TIME_Absolute expiration,
1999 const void *addr, size_t addrlen)
2001 struct NeighbourList *n = cls;
2002 struct ForeignAddressList *fal;
2005 GNUNET_STATISTICS_update (stats,
2006 gettext_noop ("# valid peer addresses returned by peerinfo"),
2010 fal = find_peer_address (n, tname, addr, addrlen);
2014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2015 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2016 GNUNET_a2s (addr, addrlen),
2018 GNUNET_i2s (&n->id),
2021 fal = add_peer_address (n, tname, addr, addrlen);
2024 GNUNET_STATISTICS_update (stats,
2025 gettext_noop ("# previously validated addresses lacking transport"),
2031 fal->expires = GNUNET_TIME_absolute_max (expiration,
2033 schedule_next_ping (fal);
2039 fal->expires = GNUNET_TIME_absolute_max (expiration,
2044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2045 "Failed to add new address for `%4s'\n",
2046 GNUNET_i2s (&n->id));
2049 if (fal->validated == GNUNET_NO)
2051 fal->validated = GNUNET_YES;
2052 GNUNET_STATISTICS_update (stats,
2053 gettext_noop ("# peer addresses considered valid"),
2057 if (try == GNUNET_YES)
2059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2060 "Have new addresses, will try to trigger transmissions.\n");
2061 try_transmission_to_peer (n);
2068 * Add addresses in validated HELLO "h" to the set of addresses
2069 * we have for this peer.
2071 * @param cls closure ('struct NeighbourList*')
2072 * @param peer id of the peer, NULL for last call
2073 * @param h hello message for the peer (can be NULL)
2074 * @param trust amount of trust we have in the peer (not used)
2077 add_hello_for_peer (void *cls,
2078 const struct GNUNET_PeerIdentity *peer,
2079 const struct GNUNET_HELLO_Message *h,
2082 struct NeighbourList *n = cls;
2090 return; /* no HELLO available */
2092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2093 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2097 if (GNUNET_YES != n->public_key_valid)
2099 GNUNET_HELLO_get_key (h, &n->publicKey);
2100 n->public_key_valid = GNUNET_YES;
2102 GNUNET_HELLO_iterate_addresses (h,
2104 &add_to_foreign_address_list,
2110 * Create a fresh entry in our neighbour list for the given peer.
2111 * Will try to transmit our current HELLO to the new neighbour.
2113 * @param peer the peer for which we create the entry
2114 * @return the new neighbour list entry
2116 static struct NeighbourList *
2117 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2119 struct NeighbourList *n;
2120 struct TransportPlugin *tp;
2121 struct ReadyList *rl;
2123 GNUNET_assert (our_hello != NULL);
2124 GNUNET_STATISTICS_update (stats,
2125 gettext_noop ("# active neighbours"),
2128 n = GNUNET_malloc (sizeof (struct NeighbourList));
2129 n->next = neighbours;
2133 GNUNET_TIME_relative_to_absolute
2134 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2135 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2136 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2137 MAX_BANDWIDTH_CARRY_S);
2141 if (tp->api->send != NULL)
2143 rl = GNUNET_malloc (sizeof (struct ReadyList));
2145 rl->next = n->plugins;
2148 rl->addresses = NULL;
2152 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2154 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2155 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2156 &neighbour_timeout_task, n);
2157 n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2158 0, GNUNET_TIME_UNIT_FOREVER_REL,
2159 &add_hello_for_peer, n);
2160 transmit_to_peer (NULL, NULL, 0,
2161 HELLO_ADDRESS_EXPIRATION,
2162 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2169 * Send periodic PING messages to a give foreign address.
2171 * @param cls our 'struct PeriodicValidationContext*'
2172 * @param tc task context
2175 send_periodic_ping (void *cls,
2176 const struct GNUNET_SCHEDULER_TaskContext *tc)
2178 struct ForeignAddressList *peer_address = cls;
2179 struct TransportPlugin *tp;
2180 struct ValidationEntry *va;
2181 struct NeighbourList *neighbour;
2182 struct TransportPingMessage ping;
2183 struct CheckAddressExistsClosure caec;
2185 uint16_t hello_size;
2188 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2189 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2191 tp = peer_address->ready_list->plugin;
2192 neighbour = peer_address->ready_list->neighbour;
2193 if (GNUNET_YES != neighbour->public_key_valid)
2195 /* no public key yet, try again later */
2196 schedule_next_ping (peer_address);
2199 caec.addr = peer_address->addr;
2200 caec.addrlen = peer_address->addrlen;
2201 caec.tname = tp->short_name;
2202 caec.exists = GNUNET_NO;
2203 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2204 &check_address_exists,
2206 if (caec.exists == GNUNET_YES)
2208 /* During validation attempts we will likely trigger the other
2209 peer trying to validate our address which in turn will cause
2210 it to send us its HELLO, so we expect to hit this case rather
2211 frequently. Only print something if we are very verbose. */
2212 #if DEBUG_TRANSPORT > 1
2213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2214 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2215 GNUNET_a2s (peer_address->addr,
2216 peer_address->addrlen),
2218 GNUNET_i2s (&neighbour->id));
2220 schedule_next_ping (peer_address);
2223 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2224 va->transport_name = GNUNET_strdup (tp->short_name);
2225 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2227 va->send_time = GNUNET_TIME_absolute_get();
2228 va->addr = (const void*) &va[1];
2229 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2230 va->addrlen = peer_address->addrlen;
2232 memcpy(&va->publicKey,
2233 &neighbour->publicKey,
2234 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2236 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2237 HELLO_VERIFICATION_TIMEOUT,
2238 &timeout_hello_validation,
2240 GNUNET_CONTAINER_multihashmap_put (validation_map,
2241 &neighbour->id.hashPubKey,
2243 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2244 hello_size = GNUNET_HELLO_size(our_hello);
2245 tsize = sizeof(struct TransportPingMessage) + hello_size;
2246 message_buf = GNUNET_malloc(tsize);
2247 ping.challenge = htonl(va->challenge);
2248 ping.header.size = htons(sizeof(struct TransportPingMessage));
2249 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2250 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2251 memcpy(message_buf, our_hello, hello_size);
2252 memcpy(&message_buf[hello_size],
2254 sizeof(struct TransportPingMessage));
2255 #if DEBUG_TRANSPORT_REVALIDATION
2256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2257 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2258 GNUNET_a2s (peer_address->addr,
2259 peer_address->addrlen),
2261 GNUNET_i2s (&neighbour->id),
2262 "HELLO", hello_size,
2263 "PING", sizeof (struct TransportPingMessage));
2265 GNUNET_STATISTICS_update (stats,
2266 gettext_noop ("# PING messages sent for re-validation"),
2269 transmit_to_peer (NULL, peer_address,
2270 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2271 HELLO_VERIFICATION_TIMEOUT,
2273 GNUNET_YES, neighbour);
2274 GNUNET_free(message_buf);
2275 schedule_next_ping (peer_address);
2280 * Schedule the job that will cause us to send a PING to the
2281 * foreign address to evaluate its validity and latency.
2283 * @param fal address to PING
2286 schedule_next_ping (struct ForeignAddressList *fal)
2288 struct GNUNET_TIME_Relative delay;
2290 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2292 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2293 delay.value /= 2; /* do before expiration */
2294 delay = GNUNET_TIME_relative_min (delay,
2295 LATENCY_EVALUATION_MAX_DELAY);
2296 if (GNUNET_YES != fal->estimated)
2298 delay = GNUNET_TIME_UNIT_ZERO;
2299 fal->estimated = GNUNET_YES;
2301 if (GNUNET_YES == fal->connected)
2303 delay = GNUNET_TIME_relative_min (delay,
2304 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2306 /* FIXME: also adjust delay based on how close the last
2307 observed latency is to the latency of the best alternative */
2308 /* bound how fast we can go */
2309 delay = GNUNET_TIME_relative_max (delay,
2310 GNUNET_TIME_UNIT_SECONDS);
2311 /* randomize a bit (to avoid doing all at the same time) */
2312 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2313 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
2315 &send_periodic_ping,
2321 * Iterator over hash map entries. Checks if the given validation
2322 * entry is for the same challenge as what is given in the PONG.
2324 * @param cls the 'struct TransportPongMessage*'
2325 * @param key peer identity
2326 * @param value value in the hash map ('struct ValidationEntry')
2327 * @return GNUNET_YES if we should continue to
2328 * iterate (mismatch), GNUNET_NO if not (entry matched)
2331 check_pending_validation (void *cls,
2332 const GNUNET_HashCode * key,
2335 const struct TransportPongMessage *pong = cls;
2336 struct ValidationEntry *ve = value;
2337 struct AddValidatedAddressContext avac;
2338 unsigned int challenge = ntohl(pong->challenge);
2339 struct GNUNET_HELLO_Message *hello;
2340 struct GNUNET_PeerIdentity target;
2341 struct NeighbourList *n;
2342 struct ForeignAddressList *fal;
2344 if (ve->challenge != challenge)
2348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2349 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2351 GNUNET_a2s ((const struct sockaddr *) ve->addr,
2353 ve->transport_name);
2355 GNUNET_STATISTICS_update (stats,
2356 gettext_noop ("# address validation successes"),
2359 /* create the updated HELLO */
2360 GNUNET_CRYPTO_hash (&ve->publicKey,
2361 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2362 &target.hashPubKey);
2363 avac.done = GNUNET_NO;
2365 hello = GNUNET_HELLO_create (&ve->publicKey,
2366 &add_validated_address,
2368 GNUNET_PEERINFO_add_peer (cfg, sched,
2371 GNUNET_free (hello);
2372 n = find_neighbour (&target);
2375 n->publicKey = ve->publicKey;
2376 n->public_key_valid = GNUNET_YES;
2377 fal = add_peer_address (n,
2381 GNUNET_assert (fal != NULL);
2382 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2383 fal->validated = GNUNET_YES;
2384 GNUNET_STATISTICS_update (stats,
2385 gettext_noop ("# peer addresses considered valid"),
2388 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2389 schedule_next_ping (fal);
2390 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2391 n->latency = fal->latency;
2393 n->latency.value = (fal->latency.value + n->latency.value) / 2;
2394 n->distance = fal->distance;
2395 if (GNUNET_NO == n->received_pong)
2397 notify_clients_connect (&target, n->latency, n->distance);
2398 n->received_pong = GNUNET_YES;
2400 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2402 GNUNET_SCHEDULER_cancel (sched,
2404 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2405 try_transmission_to_peer (n);
2409 /* clean up validation entry */
2410 GNUNET_assert (GNUNET_YES ==
2411 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2414 GNUNET_SCHEDULER_cancel (sched,
2416 GNUNET_free (ve->transport_name);
2423 * Function that will be called if we receive a validation
2424 * of an address challenge that we transmitted to another
2425 * peer. Note that the validation should only be considered
2426 * acceptable if the challenge matches AND if the sender
2427 * address is at least a plausible address for this peer
2428 * (otherwise we may be seeing a MiM attack).
2430 * @param cls closure
2431 * @param message the pong message
2432 * @param peer who responded to our challenge
2433 * @param sender_address string describing our sender address (as observed
2434 * by the other peer in binary format)
2435 * @param sender_address_len number of bytes in 'sender_address'
2438 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2439 const struct GNUNET_PeerIdentity *peer,
2440 const char *sender_address,
2441 size_t sender_address_len)
2443 #if DEBUG_TRANSPORT > 1
2444 /* we get tons of these that just get discarded, only log
2445 if we are quite verbose */
2446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2447 "Receiving `%s' message from `%4s'.\n", "PONG",
2450 GNUNET_STATISTICS_update (stats,
2451 gettext_noop ("# PONG messages received"),
2454 if (GNUNET_SYSERR !=
2455 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2457 &check_pending_validation,
2460 /* This is *expected* to happen a lot since we send
2461 PONGs to *all* known addresses of the sender of
2462 the PING, so most likely we get multiple PONGs
2463 per PING, and all but the first PONG will end up
2464 here. So really we should not print anything here
2465 unless we want to be very, very verbose... */
2466 #if DEBUG_TRANSPORT > 2
2467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2468 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2477 /* FIXME: add given address to potential pool of our addresses
2479 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2480 _("Another peer saw us using the address `%s' via `%s'.\n"),
2481 GNUNET_a2s ((const struct sockaddr *) &pong[1],
2482 ntohs(pong->addrlen)),
2483 va->transport_name);
2489 * Check if the given address is already being validated; if not,
2490 * append the given address to the list of entries that are being be
2491 * validated and initiate validation.
2493 * @param cls closure ('struct CheckHelloValidatedContext *')
2494 * @param tname name of the transport
2495 * @param expiration expiration time
2496 * @param addr the address
2497 * @param addrlen length of the address
2498 * @return GNUNET_OK (always)
2501 run_validation (void *cls,
2503 struct GNUNET_TIME_Absolute expiration,
2504 const void *addr, size_t addrlen)
2506 struct CheckHelloValidatedContext *chvc = cls;
2507 struct GNUNET_PeerIdentity id;
2508 struct TransportPlugin *tp;
2509 struct ValidationEntry *va;
2510 struct NeighbourList *neighbour;
2511 struct ForeignAddressList *peer_address;
2512 struct TransportPingMessage ping;
2513 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2514 struct CheckAddressExistsClosure caec;
2516 uint16_t hello_size;
2519 GNUNET_STATISTICS_update (stats,
2520 gettext_noop ("# peer addresses scheduled for validation"),
2523 tp = find_transport (tname);
2526 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2527 GNUNET_ERROR_TYPE_BULK,
2529 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2531 GNUNET_STATISTICS_update (stats,
2532 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2537 GNUNET_HELLO_get_key (chvc->hello, &pk);
2538 GNUNET_CRYPTO_hash (&pk,
2540 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2543 caec.addrlen = addrlen;
2545 caec.exists = GNUNET_NO;
2546 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2547 &check_address_exists,
2549 if (caec.exists == GNUNET_YES)
2551 /* During validation attempts we will likely trigger the other
2552 peer trying to validate our address which in turn will cause
2553 it to send us its HELLO, so we expect to hit this case rather
2554 frequently. Only print something if we are very verbose. */
2555 #if DEBUG_TRANSPORT > 1
2556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2557 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2558 GNUNET_a2s (addr, addrlen),
2562 GNUNET_STATISTICS_update (stats,
2563 gettext_noop ("# peer addresses not validated (in progress)"),
2568 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2569 va->transport_name = GNUNET_strdup (tname);
2570 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2572 va->send_time = GNUNET_TIME_absolute_get();
2573 va->addr = (const void*) &va[1];
2574 memcpy (&va[1], addr, addrlen);
2575 va->addrlen = addrlen;
2576 GNUNET_HELLO_get_key (chvc->hello,
2578 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2579 HELLO_VERIFICATION_TIMEOUT,
2580 &timeout_hello_validation,
2582 GNUNET_CONTAINER_multihashmap_put (validation_map,
2585 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2586 neighbour = find_neighbour(&id);
2587 if (neighbour == NULL)
2588 neighbour = setup_new_neighbour(&id);
2589 neighbour->publicKey = va->publicKey;
2590 neighbour->public_key_valid = GNUNET_YES;
2591 peer_address = add_peer_address(neighbour, tname, addr, addrlen);
2592 GNUNET_assert(peer_address != NULL);
2593 hello_size = GNUNET_HELLO_size(our_hello);
2594 tsize = sizeof(struct TransportPingMessage) + hello_size;
2595 message_buf = GNUNET_malloc(tsize);
2596 ping.challenge = htonl(va->challenge);
2597 ping.header.size = htons(sizeof(struct TransportPingMessage));
2598 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2599 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2600 memcpy(message_buf, our_hello, hello_size);
2601 memcpy(&message_buf[hello_size],
2603 sizeof(struct TransportPingMessage));
2605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2607 GNUNET_a2s (addr, addrlen),
2610 "HELLO", hello_size,
2611 "PING", sizeof (struct TransportPingMessage));
2613 GNUNET_STATISTICS_update (stats,
2614 gettext_noop ("# PING messages sent for initial validation"),
2617 transmit_to_peer (NULL, peer_address,
2618 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2619 HELLO_VERIFICATION_TIMEOUT,
2621 GNUNET_YES, neighbour);
2622 GNUNET_free(message_buf);
2628 * Check if addresses in validated hello "h" overlap with
2629 * those in "chvc->hello" and validate the rest.
2631 * @param cls closure
2632 * @param peer id of the peer, NULL for last call
2633 * @param h hello message for the peer (can be NULL)
2634 * @param trust amount of trust we have in the peer (not used)
2637 check_hello_validated (void *cls,
2638 const struct GNUNET_PeerIdentity *peer,
2639 const struct GNUNET_HELLO_Message *h,
2642 struct CheckHelloValidatedContext *chvc = cls;
2643 struct GNUNET_HELLO_Message *plain_hello;
2644 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2645 struct GNUNET_PeerIdentity target;
2646 struct NeighbourList *n;
2651 GNUNET_CONTAINER_DLL_remove (chvc_head,
2654 if (GNUNET_NO == chvc->hello_known)
2656 /* notify PEERINFO about the peer now, so that we at least
2657 have the public key if some other component needs it */
2658 GNUNET_HELLO_get_key (chvc->hello, &pk);
2659 GNUNET_CRYPTO_hash (&pk,
2660 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2661 &target.hashPubKey);
2662 plain_hello = GNUNET_HELLO_create (&pk,
2665 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2666 GNUNET_free (plain_hello);
2668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2669 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2671 GNUNET_i2s (&target));
2673 GNUNET_STATISTICS_update (stats,
2674 gettext_noop ("# new HELLOs requiring full validation"),
2677 GNUNET_HELLO_iterate_addresses (chvc->hello,
2684 GNUNET_STATISTICS_update (stats,
2685 gettext_noop ("# duplicate HELLO (peer known)"),
2695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2696 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2700 chvc->hello_known = GNUNET_YES;
2701 n = find_neighbour (peer);
2704 GNUNET_HELLO_iterate_addresses (h,
2706 &add_to_foreign_address_list,
2708 try_transmission_to_peer (n);
2712 GNUNET_STATISTICS_update (stats,
2713 gettext_noop ("# no existing neighbour record (validating HELLO)"),
2717 GNUNET_STATISTICS_update (stats,
2718 gettext_noop ("# HELLO validations (update case)"),
2721 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2723 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2729 * Process HELLO-message.
2731 * @param plugin transport involved, may be NULL
2732 * @param message the actual message
2733 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2736 process_hello (struct TransportPlugin *plugin,
2737 const struct GNUNET_MessageHeader *message)
2740 struct GNUNET_PeerIdentity target;
2741 const struct GNUNET_HELLO_Message *hello;
2742 struct CheckHelloValidatedContext *chvc;
2743 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2745 hsize = ntohs (message->size);
2746 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2747 (hsize < sizeof (struct GNUNET_MessageHeader)))
2750 return GNUNET_SYSERR;
2752 GNUNET_STATISTICS_update (stats,
2753 gettext_noop ("# HELLOs received for validation"),
2756 /* first, check if load is too high */
2757 if (GNUNET_SCHEDULER_get_load (sched,
2758 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2760 GNUNET_STATISTICS_update (stats,
2761 gettext_noop ("# HELLOs ignored due to high load"),
2766 hello = (const struct GNUNET_HELLO_Message *) message;
2767 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2769 GNUNET_break_op (0);
2770 return GNUNET_SYSERR;
2772 GNUNET_CRYPTO_hash (&publicKey,
2773 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2774 &target.hashPubKey);
2775 if (0 == memcmp (&my_identity,
2777 sizeof (struct GNUNET_PeerIdentity)))
2779 GNUNET_STATISTICS_update (stats,
2780 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2785 #if DEBUG_TRANSPORT > 1
2786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2787 "Processing `%s' message for `%4s' of size %u\n",
2789 GNUNET_i2s (&target),
2790 GNUNET_HELLO_size(hello));
2792 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2793 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2794 memcpy (&chvc[1], hello, hsize);
2795 GNUNET_CONTAINER_DLL_insert (chvc_head,
2798 /* finally, check if HELLO was previously validated
2799 (continuation will then schedule actual validation) */
2800 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2804 HELLO_VERIFICATION_TIMEOUT,
2805 &check_hello_validated, chvc);
2811 * The peer specified by the given neighbour has timed-out or a plugin
2812 * has disconnected. We may either need to do nothing (other plugins
2813 * still up), or trigger a full disconnect and clean up. This
2814 * function updates our state and does the necessary notifications.
2815 * Also notifies our clients that the neighbour is now officially
2818 * @param n the neighbour list entry for the peer
2819 * @param check should we just check if all plugins
2820 * disconnected or must we ask all plugins to
2824 disconnect_neighbour (struct NeighbourList *n, int check)
2826 struct ReadyList *rpos;
2827 struct NeighbourList *npos;
2828 struct NeighbourList *nprev;
2829 struct MessageQueue *mq;
2830 struct ForeignAddressList *peer_addresses;
2831 struct ForeignAddressList *peer_pos;
2833 if (GNUNET_YES == check)
2836 while (NULL != rpos)
2838 peer_addresses = rpos->addresses;
2839 while (peer_addresses != NULL)
2841 if (GNUNET_YES == peer_addresses->connected)
2842 return; /* still connected */
2843 peer_addresses = peer_addresses->next;
2849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2850 "Disconnecting from `%4s'\n",
2851 GNUNET_i2s (&n->id));
2853 /* remove n from neighbours list */
2856 while ((npos != NULL) && (npos != n))
2861 GNUNET_assert (npos != NULL);
2863 neighbours = n->next;
2865 nprev->next = n->next;
2867 /* notify all clients about disconnect */
2868 if (GNUNET_YES == n->received_pong)
2869 notify_clients_disconnect (&n->id);
2871 /* clean up all plugins, cancel connections and pending transmissions */
2872 while (NULL != (rpos = n->plugins))
2874 n->plugins = rpos->next;
2875 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2876 while (rpos->addresses != NULL)
2878 peer_pos = rpos->addresses;
2879 rpos->addresses = peer_pos->next;
2880 if (peer_pos->connected == GNUNET_YES)
2881 GNUNET_STATISTICS_update (stats,
2882 gettext_noop ("# connected addresses"),
2885 if (GNUNET_YES == peer_pos->validated)
2886 GNUNET_STATISTICS_update (stats,
2887 gettext_noop ("# peer addresses considered valid"),
2890 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
2892 GNUNET_SCHEDULER_cancel (sched,
2893 peer_pos->revalidate_task);
2894 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2896 GNUNET_free(peer_pos);
2901 /* free all messages on the queue */
2902 while (NULL != (mq = n->messages_head))
2904 GNUNET_STATISTICS_update (stats,
2905 gettext_noop ("# bytes in message queue for other peers"),
2906 - (int64_t) mq->message_buf_size,
2908 GNUNET_STATISTICS_update (stats,
2909 gettext_noop ("# bytes discarded due to disconnect"),
2910 mq->message_buf_size,
2912 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2915 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
2917 sizeof(struct GNUNET_PeerIdentity)));
2920 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2922 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2923 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2925 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2927 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
2928 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2930 if (n->piter != NULL)
2932 GNUNET_PEERINFO_iterate_cancel (n->piter);
2935 /* finally, free n itself */
2936 GNUNET_STATISTICS_update (stats,
2937 gettext_noop ("# active neighbours"),
2945 * We have received a PING message from someone. Need to send a PONG message
2946 * in response to the peer by any means necessary.
2948 * FIXME: With something like TCP where a connection exists, we may
2949 * want to send it that way. But the current API does not seem to
2950 * allow us to do so (can't tell this to the transport!)
2953 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2954 const struct GNUNET_PeerIdentity *peer,
2955 const char *sender_address,
2956 size_t sender_address_len)
2958 struct TransportPlugin *plugin = cls;
2959 struct TransportPingMessage *ping;
2960 struct TransportPongMessage *pong;
2961 struct NeighbourList *n;
2962 struct ReadyList *rl;
2963 struct ForeignAddressList *fal;
2965 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
2967 GNUNET_break_op (0);
2968 return GNUNET_SYSERR;
2970 ping = (struct TransportPingMessage *) message;
2971 if (0 != memcmp (&ping->target,
2972 plugin->env.my_identity,
2973 sizeof (struct GNUNET_PeerIdentity)))
2975 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2976 _("Received `%s' message not destined for me!\n"),
2978 return GNUNET_SYSERR;
2981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2982 "Processing `%s' from `%s'\n",
2984 GNUNET_a2s ((const struct sockaddr *)sender_address,
2985 sender_address_len));
2987 GNUNET_STATISTICS_update (stats,
2988 gettext_noop ("# PING messages received"),
2991 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2992 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2993 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2994 pong->purpose.size =
2995 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2997 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2998 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2999 pong->challenge = ping->challenge;
3000 pong->addrlen = htons(sender_address_len);
3001 memcpy(&pong->signer,
3003 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3004 memcpy (&pong[1], sender_address, sender_address_len);
3005 GNUNET_assert (GNUNET_OK ==
3006 GNUNET_CRYPTO_rsa_sign (my_private_key,
3007 &pong->purpose, &pong->signature));
3009 n = find_neighbour(peer);
3011 n = setup_new_neighbour(peer);
3012 /* broadcast 'PONG' to all available addresses */
3016 fal = rl->addresses;
3019 transmit_to_peer(NULL, fal,
3020 TRANSPORT_PONG_PRIORITY,
3021 HELLO_VERIFICATION_TIMEOUT,
3023 ntohs(pong->header.size),
3036 * Function called by the plugin for each received message.
3037 * Update data volumes, possibly notify plugins about
3038 * reducing the rate at which they read from the socket
3039 * and generally forward to our receive callback.
3041 * @param cls the "struct TransportPlugin *" we gave to the plugin
3042 * @param peer (claimed) identity of the other peer
3043 * @param message the message, NULL if we only care about
3044 * learning about the delay until we should receive again
3045 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3046 * @param sender_address binary address of the sender (if observed)
3047 * @param sender_address_len number of bytes in sender_address
3048 * @return how long the plugin should wait until receiving more data
3049 * (plugins that do not support this, can ignore the return value)
3051 static struct GNUNET_TIME_Relative
3052 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3053 const struct GNUNET_MessageHeader *message,
3054 unsigned int distance, const char *sender_address,
3055 size_t sender_address_len)
3057 struct ReadyList *service_context;
3058 struct TransportPlugin *plugin = cls;
3059 struct TransportClient *cpos;
3060 struct InboundMessage *im;
3061 struct ForeignAddressList *peer_address;
3063 struct NeighbourList *n;
3064 struct GNUNET_TIME_Relative ret;
3066 n = find_neighbour (peer);
3068 n = setup_new_neighbour (peer);
3069 service_context = n->plugins;
3070 while ((service_context != NULL) && (plugin != service_context->plugin))
3071 service_context = service_context->next;
3072 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3073 if (message != NULL)
3075 peer_address = add_peer_address(n,
3078 sender_address_len);
3079 if (peer_address != NULL)
3081 peer_address->distance = distance;
3082 if (peer_address->connected == GNUNET_NO)
3084 /* FIXME: be careful here to not mark
3085 MULTIPLE addresses as connected! */
3086 peer_address->connected = GNUNET_YES;
3087 GNUNET_STATISTICS_update (stats,
3088 gettext_noop ("# connected addresses"),
3092 peer_address->timeout
3094 GNUNET_TIME_relative_to_absolute
3095 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3096 schedule_next_ping (peer_address);
3098 /* update traffic received amount ... */
3099 msize = ntohs (message->size);
3100 GNUNET_STATISTICS_update (stats,
3101 gettext_noop ("# bytes received from other peers"),
3104 n->distance = distance;
3106 GNUNET_TIME_relative_to_absolute
3107 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3108 GNUNET_SCHEDULER_cancel (sched,
3111 GNUNET_SCHEDULER_add_delayed (sched,
3112 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3113 &neighbour_timeout_task, n);
3114 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3116 /* dropping message due to frequent inbound volume violations! */
3117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3118 GNUNET_ERROR_TYPE_BULK,
3120 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
3121 n->in_tracker.available_bytes_per_s__,
3122 n->quota_violation_count);
3123 GNUNET_STATISTICS_update (stats,
3124 gettext_noop ("# bandwidth quota violations by other peers"),
3127 return GNUNET_TIME_UNIT_MINUTES; /* minimum penalty, likely ignored (UDP...) */
3129 switch (ntohs (message->type))
3131 case GNUNET_MESSAGE_TYPE_HELLO:
3132 GNUNET_STATISTICS_update (stats,
3133 gettext_noop ("# HELLO messages received from other peers"),
3136 process_hello (plugin, message);
3138 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3139 handle_ping(plugin, message, peer, sender_address, sender_address_len);
3141 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3142 handle_pong(plugin, message, peer, sender_address, sender_address_len);
3146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147 "Received message of type %u from `%4s', sending to all clients.\n",
3148 ntohs (message->type), GNUNET_i2s (peer));
3150 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3152 n->quota_violation_count++;
3154 n->quota_violation_count = 0; /* back within limits */
3155 GNUNET_STATISTICS_update (stats,
3156 gettext_noop ("# payload received from other peers"),
3159 /* transmit message to all clients */
3160 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3161 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3162 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3163 im->latency = GNUNET_TIME_relative_hton (n->latency);
3165 memcpy (&im[1], message, msize);
3167 while (cpos != NULL)
3169 transmit_to_client (cpos, &im->header, GNUNET_YES);
3175 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3178 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3179 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3180 (unsigned long long) n->in_tracker.consumption_since_last_update__,
3181 (unsigned int) n->in_tracker.available_bytes_per_s__,
3182 (unsigned long long) ret.value);
3183 GNUNET_STATISTICS_update (stats,
3184 gettext_noop ("# ms throttling suggested"),
3185 (int64_t) ret.value,
3193 * Handle START-message. This is the first message sent to us
3194 * by any client which causes us to add it to our list.
3196 * @param cls closure (always NULL)
3197 * @param client identification of the client
3198 * @param message the actual message
3201 handle_start (void *cls,
3202 struct GNUNET_SERVER_Client *client,
3203 const struct GNUNET_MessageHeader *message)
3205 struct TransportClient *c;
3206 struct ConnectInfoMessage cim;
3207 struct NeighbourList *n;
3210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211 "Received `%s' request from client\n", "START");
3216 if (c->client == client)
3218 /* client already on our list! */
3220 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3225 c = GNUNET_malloc (sizeof (struct TransportClient));
3229 if (our_hello != NULL)
3232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3233 "Sending our own `%s' to new client\n", "HELLO");
3235 transmit_to_client (c,
3236 (const struct GNUNET_MessageHeader *) our_hello,
3238 /* tell new client about all existing connections */
3239 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3240 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3244 if (GNUNET_YES == n->received_pong)
3247 cim.latency = GNUNET_TIME_relative_hton (n->latency);
3248 cim.distance = htonl (n->distance);
3249 transmit_to_client (c, &cim.header, GNUNET_NO);
3254 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3259 * Handle HELLO-message.
3261 * @param cls closure (always NULL)
3262 * @param client identification of the client
3263 * @param message the actual message
3266 handle_hello (void *cls,
3267 struct GNUNET_SERVER_Client *client,
3268 const struct GNUNET_MessageHeader *message)
3272 GNUNET_STATISTICS_update (stats,
3273 gettext_noop ("# HELLOs received from clients"),
3276 ret = process_hello (NULL, message);
3277 GNUNET_SERVER_receive_done (client, ret);
3282 * Handle SEND-message.
3284 * @param cls closure (always NULL)
3285 * @param client identification of the client
3286 * @param message the actual message
3289 handle_send (void *cls,
3290 struct GNUNET_SERVER_Client *client,
3291 const struct GNUNET_MessageHeader *message)
3293 struct TransportClient *tc;
3294 struct NeighbourList *n;
3295 const struct OutboundMessage *obm;
3296 const struct GNUNET_MessageHeader *obmm;
3300 size = ntohs (message->size);
3302 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3305 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3308 GNUNET_STATISTICS_update (stats,
3309 gettext_noop ("# payload received for other peers"),
3312 obm = (const struct OutboundMessage *) message;
3314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3315 "Received `%s' request from client with target `%4s'\n",
3316 "SEND", GNUNET_i2s (&obm->peer));
3318 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3319 msize = ntohs (obmm->size);
3320 if (size != msize + sizeof (struct OutboundMessage))
3323 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3326 n = find_neighbour (&obm->peer);
3328 n = setup_new_neighbour (&obm->peer);
3330 while ((tc != NULL) && (tc->client != client))
3334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3335 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3337 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3339 transmit_to_peer (tc, NULL, ntohl (obm->priority),
3340 GNUNET_TIME_relative_ntoh (obm->timeout),
3342 ntohs (obmm->size), GNUNET_NO, n);
3343 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3348 * Handle SET_QUOTA-message.
3350 * @param cls closure (always NULL)
3351 * @param client identification of the client
3352 * @param message the actual message
3355 handle_set_quota (void *cls,
3356 struct GNUNET_SERVER_Client *client,
3357 const struct GNUNET_MessageHeader *message)
3359 const struct QuotaSetMessage *qsm =
3360 (const struct QuotaSetMessage *) message;
3361 struct NeighbourList *n;
3363 GNUNET_STATISTICS_update (stats,
3364 gettext_noop ("# SET QUOTA messages received"),
3367 n = find_neighbour (&qsm->peer);
3370 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3371 GNUNET_STATISTICS_update (stats,
3372 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3379 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3381 (unsigned int) ntohl (qsm->quota.value__),
3382 (unsigned int) n->in_tracker.available_bytes_per_s__,
3383 GNUNET_i2s (&qsm->peer));
3385 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3387 if (0 == ntohl (qsm->quota.value__))
3388 disconnect_neighbour (n, GNUNET_NO);
3389 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3394 * Take the given address and append it to the set of results send back to
3397 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3398 * @param address the resolved name, NULL to indicate the last response
3401 transmit_address_to_client (void *cls, const char *address)
3403 struct GNUNET_SERVER_TransmitContext *tc = cls;
3406 if (NULL == address)
3409 slen = strlen (address) + 1;
3410 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3411 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3412 if (NULL == address)
3413 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3418 * Handle AddressLookup-message.
3420 * @param cls closure (always NULL)
3421 * @param client identification of the client
3422 * @param message the actual message
3425 handle_address_lookup (void *cls,
3426 struct GNUNET_SERVER_Client *client,
3427 const struct GNUNET_MessageHeader *message)
3429 const struct AddressLookupMessage *alum;
3430 struct TransportPlugin *lsPlugin;
3431 const char *nameTransport;
3432 const char *address;
3434 struct GNUNET_SERVER_TransmitContext *tc;
3435 struct GNUNET_TIME_Absolute timeout;
3436 struct GNUNET_TIME_Relative rtimeout;
3439 size = ntohs (message->size);
3440 if (size < sizeof (struct AddressLookupMessage))
3442 GNUNET_break_op (0);
3443 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3446 alum = (const struct AddressLookupMessage *) message;
3447 uint32_t addressLen = ntohl (alum->addrlen);
3448 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3450 GNUNET_break_op (0);
3451 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3454 address = (const char *) &alum[1];
3455 nameTransport = (const char *) &address[addressLen];
3457 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3459 GNUNET_break_op (0);
3460 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3463 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
3464 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
3465 numeric = ntohl (alum->numeric_only);
3466 lsPlugin = find_transport (nameTransport);
3467 if (NULL == lsPlugin)
3469 tc = GNUNET_SERVER_transmit_context_create (client);
3470 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3471 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3472 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3475 tc = GNUNET_SERVER_transmit_context_create (client);
3476 lsPlugin->api->address_pretty_printer (cls, nameTransport,
3477 address, addressLen,
3480 &transmit_address_to_client, tc);
3484 * List of handlers for the messages understood by this
3487 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3488 {&handle_start, NULL,
3489 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3490 {&handle_hello, NULL,
3491 GNUNET_MESSAGE_TYPE_HELLO, 0},
3492 {&handle_send, NULL,
3493 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3494 {&handle_set_quota, NULL,
3495 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3496 {&handle_address_lookup, NULL,
3497 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3504 * Setup the environment for this plugin.
3507 create_environment (struct TransportPlugin *plug)
3509 plug->env.cfg = cfg;
3510 plug->env.sched = sched;
3511 plug->env.my_identity = &my_identity;
3512 plug->env.cls = plug;
3513 plug->env.receive = &plugin_env_receive;
3514 plug->env.notify_address = &plugin_env_notify_address;
3515 plug->env.max_connections = max_connect_per_transport;
3516 plug->env.stats = stats;
3521 * Start the specified transport (load the plugin).
3524 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
3526 struct TransportPlugin *plug;
3529 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3530 _("Loading `%s' transport plugin\n"), name);
3531 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3532 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3533 create_environment (plug);
3534 plug->short_name = GNUNET_strdup (name);
3535 plug->lib_name = libname;
3536 plug->next = plugins;
3538 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3539 if (plug->api == NULL)
3541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3542 _("Failed to load transport plugin for `%s'\n"), name);
3543 GNUNET_free (plug->short_name);
3544 plugins = plug->next;
3545 GNUNET_free (libname);
3552 * Called whenever a client is disconnected. Frees our
3553 * resources associated with that client.
3555 * @param cls closure
3556 * @param client identification of the client
3559 client_disconnect_notification (void *cls,
3560 struct GNUNET_SERVER_Client *client)
3562 struct TransportClient *pos;
3563 struct TransportClient *prev;
3564 struct ClientMessageQueueEntry *mqe;
3569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3570 "Client disconnected, cleaning up.\n");
3574 while ((pos != NULL) && (pos->client != client))
3581 while (NULL != (mqe = pos->message_queue_head))
3583 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3584 pos->message_queue_tail,
3586 pos->message_count--;
3590 clients = pos->next;
3592 prev->next = pos->next;
3593 if (GNUNET_YES == pos->tcs_pending)
3598 if (pos->th != NULL)
3600 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3603 GNUNET_break (0 == pos->message_count);
3609 * Iterator to free entries in the validation_map.
3611 * @param cls closure (unused)
3612 * @param key current key code
3613 * @param value value in the hash map (validation to abort)
3614 * @return GNUNET_YES (always)
3617 abort_validation (void *cls,
3618 const GNUNET_HashCode * key,
3621 struct ValidationEntry *va = value;
3623 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3624 GNUNET_free (va->transport_name);
3631 * Function called when the service shuts down. Unloads our plugins
3632 * and cancels pending validations.
3634 * @param cls closure, unused
3635 * @param tc task context (unused)
3638 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3640 struct TransportPlugin *plug;
3641 struct OwnAddressList *al;
3642 struct CheckHelloValidatedContext *chvc;
3644 while (neighbours != NULL)
3645 disconnect_neighbour (neighbours, GNUNET_NO);
3647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3648 "Transport service is unloading plugins...\n");
3650 while (NULL != (plug = plugins))
3652 plugins = plug->next;
3653 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3654 GNUNET_free (plug->lib_name);
3655 GNUNET_free (plug->short_name);
3656 while (NULL != (al = plug->addresses))
3658 plug->addresses = al->next;
3663 if (my_private_key != NULL)
3664 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3665 GNUNET_free_non_null (our_hello);
3667 /* free 'chvc' data structure */
3668 while (NULL != (chvc = chvc_head))
3670 chvc_head = chvc->next;
3671 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3676 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3679 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3680 validation_map = NULL;
3683 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3690 * Initiate transport service.
3692 * @param cls closure
3693 * @param s scheduler to use
3694 * @param serv the initialized server
3695 * @param c configuration to use
3699 struct GNUNET_SCHEDULER_Handle *s,
3700 struct GNUNET_SERVER_Handle *serv,
3701 const struct GNUNET_CONFIGURATION_Handle *c)
3706 unsigned long long tneigh;
3711 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3712 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3713 /* parse configuration */
3715 GNUNET_CONFIGURATION_get_value_number (c,
3720 GNUNET_CONFIGURATION_get_value_filename (c,
3722 "HOSTKEY", &keyfile)))
3724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3726 ("Transport service is lacking key configuration settings. Exiting.\n"));
3727 GNUNET_SCHEDULER_shutdown (s);
3730 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3733 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3734 validation_map = NULL;
3737 max_connect_per_transport = (uint32_t) tneigh;
3738 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3739 GNUNET_free (keyfile);
3740 if (my_private_key == NULL)
3742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3744 ("Transport service could not access hostkey. Exiting.\n"));
3745 GNUNET_SCHEDULER_shutdown (s);
3748 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3751 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3752 validation_map = NULL;
3755 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3756 GNUNET_CRYPTO_hash (&my_public_key,
3757 sizeof (my_public_key), &my_identity.hashPubKey);
3758 /* setup notification */
3760 GNUNET_SERVER_disconnect_notify (server,
3761 &client_disconnect_notification, NULL);
3762 /* load plugins... */
3765 GNUNET_CONFIGURATION_get_value_string (c,
3766 "TRANSPORT", "PLUGINS", &plugs))
3768 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3769 _("Starting transport plugins `%s'\n"), plugs);
3770 pos = strtok (plugs, " ");
3773 start_transport (server, pos);
3775 pos = strtok (NULL, " ");
3777 GNUNET_free (plugs);
3779 GNUNET_SCHEDULER_add_delayed (sched,
3780 GNUNET_TIME_UNIT_FOREVER_REL,
3781 &shutdown_task, NULL);
3786 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3788 /* process client requests */
3789 GNUNET_SERVER_add_handlers (server, handlers);
3794 * The main function for the transport service.
3796 * @param argc number of arguments from the command line
3797 * @param argv command line arguments
3798 * @return 0 ok, 1 on error
3801 main (int argc, char *const *argv)
3803 return (GNUNET_OK ==
3804 GNUNET_SERVICE_run (argc,
3807 GNUNET_SERVICE_OPTION_NONE,
3808 &run, NULL)) ? 0 : 1;
3811 /* end of gnunet-service-transport.c */