2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
27 * - Need to SIGNAL connection in 'mark_address_connected'
28 * (if cnt == GNUNET_YES at the end!)
29 * - Need to SIGNAL disconnect when we no longer have any validated
31 * - Need to defer forwarding messages until after CONNECT message
32 * - MIGHT want to track connected state with neighbour
33 * - CHECK that 'address' being NULL in 'struct ForeignAddressList' is
34 * tolerated in the code everywhere (could not happen before)
37 * - This code uses 'GNUNET_a2s' for debug printing in many places,
38 * which is technically wrong since it assumes we have IP+Port
39 * (v4/v6) addresses. Once we add transports like http or smtp
40 * this will have to be changed!
43 #include "gnunet_client_lib.h"
44 #include "gnunet_container_lib.h"
45 #include "gnunet_constants.h"
46 #include "gnunet_getopt_lib.h"
47 #include "gnunet_hello_lib.h"
48 #include "gnunet_os_lib.h"
49 #include "gnunet_peerinfo_service.h"
50 #include "gnunet_plugin_lib.h"
51 #include "gnunet_protocols.h"
52 #include "gnunet_service_lib.h"
53 #include "gnunet_signatures.h"
54 #include "plugin_transport.h"
55 #include "transport.h"
58 * Should we do some additional checks (to validate behavior
61 #define EXTRA_CHECKS GNUNET_YES
64 * How many messages can we have pending for a given client process
65 * before we start to drop incoming messages? We typically should
66 * have only one client and so this would be the primary buffer for
67 * messages, so the number should be chosen rather generously.
69 * The expectation here is that most of the time the queue is large
70 * enough so that a drop is virtually never required.
72 #define MAX_PENDING 128
75 * How often should we try to reconnect to a peer using a particular
76 * transport plugin before giving up? Note that the plugin may be
77 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
79 #define MAX_CONNECT_RETRY 3
82 * Limit on the number of ready-to-run tasks when validating
83 * HELLOs. If more tasks are ready to run, we will drop
84 * HELLOs instead of validating them.
86 #define MAX_HELLO_LOAD 4
89 * How often must a peer violate bandwidth quotas before we start
90 * to simply drop its messages?
92 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
95 * How long until a HELLO verification attempt should time out?
96 * Must be rather small, otherwise a partially successful HELLO
97 * validation (some addresses working) might not be available
98 * before a client's request for a connection fails for good.
99 * Besides, if a single request to an address takes a long time,
100 * then the peer is unlikely worthwhile anyway.
102 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
105 * Priority to use for PONG messages.
107 #define TRANSPORT_PONG_PRIORITY 4
110 * How often do we re-add (cheaper) plugins to our list of plugins
111 * to try for a given connected peer?
113 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
116 * After how long do we expire an address in a HELLO that we just
117 * validated? This value is also used for our own addresses when we
120 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
124 * How long before an existing address expires should we again try to
125 * validate it? Must be (significantly) smaller than
126 * HELLO_ADDRESS_EXPIRATION.
128 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
131 * Maximum frequency for re-evaluating latencies for all transport addresses.
133 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
136 * Maximum frequency for re-evaluating latencies for connected addresses.
138 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
142 * List of addresses of other peers
144 struct ForeignAddressList
147 * This is a linked list.
149 struct ForeignAddressList *next;
152 * Which ready list does this entry belong to.
154 struct ReadyList *ready_list;
157 * How long until we auto-expire this address (unless it is
158 * re-confirmed by the transport)?
160 struct GNUNET_TIME_Absolute expires;
163 * Task used to re-validate addresses, updates latencies and
166 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
179 * Session (or NULL if no valid session currently exists or if the
180 * plugin does not use sessions).
182 struct Session *session;
185 * What was the last latency observed for this address, plugin and peer?
187 struct GNUNET_TIME_Relative latency;
190 * If we did not successfully transmit a message to the given peer
191 * via this connection during the specified time, we should consider
192 * the connection to be dead. This is used in the case that a TCP
193 * transport simply stalls writing to the stream but does not
194 * formerly get a signal that the other peer died.
196 struct GNUNET_TIME_Absolute timeout;
199 * How often have we tried to connect using this plugin? Used to
200 * discriminate against addresses that do not work well.
201 * FIXME: not yet used, but should be!
203 unsigned int connect_attempts;
206 * DV distance to this peer (1 if no DV is used).
207 * FIXME: need to set this from transport plugins!
212 * Have we ever estimated the latency of this address? Used to
213 * ensure that the first time we add an address, we immediately
219 * Are we currently connected via this address? The first time we
220 * successfully transmit or receive data to a peer via a particular
221 * address, we set this to GNUNET_YES. If we later get an error
222 * (disconnect notification, transmission failure, timeout), we set
223 * it back to GNUNET_NO.
228 * Is this plugin currently busy transmitting to the specific target?
229 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
230 * messages do not count as 'in transmit'.
235 * Has this address been validated yet?
243 * Entry in linked list of network addresses for ourselves.
245 struct OwnAddressList
248 * This is a linked list.
250 struct OwnAddressList *next;
253 * The address, actually a pointer to the end
254 * of this struct. Do not free!
259 * How long until we auto-expire this address (unless it is
260 * re-confirmed by the transport)?
262 struct GNUNET_TIME_Absolute expires;
273 * Entry in linked list of all of our plugins.
275 struct TransportPlugin
279 * This is a linked list.
281 struct TransportPlugin *next;
284 * API of the transport as returned by the plugin's
285 * initialization function.
287 struct GNUNET_TRANSPORT_PluginFunctions *api;
290 * Short name for the plugin (i.e. "tcp").
295 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
300 * List of our known addresses for this transport.
302 struct OwnAddressList *addresses;
305 * Environment this transport service is using
308 struct GNUNET_TRANSPORT_PluginEnvironment env;
311 * ID of task that is used to clean up expired addresses.
313 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
316 * Set to GNUNET_YES if we need to scrap the existing list of
317 * "addresses" and start fresh when we receive the next address
318 * update from a transport. Set to GNUNET_NO if we should just add
319 * the new address to the list and wait for the commit call.
325 struct NeighbourList;
328 * For each neighbour we keep a list of messages
329 * that we still want to transmit to the neighbour.
335 * This is a doubly linked list.
337 struct MessageQueue *next;
340 * This is a doubly linked list.
342 struct MessageQueue *prev;
345 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
346 * stuck together in memory. Allocated at the end of this struct.
348 const char *message_buf;
351 * Size of the message buf
353 size_t message_buf_size;
356 * Client responsible for queueing the message;
357 * used to check that a client has no two messages
358 * pending for the same target. Can be NULL.
360 struct TransportClient *client;
363 * Using which specific address should we send this message?
365 struct ForeignAddressList *specific_address;
368 * Peer ID of the Neighbour this entry belongs to.
370 struct GNUNET_PeerIdentity neighbour_id;
373 * Plugin that we used for the transmission.
374 * NULL until we scheduled a transmission.
376 struct TransportPlugin *plugin;
379 * At what time should we fail?
381 struct GNUNET_TIME_Absolute timeout;
384 * Internal message of the transport system that should not be
385 * included in the usual SEND-SEND_OK transmission confirmation
386 * traffic management scheme. Typically, "internal_msg" will
387 * be set whenever "client" is NULL (but it is not strictly
393 * How important is the message?
395 unsigned int priority;
401 * For a given Neighbour, which plugins are available
402 * to talk to this peer and what are their costs?
407 * This is a linked list.
409 struct ReadyList *next;
412 * Which of our transport plugins does this entry
415 struct TransportPlugin *plugin;
418 * Transport addresses, latency, and readiness for
419 * this particular plugin.
421 struct ForeignAddressList *addresses;
424 * To which neighbour does this ready list belong to?
426 struct NeighbourList *neighbour;
432 * Entry in linked list of all of our current neighbours.
438 * This is a linked list.
440 struct NeighbourList *next;
443 * Which of our transports is connected to this peer
444 * and what is their status?
446 struct ReadyList *plugins;
449 * Head of list of messages we would like to send to this peer;
450 * must contain at most one message per client.
452 struct MessageQueue *messages_head;
455 * Tail of list of messages we would like to send to this peer; must
456 * contain at most one message per client.
458 struct MessageQueue *messages_tail;
461 * Context for peerinfo iteration.
462 * NULL after we are done processing peerinfo's information.
464 struct GNUNET_PEERINFO_IteratorContext *piter;
467 * Public key for this peer. Valid only if the respective flag is set below.
469 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
472 * Identity of this neighbour.
474 struct GNUNET_PeerIdentity id;
477 * ID of task scheduled to run when this peer is about to
478 * time out (will free resources associated with the peer).
480 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
483 * ID of task scheduled to run when we should retry transmitting
484 * the head of the message queue. Actually triggered when the
485 * transmission is timing out (we trigger instantly when we have
486 * a chance of success).
488 GNUNET_SCHEDULER_TaskIdentifier retry_task;
491 * How long until we should consider this peer dead
492 * (if we don't receive another message in the
495 struct GNUNET_TIME_Absolute peer_timeout;
498 * Tracker for inbound bandwidth.
500 struct GNUNET_BANDWIDTH_Tracker in_tracker;
503 * The latency we have seen for this particular address for
504 * this particular peer. This latency may have been calculated
505 * over multiple transports. This value reflects how long it took
506 * us to receive a response when SENDING via this particular
507 * transport/neighbour/address combination!
509 * FIXME: we need to periodically send PINGs to update this
510 * latency (at least more often than the current "huge" (11h?)
513 struct GNUNET_TIME_Relative latency;
516 * How often has the other peer (recently) violated the
517 * inbound traffic limit? Incremented by 10 per violation,
518 * decremented by 1 per non-violation (for each
521 unsigned int quota_violation_count;
524 * DV distance to this peer (1 if no DV is used).
529 * Have we seen an PONG from this neighbour in the past (and
530 * not had a disconnect since)?
535 * Do we have a valid public key for this neighbour?
537 int public_key_valid;
542 * Message used to ask a peer to validate receipt (to check an address
545 struct TransportPingMessage
549 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
551 struct GNUNET_MessageHeader header;
554 * Random challenge number (in network byte order).
556 uint32_t challenge GNUNET_PACKED;
559 * Who is the intended recipient?
561 struct GNUNET_PeerIdentity target;
567 * Message used to validate a HELLO. The challenge is included in the
568 * confirmation to make matching of replies to requests possible. The
569 * signature signs the original challenge number, our public key, the
570 * sender's address (so that the sender can check that the address we
571 * saw is plausible for him and possibly detect a MiM attack) and a
572 * timestamp (to limit replay).<p>
574 * This message is followed by the address of the
575 * client that we are observing (which is part of what
578 struct TransportPongMessage
582 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
584 struct GNUNET_MessageHeader header;
587 * For padding, always zero.
589 uint32_t reserved GNUNET_PACKED;
594 struct GNUNET_CRYPTO_RsaSignature signature;
597 * What are we signing and why?
599 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
602 * Random challenge number (in network byte order).
604 uint32_t challenge GNUNET_PACKED;
607 * Who signed this message?
609 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
612 * Size of address appended to this message
620 * Linked list of messages to be transmitted to the client. Each
621 * entry is followed by the actual message.
623 struct ClientMessageQueueEntry
626 * This is a doubly-linked list.
628 struct ClientMessageQueueEntry *next;
631 * This is a doubly-linked list.
633 struct ClientMessageQueueEntry *prev;
638 * Client connected to the transport service.
640 struct TransportClient
644 * This is a linked list.
646 struct TransportClient *next;
649 * Handle to the client.
651 struct GNUNET_SERVER_Client *client;
654 * Linked list of messages yet to be transmitted to
657 struct ClientMessageQueueEntry *message_queue_head;
660 * Tail of linked list of messages yet to be transmitted to the
663 struct ClientMessageQueueEntry *message_queue_tail;
666 * Current transmit request handle.
668 struct GNUNET_CONNECTION_TransmitHandle *th;
671 * Is a call to "transmit_send_continuation" pending? If so, we
672 * must not free this struct (even if the corresponding client
673 * disconnects) and instead only remove it from the linked list and
674 * set the "client" field to NULL.
679 * Length of the list of messages pending for this client.
681 unsigned int message_count;
687 * Entry in map of all HELLOs awaiting validation.
689 struct ValidationEntry
693 * The address, actually a pointer to the end
694 * of this struct. Do not free!
699 * Name of the transport.
701 char *transport_name;
704 * The public key of the peer.
706 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
709 * ID of task that will clean up this entry if we don't succeed
710 * with the validation first.
712 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
715 * At what time did we send this validation?
717 struct GNUNET_TIME_Absolute send_time;
720 * Session being validated (or NULL for none).
722 struct Session *session;
730 * Challenge number we used.
738 * Context of currently active requests to peerinfo
739 * for validation of HELLOs.
741 struct CheckHelloValidatedContext
745 * This is a doubly-linked list.
747 struct CheckHelloValidatedContext *next;
750 * This is a doubly-linked list.
752 struct CheckHelloValidatedContext *prev;
755 * Hello that we are validating.
757 const struct GNUNET_HELLO_Message *hello;
760 * Context for peerinfo iteration.
761 * NULL after we are done processing peerinfo's information.
763 struct GNUNET_PEERINFO_IteratorContext *piter;
766 * Was a HELLO known for this peer to peerinfo?
776 static struct GNUNET_HELLO_Message *our_hello;
779 * "version" of "our_hello". Used to see if a given neighbour has
780 * already been sent the latest version of our HELLO message.
782 static unsigned int our_hello_version;
787 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
792 static struct GNUNET_PeerIdentity my_identity;
797 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
802 struct GNUNET_SCHEDULER_Handle *sched;
807 const struct GNUNET_CONFIGURATION_Handle *cfg;
810 * Linked list of all clients to this service.
812 static struct TransportClient *clients;
815 * All loaded plugins.
817 static struct TransportPlugin *plugins;
822 static struct GNUNET_SERVER_Handle *server;
825 * All known neighbours and their HELLOs.
827 static struct NeighbourList *neighbours;
830 * Number of neighbours we'd like to have.
832 static uint32_t max_connect_per_transport;
835 * Head of linked list.
837 static struct CheckHelloValidatedContext *chvc_head;
840 * Tail of linked list.
842 static struct CheckHelloValidatedContext *chvc_tail;
845 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
846 * of the given peer that we are currently validating).
848 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
851 * Handle for reporting statistics.
853 static struct GNUNET_STATISTICS_Handle *stats;
857 * The peer specified by the given neighbour has timed-out or a plugin
858 * has disconnected. We may either need to do nothing (other plugins
859 * still up), or trigger a full disconnect and clean up. This
860 * function updates our state and do the necessary notifications.
861 * Also notifies our clients that the neighbour is now officially
864 * @param n the neighbour list entry for the peer
865 * @param check should we just check if all plugins
866 * disconnected or must we ask all plugins to
869 static void disconnect_neighbour (struct NeighbourList *n, int check);
872 * Check the ready list for the given neighbour and if a plugin is
873 * ready for transmission (and if we have a message), do so!
875 * @param neighbour target peer for which to transmit
877 static void try_transmission_to_peer (struct NeighbourList *neighbour);
881 * Find an entry in the neighbour list for a particular peer.
883 * @return NULL if not found.
885 static struct NeighbourList *
886 find_neighbour (const struct GNUNET_PeerIdentity *key)
888 struct NeighbourList *head = neighbours;
890 while ((head != NULL) &&
891 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
898 * Find an entry in the transport list for a particular transport.
900 * @return NULL if not found.
902 static struct TransportPlugin *
903 find_transport (const char *short_name)
905 struct TransportPlugin *head = plugins;
906 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
913 * Function called to notify a client about the socket being ready to
914 * queue more data. "buf" will be NULL and "size" zero if the socket
915 * was closed for writing in the meantime.
918 * @param size number of bytes available in buf
919 * @param buf where the callee should write the message
920 * @return number of bytes written to buf
923 transmit_to_client_callback (void *cls, size_t size, void *buf)
925 struct TransportClient *client = cls;
926 struct ClientMessageQueueEntry *q;
929 const struct GNUNET_MessageHeader *msg;
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936 "Transmission to client failed, closing connection.\n");
937 /* fatal error with client, free message queue! */
938 while (NULL != (q = client->message_queue_head))
940 GNUNET_STATISTICS_update (stats,
941 gettext_noop ("# bytes discarded (could not transmit to client)"),
942 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
944 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
945 client->message_queue_tail,
949 client->message_count = 0;
954 while (NULL != (q = client->message_queue_head))
956 msg = (const struct GNUNET_MessageHeader *) &q[1];
957 msize = ntohs (msg->size);
958 if (msize + tsize > size)
961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 "Transmitting message of type %u to client.\n",
965 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
966 client->message_queue_tail,
968 memcpy (&cbuf[tsize], msg, msize);
971 client->message_count--;
975 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
976 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
978 GNUNET_TIME_UNIT_FOREVER_REL,
979 &transmit_to_client_callback,
981 GNUNET_assert (client->th != NULL);
988 * Mark the given FAL entry as 'connected' (and hence preferred for
989 * sending); also mark all others for the same peer as 'not connected'
990 * (since only one can be preferred).
992 * @param fal address to set to 'connected'
995 mark_address_connected (struct ForeignAddressList *fal)
997 struct ForeignAddressList *pos;
1000 if (fal->connected == GNUNET_YES)
1001 return; /* nothing to do */
1003 pos = fal->ready_list->addresses;
1006 if (GNUNET_YES == pos->connected)
1008 GNUNET_break (cnt == GNUNET_YES);
1010 pos->connected = GNUNET_NO;
1014 fal->connected = GNUNET_YES;
1015 if (GNUNET_YES == cnt)
1016 GNUNET_STATISTICS_update (stats,
1017 gettext_noop ("# connected addresses"),
1024 * Send the specified message to the specified client. Since multiple
1025 * messages may be pending for the same client at a time, this code
1026 * makes sure that no message is lost.
1028 * @param client client to transmit the message to
1029 * @param msg the message to send
1030 * @param may_drop can this message be dropped if the
1031 * message queue for this client is getting far too large?
1034 transmit_to_client (struct TransportClient *client,
1035 const struct GNUNET_MessageHeader *msg, int may_drop)
1037 struct ClientMessageQueueEntry *q;
1040 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1042 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1044 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1045 client->message_count, MAX_PENDING);
1046 /* TODO: call to statistics... */
1049 msize = ntohs (msg->size);
1050 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1051 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1052 memcpy (&q[1], msg, msize);
1053 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1054 client->message_queue_tail,
1055 client->message_queue_tail,
1057 client->message_count++;
1058 if (client->th == NULL)
1060 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1062 GNUNET_TIME_UNIT_FOREVER_REL,
1063 &transmit_to_client_callback,
1065 GNUNET_assert (client->th != NULL);
1071 * Transmit a 'SEND_OK' notification to the given client for the
1074 * @param client who to notify
1075 * @param n neighbour to notify about
1076 * @param result status code for the transmission request
1079 transmit_send_ok (struct TransportClient *client,
1080 struct NeighbourList *n,
1083 struct SendOkMessage send_ok_msg;
1085 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1086 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1087 send_ok_msg.success = htonl (result);
1088 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1089 send_ok_msg.peer = n->id;
1090 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1095 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1096 * upon "completion" of a send request. This tells the API
1097 * that it is now legal to send another message to the given
1100 * @param cls closure, identifies the entry on the
1101 * message queue that was transmitted and the
1102 * client responsible for queueing the message
1103 * @param target the peer receiving the message
1104 * @param result GNUNET_OK on success, if the transmission
1105 * failed, we should not tell the client to transmit
1109 transmit_send_continuation (void *cls,
1110 const struct GNUNET_PeerIdentity *target,
1113 struct MessageQueue *mq = cls;
1114 struct NeighbourList *n;
1116 GNUNET_STATISTICS_update (stats,
1117 gettext_noop ("# bytes pending with plugins"),
1118 - (int64_t) mq->message_buf_size,
1120 if (result == GNUNET_OK)
1122 GNUNET_STATISTICS_update (stats,
1123 gettext_noop ("# bytes successfully transmitted by plugins"),
1124 mq->message_buf_size,
1129 GNUNET_STATISTICS_update (stats,
1130 gettext_noop ("# bytes with transmission failure by plugins"),
1131 mq->message_buf_size,
1134 n = find_neighbour(&mq->neighbour_id);
1135 GNUNET_assert (n != NULL);
1136 if (mq->specific_address != NULL)
1138 if (result == GNUNET_OK)
1140 mq->specific_address->timeout =
1141 GNUNET_TIME_relative_to_absolute
1142 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1143 mark_address_connected (mq->specific_address);
1147 if (mq->specific_address->connected != GNUNET_NO)
1149 GNUNET_STATISTICS_update (stats,
1150 gettext_noop ("# connected addresses"),
1153 mq->specific_address->connected = GNUNET_NO;
1156 if (! mq->internal_msg)
1157 mq->specific_address->in_transmit = GNUNET_NO;
1159 if (mq->client != NULL)
1160 transmit_send_ok (mq->client, n, result);
1162 try_transmission_to_peer (n);
1167 * Find an address in any of the available transports for
1168 * the given neighbour that would be good for message
1169 * transmission. This is essentially the transport selection
1172 * @param neighbour for whom to select an address
1173 * @return selected address, NULL if we have none
1175 struct ForeignAddressList *
1176 find_ready_address(struct NeighbourList *neighbour)
1178 struct ReadyList *head = neighbour->plugins;
1179 struct ForeignAddressList *addresses;
1180 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1181 struct ForeignAddressList *best_address;
1183 best_address = NULL;
1184 while (head != NULL)
1186 addresses = head->addresses;
1187 while (addresses != NULL)
1189 if ( (addresses->timeout.value < now.value) &&
1190 (addresses->connected == GNUNET_YES) )
1193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194 "Marking long-time inactive connection to `%4s' as down.\n",
1195 GNUNET_i2s (&neighbour->id));
1197 GNUNET_STATISTICS_update (stats,
1198 gettext_noop ("# connected addresses"),
1201 addresses->connected = GNUNET_NO;
1203 addresses = addresses->next;
1206 addresses = head->addresses;
1207 while (addresses != NULL)
1209 #if DEBUG_TRANSPORT > 1
1210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1211 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1212 GNUNET_a2s (addresses->addr,
1213 addresses->addrlen),
1214 GNUNET_i2s (&neighbour->id),
1215 addresses->connected,
1216 addresses->in_transmit,
1217 addresses->validated,
1218 addresses->connect_attempts,
1219 (unsigned long long) addresses->timeout.value,
1220 (unsigned int) addresses->distance);
1222 if ( ( (best_address == NULL) ||
1223 (addresses->connected == GNUNET_YES) ||
1224 (best_address->connected == GNUNET_NO) ) &&
1225 (addresses->in_transmit == GNUNET_NO) &&
1226 ( (best_address == NULL) ||
1227 (addresses->latency.value < best_address->latency.value)) )
1228 best_address = addresses;
1229 /* FIXME: also give lower-latency addresses that are not
1230 connected a chance some times... */
1231 addresses = addresses->next;
1235 if (best_address != NULL)
1238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1239 "Best address found has latency of %llu ms.\n",
1240 best_address->latency.value);
1245 GNUNET_STATISTICS_update (stats,
1246 gettext_noop ("# transmission attempts failed (no address)"),
1250 return best_address;
1256 * We should re-try transmitting to the given peer,
1257 * hopefully we've learned something in the meantime.
1260 retry_transmission_task (void *cls,
1261 const struct GNUNET_SCHEDULER_TaskContext *tc)
1263 struct NeighbourList *n = cls;
1265 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1266 try_transmission_to_peer (n);
1271 * Check the ready list for the given neighbour and if a plugin is
1272 * ready for transmission (and if we have a message), do so!
1274 * @param neighbour target peer for which to transmit
1277 try_transmission_to_peer (struct NeighbourList *neighbour)
1279 struct ReadyList *rl;
1280 struct MessageQueue *mq;
1281 struct GNUNET_TIME_Relative timeout;
1285 if (neighbour->messages_head == NULL)
1288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1289 "Transmission queue for `%4s' is empty\n",
1290 GNUNET_i2s (&neighbour->id));
1292 return; /* nothing to do */
1295 mq = neighbour->messages_head;
1296 force_address = GNUNET_YES;
1297 if (mq->specific_address == NULL)
1299 mq->specific_address = find_ready_address(neighbour);
1300 GNUNET_STATISTICS_update (stats,
1301 gettext_noop ("# transport selected peer address freely"),
1304 force_address = GNUNET_NO;
1306 if (mq->specific_address == NULL)
1308 GNUNET_STATISTICS_update (stats,
1309 gettext_noop ("# transport failed to selected peer address"),
1312 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1313 if (timeout.value == 0)
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317 "No destination address available to transmit message of size %u to peer `%4s'\n",
1318 mq->message_buf_size,
1319 GNUNET_i2s (&mq->neighbour_id));
1321 GNUNET_STATISTICS_update (stats,
1322 gettext_noop ("# bytes in message queue for other peers"),
1323 - (int64_t) mq->message_buf_size,
1325 GNUNET_STATISTICS_update (stats,
1326 gettext_noop ("# bytes discarded (no destination address available)"),
1327 mq->message_buf_size,
1329 if (mq->client != NULL)
1330 transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1331 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1332 neighbour->messages_tail,
1335 return; /* nobody ready */
1337 GNUNET_STATISTICS_update (stats,
1338 gettext_noop ("# message delivery deferred (no address)"),
1341 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1342 GNUNET_SCHEDULER_cancel (sched,
1343 neighbour->retry_task);
1344 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1346 &retry_transmission_task,
1349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1350 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1351 mq->message_buf_size,
1352 GNUNET_i2s (&mq->neighbour_id),
1355 /* FIXME: might want to trigger peerinfo lookup here
1356 (unless that's already pending...) */
1359 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1360 neighbour->messages_tail,
1362 if (mq->specific_address->connected == GNUNET_NO)
1363 mq->specific_address->connect_attempts++;
1364 rl = mq->specific_address->ready_list;
1365 mq->plugin = rl->plugin;
1366 if (!mq->internal_msg)
1367 mq->specific_address->in_transmit = GNUNET_YES;
1369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1370 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1371 mq->message_buf_size,
1372 GNUNET_i2s (&neighbour->id),
1373 GNUNET_a2s (mq->specific_address->addr,
1374 mq->specific_address->addrlen),
1375 rl->plugin->short_name);
1377 GNUNET_STATISTICS_update (stats,
1378 gettext_noop ("# bytes in message queue for other peers"),
1379 - (int64_t) mq->message_buf_size,
1381 GNUNET_STATISTICS_update (stats,
1382 gettext_noop ("# bytes pending with plugins"),
1383 mq->message_buf_size,
1385 ret = rl->plugin->api->send (rl->plugin->api->cls,
1388 mq->message_buf_size,
1390 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1391 mq->specific_address->session,
1392 mq->specific_address->addr,
1393 mq->specific_address->addrlen,
1395 &transmit_send_continuation, mq);
1398 /* failure, but 'send' would not call continuation in this case,
1399 so we need to do it here! */
1400 transmit_send_continuation (mq,
1408 * Send the specified message to the specified peer.
1410 * @param client source of the transmission request (can be NULL)
1411 * @param peer_address ForeignAddressList where we should send this message
1412 * @param priority how important is the message
1413 * @param timeout how long do we have to transmit?
1414 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1415 * @param message_buf_size total size of all messages in message_buf
1416 * @param is_internal is this an internal message; these are pre-pended and
1417 * also do not count for plugins being "ready" to transmit
1418 * @param neighbour handle to the neighbour for transmission
1421 transmit_to_peer (struct TransportClient *client,
1422 struct ForeignAddressList *peer_address,
1423 unsigned int priority,
1424 struct GNUNET_TIME_Relative timeout,
1425 const char *message_buf,
1426 size_t message_buf_size,
1427 int is_internal, struct NeighbourList *neighbour)
1429 struct MessageQueue *mq;
1434 /* check for duplicate submission */
1435 mq = neighbour->messages_head;
1438 if (mq->client == client)
1440 /* client transmitted to same peer twice
1441 before getting SEND_OK! */
1449 GNUNET_STATISTICS_update (stats,
1450 gettext_noop ("# bytes in message queue for other peers"),
1453 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1454 mq->specific_address = peer_address;
1455 mq->client = client;
1456 memcpy (&mq[1], message_buf, message_buf_size);
1457 mq->message_buf = (const char*) &mq[1];
1458 mq->message_buf_size = message_buf_size;
1459 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1460 mq->internal_msg = is_internal;
1461 mq->priority = priority;
1462 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1464 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1465 neighbour->messages_tail,
1468 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1469 neighbour->messages_tail,
1470 neighbour->messages_tail,
1472 try_transmission_to_peer (neighbour);
1479 struct GeneratorContext
1481 struct TransportPlugin *plug_pos;
1482 struct OwnAddressList *addr_pos;
1483 struct GNUNET_TIME_Absolute expiration;
1491 address_generator (void *cls, size_t max, void *buf)
1493 struct GeneratorContext *gc = cls;
1496 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1498 gc->plug_pos = gc->plug_pos->next;
1499 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1501 if (NULL == gc->plug_pos)
1506 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1509 gc->addr_pos->addrlen, buf, max);
1510 gc->addr_pos = gc->addr_pos->next;
1516 * Construct our HELLO message from all of the addresses of
1517 * all of the transports.
1522 struct GNUNET_HELLO_Message *hello;
1523 struct TransportClient *cpos;
1524 struct NeighbourList *npos;
1525 struct GeneratorContext gc;
1527 gc.plug_pos = plugins;
1528 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1529 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1530 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1533 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1535 GNUNET_STATISTICS_update (stats,
1536 gettext_noop ("# refreshed my HELLO"),
1540 while (cpos != NULL)
1542 transmit_to_client (cpos,
1543 (const struct GNUNET_MessageHeader *) hello,
1548 GNUNET_free_non_null (our_hello);
1550 our_hello_version++;
1551 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1553 while (npos != NULL)
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1557 "Transmitting updated `%s' to neighbour `%4s'\n",
1558 "HELLO", GNUNET_i2s (&npos->id));
1560 GNUNET_STATISTICS_update (stats,
1561 gettext_noop ("# transmitted my HELLO to other peers"),
1564 transmit_to_peer (NULL, NULL, 0,
1565 HELLO_ADDRESS_EXPIRATION,
1566 (const char *) our_hello,
1567 GNUNET_HELLO_size(our_hello),
1575 * Task used to clean up expired addresses for a plugin.
1577 * @param cls closure
1581 expire_address_task (void *cls,
1582 const struct GNUNET_SCHEDULER_TaskContext *tc);
1586 * Update the list of addresses for this plugin,
1587 * expiring those that are past their expiration date.
1589 * @param plugin addresses of which plugin should be recomputed?
1590 * @param fresh set to GNUNET_YES if a new address was added
1591 * and we need to regenerate the HELLO even if nobody
1595 update_addresses (struct TransportPlugin *plugin, int fresh)
1597 static struct GNUNET_TIME_Absolute last_update;
1598 struct GNUNET_TIME_Relative min_remaining;
1599 struct GNUNET_TIME_Relative remaining;
1600 struct GNUNET_TIME_Absolute now;
1601 struct OwnAddressList *pos;
1602 struct OwnAddressList *prev;
1603 struct OwnAddressList *next;
1606 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1607 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1608 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1609 now = GNUNET_TIME_absolute_get ();
1610 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1611 expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1613 pos = plugin->addresses;
1617 if (pos->expires.value < now.value)
1619 expired = GNUNET_YES;
1621 plugin->addresses = pos->next;
1623 prev->next = pos->next;
1628 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1629 if (remaining.value < min_remaining.value)
1630 min_remaining = remaining;
1636 if (expired || fresh)
1641 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1642 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1644 plugin->address_update_task
1645 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1647 &expire_address_task, plugin);
1652 * Task used to clean up expired addresses for a plugin.
1654 * @param cls closure
1658 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1660 struct TransportPlugin *plugin = cls;
1662 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1663 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1664 update_addresses (plugin, GNUNET_NO);
1669 * Iterator over hash map entries that NULLs the session of validation
1670 * entries that match the given session.
1672 * @param cls closure (the 'struct Session*' to match against)
1673 * @param key current key code (peer ID, not used)
1674 * @param value value in the hash map ('struct ValidationEntry*')
1675 * @return GNUNET_YES (we should continue to iterate)
1678 remove_session_validations (void *cls,
1679 const GNUNET_HashCode * key,
1682 struct Session *session = cls;
1683 struct ValidationEntry *ve = value;
1685 if (session == ve->session)
1692 * Function that will be called whenever the plugin internally
1693 * cleans up a session pointer and hence the service needs to
1694 * discard all of those sessions as well. Plugins that do not
1695 * use sessions can simply omit calling this function and always
1696 * use NULL wherever a session pointer is needed.
1698 * @param cls closure
1699 * @param peer which peer was the session for
1700 * @param session which session is being destoyed
1703 plugin_env_session_end (void *cls,
1704 const struct GNUNET_PeerIdentity *peer,
1705 struct Session *session)
1707 struct TransportPlugin *p = cls;
1708 struct NeighbourList *nl;
1709 struct ReadyList *rl;
1710 struct ForeignAddressList *pos;
1711 struct ForeignAddressList *prev;
1713 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1714 &remove_session_validations,
1716 nl = find_neighbour (peer);
1722 if (rl->plugin == p)
1729 pos = rl->addresses;
1730 while ( (pos != NULL) &&
1731 (pos->session != session) )
1738 pos->session = NULL;
1739 if (pos->addrlen != 0)
1742 rl->addresses = pos->next;
1744 prev->next = pos->next;
1750 * Function that must be called by each plugin to notify the
1751 * transport service about the addresses under which the transport
1752 * provided by the plugin can be reached.
1754 * @param cls closure
1755 * @param name name of the transport that generated the address
1756 * @param addr one of the addresses of the host, NULL for the last address
1757 * the specific address format depends on the transport
1758 * @param addrlen length of the address
1759 * @param expires when should this address automatically expire?
1762 plugin_env_notify_address (void *cls,
1766 struct GNUNET_TIME_Relative expires)
1768 struct TransportPlugin *p = cls;
1769 struct OwnAddressList *al;
1770 struct GNUNET_TIME_Absolute abex;
1772 abex = GNUNET_TIME_relative_to_absolute (expires);
1773 GNUNET_assert (p == find_transport (name));
1778 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1780 if (al->expires.value < abex.value)
1787 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1789 al->next = p->addresses;
1792 al->addrlen = addrlen;
1793 memcpy (&al[1], addr, addrlen);
1794 update_addresses (p, GNUNET_YES);
1799 * Notify all of our clients about a peer connecting.
1802 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1803 struct GNUNET_TIME_Relative latency,
1806 struct ConnectInfoMessage cim;
1807 struct TransportClient *cpos;
1810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1811 "Notifying clients about connection from `%s'\n",
1814 GNUNET_STATISTICS_update (stats,
1815 gettext_noop ("# peers connected"),
1818 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1819 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1820 cim.distance = htonl (distance);
1821 cim.latency = GNUNET_TIME_relative_hton (latency);
1822 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1824 while (cpos != NULL)
1826 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1833 * Notify all of our clients about a peer disconnecting.
1836 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1838 struct DisconnectInfoMessage dim;
1839 struct TransportClient *cpos;
1842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1843 "Notifying clients about lost connection to `%s'\n",
1846 GNUNET_STATISTICS_update (stats,
1847 gettext_noop ("# peers connected"),
1850 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1851 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1852 dim.reserved = htonl (0);
1853 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1855 while (cpos != NULL)
1857 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1864 * Find a ForeignAddressList entry for the given neighbour
1865 * that matches the given address and transport.
1867 * @param neighbour which peer we care about
1868 * @param tname name of the transport plugin
1869 * @param session session to look for, NULL for 'any'; otherwise
1870 * can be used for the service to "learn" this session ID
1871 * @param addr binary address
1872 * @param addrlen length of addr
1873 * @return NULL if no such entry exists
1875 static struct ForeignAddressList *
1876 find_peer_address(struct NeighbourList *neighbour,
1878 struct Session *session,
1882 struct ReadyList *head;
1883 struct ForeignAddressList *address_head;
1885 head = neighbour->plugins;
1886 while (head != NULL)
1888 if (0 == strcmp (tname, head->plugin->short_name))
1895 address_head = head->addresses;
1896 while ( (address_head != NULL) &&
1897 ( (address_head->addrlen != addrlen) ||
1898 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1899 address_head = address_head->next;
1900 if ( (session != NULL) && (address_head != NULL) )
1901 address_head->session = session; /* learn it! */
1902 return address_head;
1907 * Get the peer address struct for the given neighbour and
1908 * address. If it doesn't yet exist, create it.
1910 * @param neighbour which peer we care about
1911 * @param tname name of the transport plugin
1912 * @param session session of the plugin, or NULL for none
1913 * @param addr binary address
1914 * @param addrlen length of addr
1915 * @return NULL if we do not have a transport plugin for 'tname'
1917 static struct ForeignAddressList *
1918 add_peer_address (struct NeighbourList *neighbour,
1920 struct Session *session,
1924 struct ReadyList *head;
1925 struct ForeignAddressList *ret;
1927 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
1930 head = neighbour->plugins;
1931 while (head != NULL)
1933 if (0 == strcmp (tname, head->plugin->short_name))
1939 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1940 ret->session = session;
1943 ret->addr = (const char*) &ret[1];
1944 memcpy (&ret[1], addr, addrlen);
1950 ret->addrlen = addrlen;
1951 ret->expires = GNUNET_TIME_relative_to_absolute
1952 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1953 ret->latency = GNUNET_TIME_relative_get_forever();
1955 ret->timeout = GNUNET_TIME_relative_to_absolute
1956 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1957 ret->ready_list = head;
1958 ret->next = head->addresses;
1959 head->addresses = ret;
1965 * Closure for 'add_validated_address'.
1967 struct AddValidatedAddressContext
1970 * Entry that has been validated.
1972 const struct ValidationEntry *ve;
1975 * Flag set after we have added the address so
1976 * that we terminate the iteration next time.
1983 * Callback function used to fill a buffer of max bytes with a list of
1984 * addresses in the format used by HELLOs. Should use
1985 * "GNUNET_HELLO_add_address" as a helper function.
1987 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1988 * @param max maximum number of bytes that can be written to buf
1989 * @param buf where to write the address information
1990 * @return number of bytes written, 0 to signal the
1991 * end of the iteration.
1994 add_validated_address (void *cls,
1995 size_t max, void *buf)
1997 struct AddValidatedAddressContext *avac = cls;
1998 const struct ValidationEntry *ve = avac->ve;
2000 if (GNUNET_YES == avac->done)
2002 avac->done = GNUNET_YES;
2003 return GNUNET_HELLO_add_address (ve->transport_name,
2004 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2014 * Closure for 'check_address_exists'.
2016 struct CheckAddressExistsClosure
2019 * Address to check for.
2024 * Name of the transport.
2034 * Set to GNUNET_YES if the address exists.
2041 * Iterator over hash map entries. Checks if the given
2042 * validation entry is for the same address as what is given
2045 * @param cls the 'struct CheckAddressExistsClosure*'
2046 * @param key current key code (ignored)
2047 * @param value value in the hash map ('struct ValidationEntry')
2048 * @return GNUNET_YES if we should continue to
2049 * iterate (mismatch), GNUNET_NO if not (entry matched)
2052 check_address_exists (void *cls,
2053 const GNUNET_HashCode * key,
2056 struct CheckAddressExistsClosure *caec = cls;
2057 struct ValidationEntry *ve = value;
2058 if ( (0 == strcmp (caec->tname,
2059 ve->transport_name)) &&
2060 (caec->addrlen == ve->addrlen) &&
2061 (0 == memcmp (caec->addr,
2065 caec->exists = GNUNET_YES;
2073 * HELLO validation cleanup task (validation failed).
2075 * @param cls the 'struct ValidationEntry' that failed
2076 * @param tc scheduler context (unused)
2079 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2081 struct ValidationEntry *va = cls;
2082 struct GNUNET_PeerIdentity pid;
2084 GNUNET_STATISTICS_update (stats,
2085 gettext_noop ("# address validation timeouts"),
2088 GNUNET_CRYPTO_hash (&va->publicKey,
2090 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2092 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2095 GNUNET_free (va->transport_name);
2101 neighbour_timeout_task (void *cls,
2102 const struct GNUNET_SCHEDULER_TaskContext *tc)
2104 struct NeighbourList *n = cls;
2107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2108 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2110 GNUNET_STATISTICS_update (stats,
2111 gettext_noop ("# disconnects due to timeout"),
2114 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2115 disconnect_neighbour (n, GNUNET_NO);
2120 * Schedule the job that will cause us to send a PING to the
2121 * foreign address to evaluate its validity and latency.
2123 * @param fal address to PING
2126 schedule_next_ping (struct ForeignAddressList *fal);
2130 * Add the given address to the list of foreign addresses
2131 * available for the given peer (check for duplicates).
2133 * @param cls the respective 'struct NeighbourList' to update
2134 * @param tname name of the transport
2135 * @param expiration expiration time
2136 * @param addr the address
2137 * @param addrlen length of the address
2138 * @return GNUNET_OK (always)
2141 add_to_foreign_address_list (void *cls,
2143 struct GNUNET_TIME_Absolute expiration,
2144 const void *addr, size_t addrlen)
2146 struct NeighbourList *n = cls;
2147 struct ForeignAddressList *fal;
2150 GNUNET_STATISTICS_update (stats,
2151 gettext_noop ("# valid peer addresses returned by peerinfo"),
2155 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2160 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2161 GNUNET_a2s (addr, addrlen),
2163 GNUNET_i2s (&n->id),
2166 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2169 GNUNET_STATISTICS_update (stats,
2170 gettext_noop ("# previously validated addresses lacking transport"),
2176 fal->expires = GNUNET_TIME_absolute_max (expiration,
2178 schedule_next_ping (fal);
2184 fal->expires = GNUNET_TIME_absolute_max (expiration,
2189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2190 "Failed to add new address for `%4s'\n",
2191 GNUNET_i2s (&n->id));
2194 if (fal->validated == GNUNET_NO)
2196 fal->validated = GNUNET_YES;
2197 GNUNET_STATISTICS_update (stats,
2198 gettext_noop ("# peer addresses considered valid"),
2202 if (try == GNUNET_YES)
2204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2205 "Have new addresses, will try to trigger transmissions.\n");
2206 try_transmission_to_peer (n);
2213 * Add addresses in validated HELLO "h" to the set of addresses
2214 * we have for this peer.
2216 * @param cls closure ('struct NeighbourList*')
2217 * @param peer id of the peer, NULL for last call
2218 * @param h hello message for the peer (can be NULL)
2219 * @param trust amount of trust we have in the peer (not used)
2222 add_hello_for_peer (void *cls,
2223 const struct GNUNET_PeerIdentity *peer,
2224 const struct GNUNET_HELLO_Message *h,
2227 struct NeighbourList *n = cls;
2235 return; /* no HELLO available */
2237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2238 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2242 if (GNUNET_YES != n->public_key_valid)
2244 GNUNET_HELLO_get_key (h, &n->publicKey);
2245 n->public_key_valid = GNUNET_YES;
2247 GNUNET_HELLO_iterate_addresses (h,
2249 &add_to_foreign_address_list,
2255 * Create a fresh entry in our neighbour list for the given peer.
2256 * Will try to transmit our current HELLO to the new neighbour.
2258 * @param peer the peer for which we create the entry
2259 * @return the new neighbour list entry
2261 static struct NeighbourList *
2262 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2264 struct NeighbourList *n;
2265 struct TransportPlugin *tp;
2266 struct ReadyList *rl;
2268 GNUNET_assert (our_hello != NULL);
2269 GNUNET_STATISTICS_update (stats,
2270 gettext_noop ("# active neighbours"),
2273 n = GNUNET_malloc (sizeof (struct NeighbourList));
2274 n->next = neighbours;
2278 GNUNET_TIME_relative_to_absolute
2279 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2280 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2281 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2282 MAX_BANDWIDTH_CARRY_S);
2286 if (tp->api->send != NULL)
2288 rl = GNUNET_malloc (sizeof (struct ReadyList));
2290 rl->next = n->plugins;
2293 rl->addresses = NULL;
2297 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2299 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2300 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2301 &neighbour_timeout_task, n);
2302 n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2303 0, GNUNET_TIME_UNIT_FOREVER_REL,
2304 &add_hello_for_peer, n);
2305 transmit_to_peer (NULL, NULL, 0,
2306 HELLO_ADDRESS_EXPIRATION,
2307 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2314 * Send periodic PING messages to a give foreign address.
2316 * @param cls our 'struct PeriodicValidationContext*'
2317 * @param tc task context
2320 send_periodic_ping (void *cls,
2321 const struct GNUNET_SCHEDULER_TaskContext *tc)
2323 struct ForeignAddressList *peer_address = cls;
2324 struct TransportPlugin *tp;
2325 struct ValidationEntry *va;
2326 struct NeighbourList *neighbour;
2327 struct TransportPingMessage ping;
2328 struct CheckAddressExistsClosure caec;
2330 uint16_t hello_size;
2333 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2334 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2336 tp = peer_address->ready_list->plugin;
2337 neighbour = peer_address->ready_list->neighbour;
2338 if (GNUNET_YES != neighbour->public_key_valid)
2340 /* no public key yet, try again later */
2341 schedule_next_ping (peer_address);
2344 caec.addr = peer_address->addr;
2345 caec.addrlen = peer_address->addrlen;
2346 caec.tname = tp->short_name;
2347 caec.exists = GNUNET_NO;
2348 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2349 &check_address_exists,
2351 if (caec.exists == GNUNET_YES)
2353 /* During validation attempts we will likely trigger the other
2354 peer trying to validate our address which in turn will cause
2355 it to send us its HELLO, so we expect to hit this case rather
2356 frequently. Only print something if we are very verbose. */
2357 #if DEBUG_TRANSPORT > 1
2358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2360 GNUNET_a2s (peer_address->addr,
2361 peer_address->addrlen),
2363 GNUNET_i2s (&neighbour->id));
2365 schedule_next_ping (peer_address);
2368 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2369 va->transport_name = GNUNET_strdup (tp->short_name);
2370 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2372 va->send_time = GNUNET_TIME_absolute_get();
2373 va->session = peer_address->session;
2374 va->addr = (const void*) &va[1];
2375 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2376 va->addrlen = peer_address->addrlen;
2378 memcpy(&va->publicKey,
2379 &neighbour->publicKey,
2380 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2382 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2383 HELLO_VERIFICATION_TIMEOUT,
2384 &timeout_hello_validation,
2386 GNUNET_CONTAINER_multihashmap_put (validation_map,
2387 &neighbour->id.hashPubKey,
2389 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2390 hello_size = GNUNET_HELLO_size(our_hello);
2391 tsize = sizeof(struct TransportPingMessage) + hello_size;
2392 message_buf = GNUNET_malloc(tsize);
2393 ping.challenge = htonl(va->challenge);
2394 ping.header.size = htons(sizeof(struct TransportPingMessage));
2395 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2396 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2397 memcpy(message_buf, our_hello, hello_size);
2398 memcpy(&message_buf[hello_size],
2400 sizeof(struct TransportPingMessage));
2401 #if DEBUG_TRANSPORT_REVALIDATION
2402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2404 GNUNET_a2s (peer_address->addr,
2405 peer_address->addrlen),
2407 GNUNET_i2s (&neighbour->id),
2408 "HELLO", hello_size,
2409 "PING", sizeof (struct TransportPingMessage));
2411 GNUNET_STATISTICS_update (stats,
2412 gettext_noop ("# PING messages sent for re-validation"),
2415 transmit_to_peer (NULL, peer_address,
2416 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2417 HELLO_VERIFICATION_TIMEOUT,
2419 GNUNET_YES, neighbour);
2420 GNUNET_free(message_buf);
2421 schedule_next_ping (peer_address);
2426 * Schedule the job that will cause us to send a PING to the
2427 * foreign address to evaluate its validity and latency.
2429 * @param fal address to PING
2432 schedule_next_ping (struct ForeignAddressList *fal)
2434 struct GNUNET_TIME_Relative delay;
2436 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2438 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2439 delay.value /= 2; /* do before expiration */
2440 delay = GNUNET_TIME_relative_min (delay,
2441 LATENCY_EVALUATION_MAX_DELAY);
2442 if (GNUNET_YES != fal->estimated)
2444 delay = GNUNET_TIME_UNIT_ZERO;
2445 fal->estimated = GNUNET_YES;
2447 if (GNUNET_YES == fal->connected)
2449 delay = GNUNET_TIME_relative_min (delay,
2450 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2452 /* FIXME: also adjust delay based on how close the last
2453 observed latency is to the latency of the best alternative */
2454 /* bound how fast we can go */
2455 delay = GNUNET_TIME_relative_max (delay,
2456 GNUNET_TIME_UNIT_SECONDS);
2457 /* randomize a bit (to avoid doing all at the same time) */
2458 delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2459 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
2461 &send_periodic_ping,
2467 * Iterator over hash map entries. Checks if the given validation
2468 * entry is for the same challenge as what is given in the PONG.
2470 * @param cls the 'struct TransportPongMessage*'
2471 * @param key peer identity
2472 * @param value value in the hash map ('struct ValidationEntry')
2473 * @return GNUNET_YES if we should continue to
2474 * iterate (mismatch), GNUNET_NO if not (entry matched)
2477 check_pending_validation (void *cls,
2478 const GNUNET_HashCode * key,
2481 const struct TransportPongMessage *pong = cls;
2482 struct ValidationEntry *ve = value;
2483 struct AddValidatedAddressContext avac;
2484 unsigned int challenge = ntohl(pong->challenge);
2485 struct GNUNET_HELLO_Message *hello;
2486 struct GNUNET_PeerIdentity target;
2487 struct NeighbourList *n;
2488 struct ForeignAddressList *fal;
2490 if (ve->challenge != challenge)
2493 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
2498 GNUNET_break_op (0);
2503 if (ve->addr != NULL)
2504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2505 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2507 GNUNET_a2s ((const struct sockaddr *) ve->addr,
2509 ve->transport_name);
2511 GNUNET_STATISTICS_update (stats,
2512 gettext_noop ("# address validation successes"),
2515 /* create the updated HELLO */
2516 GNUNET_CRYPTO_hash (&ve->publicKey,
2517 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2518 &target.hashPubKey);
2519 avac.done = GNUNET_NO;
2521 hello = GNUNET_HELLO_create (&ve->publicKey,
2522 &add_validated_address,
2524 GNUNET_PEERINFO_add_peer (cfg, sched,
2527 GNUNET_free (hello);
2528 n = find_neighbour (&target);
2531 n->publicKey = ve->publicKey;
2532 n->public_key_valid = GNUNET_YES;
2533 fal = add_peer_address (n,
2538 GNUNET_assert (fal != NULL);
2539 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2540 fal->validated = GNUNET_YES;
2541 mark_address_connected (fal);
2542 GNUNET_STATISTICS_update (stats,
2543 gettext_noop ("# peer addresses considered valid"),
2546 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2547 schedule_next_ping (fal);
2548 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2549 n->latency = fal->latency;
2551 n->latency.value = (fal->latency.value + n->latency.value) / 2;
2552 n->distance = fal->distance;
2553 if (GNUNET_NO == n->received_pong)
2555 n->received_pong = GNUNET_YES;
2556 notify_clients_connect (&target, n->latency, n->distance);
2558 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2560 GNUNET_SCHEDULER_cancel (sched,
2562 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2563 try_transmission_to_peer (n);
2567 /* clean up validation entry */
2568 GNUNET_assert (GNUNET_YES ==
2569 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2572 GNUNET_SCHEDULER_cancel (sched,
2574 GNUNET_free (ve->transport_name);
2581 * Function that will be called if we receive a validation
2582 * of an address challenge that we transmitted to another
2583 * peer. Note that the validation should only be considered
2584 * acceptable if the challenge matches AND if the sender
2585 * address is at least a plausible address for this peer
2586 * (otherwise we may be seeing a MiM attack).
2588 * @param cls closure
2589 * @param message the pong message
2590 * @param peer who responded to our challenge
2591 * @param sender_address string describing our sender address (as observed
2592 * by the other peer in binary format)
2593 * @param sender_address_len number of bytes in 'sender_address'
2596 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2597 const struct GNUNET_PeerIdentity *peer,
2598 const char *sender_address,
2599 size_t sender_address_len)
2601 #if DEBUG_TRANSPORT > 1
2602 /* we get tons of these that just get discarded, only log
2603 if we are quite verbose */
2604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2605 "Receiving `%s' message from `%4s'.\n", "PONG",
2608 GNUNET_STATISTICS_update (stats,
2609 gettext_noop ("# PONG messages received"),
2612 if (GNUNET_SYSERR !=
2613 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2615 &check_pending_validation,
2618 /* This is *expected* to happen a lot since we send
2619 PONGs to *all* known addresses of the sender of
2620 the PING, so most likely we get multiple PONGs
2621 per PING, and all but the first PONG will end up
2622 here. So really we should not print anything here
2623 unless we want to be very, very verbose... */
2624 #if DEBUG_TRANSPORT > 2
2625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2626 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2635 /* FIXME: add given address to potential pool of our addresses
2637 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2638 _("Another peer saw us using the address `%s' via `%s'.\n"),
2639 GNUNET_a2s ((const struct sockaddr *) &pong[1],
2640 ntohs(pong->addrlen)),
2641 va->transport_name);
2647 * Check if the given address is already being validated; if not,
2648 * append the given address to the list of entries that are being be
2649 * validated and initiate validation.
2651 * @param cls closure ('struct CheckHelloValidatedContext *')
2652 * @param tname name of the transport
2653 * @param expiration expiration time
2654 * @param addr the address
2655 * @param addrlen length of the address
2656 * @return GNUNET_OK (always)
2659 run_validation (void *cls,
2661 struct GNUNET_TIME_Absolute expiration,
2662 const void *addr, size_t addrlen)
2664 struct CheckHelloValidatedContext *chvc = cls;
2665 struct GNUNET_PeerIdentity id;
2666 struct TransportPlugin *tp;
2667 struct ValidationEntry *va;
2668 struct NeighbourList *neighbour;
2669 struct ForeignAddressList *peer_address;
2670 struct TransportPingMessage ping;
2671 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2672 struct CheckAddressExistsClosure caec;
2674 uint16_t hello_size;
2677 GNUNET_STATISTICS_update (stats,
2678 gettext_noop ("# peer addresses scheduled for validation"),
2681 tp = find_transport (tname);
2684 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2685 GNUNET_ERROR_TYPE_BULK,
2687 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2689 GNUNET_STATISTICS_update (stats,
2690 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2695 GNUNET_HELLO_get_key (chvc->hello, &pk);
2696 GNUNET_CRYPTO_hash (&pk,
2698 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2701 caec.addrlen = addrlen;
2703 caec.exists = GNUNET_NO;
2704 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2705 &check_address_exists,
2707 if (caec.exists == GNUNET_YES)
2709 /* During validation attempts we will likely trigger the other
2710 peer trying to validate our address which in turn will cause
2711 it to send us its HELLO, so we expect to hit this case rather
2712 frequently. Only print something if we are very verbose. */
2713 #if DEBUG_TRANSPORT > 1
2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2716 GNUNET_a2s (addr, addrlen),
2720 GNUNET_STATISTICS_update (stats,
2721 gettext_noop ("# peer addresses not validated (in progress)"),
2726 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2727 va->transport_name = GNUNET_strdup (tname);
2728 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2730 va->send_time = GNUNET_TIME_absolute_get();
2731 va->addr = (const void*) &va[1];
2732 memcpy (&va[1], addr, addrlen);
2733 va->addrlen = addrlen;
2734 GNUNET_HELLO_get_key (chvc->hello,
2736 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2737 HELLO_VERIFICATION_TIMEOUT,
2738 &timeout_hello_validation,
2740 GNUNET_CONTAINER_multihashmap_put (validation_map,
2743 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2744 neighbour = find_neighbour(&id);
2745 if (neighbour == NULL)
2746 neighbour = setup_new_neighbour(&id);
2747 neighbour->publicKey = va->publicKey;
2748 neighbour->public_key_valid = GNUNET_YES;
2749 peer_address = add_peer_address (neighbour, tname, NULL, addr, addrlen);
2750 GNUNET_assert(peer_address != NULL);
2751 hello_size = GNUNET_HELLO_size(our_hello);
2752 tsize = sizeof(struct TransportPingMessage) + hello_size;
2753 message_buf = GNUNET_malloc(tsize);
2754 ping.challenge = htonl(va->challenge);
2755 ping.header.size = htons(sizeof(struct TransportPingMessage));
2756 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2757 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2758 memcpy(message_buf, our_hello, hello_size);
2759 memcpy(&message_buf[hello_size],
2761 sizeof(struct TransportPingMessage));
2763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2764 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2765 GNUNET_a2s (addr, addrlen),
2768 "HELLO", hello_size,
2769 "PING", sizeof (struct TransportPingMessage));
2771 GNUNET_STATISTICS_update (stats,
2772 gettext_noop ("# PING messages sent for initial validation"),
2775 transmit_to_peer (NULL, peer_address,
2776 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2777 HELLO_VERIFICATION_TIMEOUT,
2779 GNUNET_YES, neighbour);
2780 GNUNET_free(message_buf);
2786 * Check if addresses in validated hello "h" overlap with
2787 * those in "chvc->hello" and validate the rest.
2789 * @param cls closure
2790 * @param peer id of the peer, NULL for last call
2791 * @param h hello message for the peer (can be NULL)
2792 * @param trust amount of trust we have in the peer (not used)
2795 check_hello_validated (void *cls,
2796 const struct GNUNET_PeerIdentity *peer,
2797 const struct GNUNET_HELLO_Message *h,
2800 struct CheckHelloValidatedContext *chvc = cls;
2801 struct GNUNET_HELLO_Message *plain_hello;
2802 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2803 struct GNUNET_PeerIdentity target;
2804 struct NeighbourList *n;
2809 GNUNET_CONTAINER_DLL_remove (chvc_head,
2812 if (GNUNET_NO == chvc->hello_known)
2814 /* notify PEERINFO about the peer now, so that we at least
2815 have the public key if some other component needs it */
2816 GNUNET_HELLO_get_key (chvc->hello, &pk);
2817 GNUNET_CRYPTO_hash (&pk,
2818 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2819 &target.hashPubKey);
2820 plain_hello = GNUNET_HELLO_create (&pk,
2823 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2824 GNUNET_free (plain_hello);
2826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2827 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2829 GNUNET_i2s (&target));
2831 GNUNET_STATISTICS_update (stats,
2832 gettext_noop ("# new HELLOs requiring full validation"),
2835 GNUNET_HELLO_iterate_addresses (chvc->hello,
2842 GNUNET_STATISTICS_update (stats,
2843 gettext_noop ("# duplicate HELLO (peer known)"),
2853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2854 "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2858 chvc->hello_known = GNUNET_YES;
2859 n = find_neighbour (peer);
2862 GNUNET_HELLO_iterate_addresses (h,
2864 &add_to_foreign_address_list,
2866 try_transmission_to_peer (n);
2870 GNUNET_STATISTICS_update (stats,
2871 gettext_noop ("# no existing neighbour record (validating HELLO)"),
2875 GNUNET_STATISTICS_update (stats,
2876 gettext_noop ("# HELLO validations (update case)"),
2879 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2881 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2887 * Process HELLO-message.
2889 * @param plugin transport involved, may be NULL
2890 * @param message the actual message
2891 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2894 process_hello (struct TransportPlugin *plugin,
2895 const struct GNUNET_MessageHeader *message)
2898 struct GNUNET_PeerIdentity target;
2899 const struct GNUNET_HELLO_Message *hello;
2900 struct CheckHelloValidatedContext *chvc;
2901 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2903 hsize = ntohs (message->size);
2904 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2905 (hsize < sizeof (struct GNUNET_MessageHeader)))
2908 return GNUNET_SYSERR;
2910 GNUNET_STATISTICS_update (stats,
2911 gettext_noop ("# HELLOs received for validation"),
2914 /* first, check if load is too high */
2915 if (GNUNET_SCHEDULER_get_load (sched,
2916 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2918 GNUNET_STATISTICS_update (stats,
2919 gettext_noop ("# HELLOs ignored due to high load"),
2924 hello = (const struct GNUNET_HELLO_Message *) message;
2925 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2927 GNUNET_break_op (0);
2928 return GNUNET_SYSERR;
2930 GNUNET_CRYPTO_hash (&publicKey,
2931 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2932 &target.hashPubKey);
2933 if (0 == memcmp (&my_identity,
2935 sizeof (struct GNUNET_PeerIdentity)))
2937 GNUNET_STATISTICS_update (stats,
2938 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2943 #if DEBUG_TRANSPORT > 1
2944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2945 "Processing `%s' message for `%4s' of size %u\n",
2947 GNUNET_i2s (&target),
2948 GNUNET_HELLO_size(hello));
2950 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2951 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2952 memcpy (&chvc[1], hello, hsize);
2953 GNUNET_CONTAINER_DLL_insert (chvc_head,
2956 /* finally, check if HELLO was previously validated
2957 (continuation will then schedule actual validation) */
2958 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2962 HELLO_VERIFICATION_TIMEOUT,
2963 &check_hello_validated, chvc);
2969 * The peer specified by the given neighbour has timed-out or a plugin
2970 * has disconnected. We may either need to do nothing (other plugins
2971 * still up), or trigger a full disconnect and clean up. This
2972 * function updates our state and does the necessary notifications.
2973 * Also notifies our clients that the neighbour is now officially
2976 * @param n the neighbour list entry for the peer
2977 * @param check should we just check if all plugins
2978 * disconnected or must we ask all plugins to
2982 disconnect_neighbour (struct NeighbourList *n, int check)
2984 struct ReadyList *rpos;
2985 struct NeighbourList *npos;
2986 struct NeighbourList *nprev;
2987 struct MessageQueue *mq;
2988 struct ForeignAddressList *peer_addresses;
2989 struct ForeignAddressList *peer_pos;
2991 if (GNUNET_YES == check)
2994 while (NULL != rpos)
2996 peer_addresses = rpos->addresses;
2997 while (peer_addresses != NULL)
2999 if (GNUNET_YES == peer_addresses->connected)
3000 return; /* still connected */
3001 peer_addresses = peer_addresses->next;
3007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3008 "Disconnecting from `%4s'\n",
3009 GNUNET_i2s (&n->id));
3011 /* remove n from neighbours list */
3014 while ((npos != NULL) && (npos != n))
3019 GNUNET_assert (npos != NULL);
3021 neighbours = n->next;
3023 nprev->next = n->next;
3025 /* notify all clients about disconnect */
3026 if (GNUNET_YES == n->received_pong)
3027 notify_clients_disconnect (&n->id);
3029 /* clean up all plugins, cancel connections and pending transmissions */
3030 while (NULL != (rpos = n->plugins))
3032 n->plugins = rpos->next;
3033 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3034 while (rpos->addresses != NULL)
3036 peer_pos = rpos->addresses;
3037 rpos->addresses = peer_pos->next;
3038 if (peer_pos->connected == GNUNET_YES)
3039 GNUNET_STATISTICS_update (stats,
3040 gettext_noop ("# connected addresses"),
3043 if (GNUNET_YES == peer_pos->validated)
3044 GNUNET_STATISTICS_update (stats,
3045 gettext_noop ("# peer addresses considered valid"),
3048 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3050 GNUNET_SCHEDULER_cancel (sched,
3051 peer_pos->revalidate_task);
3052 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3054 GNUNET_free(peer_pos);
3059 /* free all messages on the queue */
3060 while (NULL != (mq = n->messages_head))
3062 GNUNET_STATISTICS_update (stats,
3063 gettext_noop ("# bytes in message queue for other peers"),
3064 - (int64_t) mq->message_buf_size,
3066 GNUNET_STATISTICS_update (stats,
3067 gettext_noop ("# bytes discarded due to disconnect"),
3068 mq->message_buf_size,
3070 GNUNET_CONTAINER_DLL_remove (n->messages_head,
3073 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
3075 sizeof(struct GNUNET_PeerIdentity)));
3078 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3080 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3081 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3083 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3085 GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3086 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3088 if (n->piter != NULL)
3090 GNUNET_PEERINFO_iterate_cancel (n->piter);
3093 /* finally, free n itself */
3094 GNUNET_STATISTICS_update (stats,
3095 gettext_noop ("# active neighbours"),
3103 * We have received a PING message from someone. Need to send a PONG message
3104 * in response to the peer by any means necessary.
3107 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3108 const struct GNUNET_PeerIdentity *peer,
3109 const char *sender_address,
3110 size_t sender_address_len)
3112 struct TransportPlugin *plugin = cls;
3113 struct TransportPingMessage *ping;
3114 struct TransportPongMessage *pong;
3115 struct NeighbourList *n;
3116 struct ReadyList *rl;
3117 struct ForeignAddressList *fal;
3119 if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3121 GNUNET_break_op (0);
3122 return GNUNET_SYSERR;
3124 ping = (struct TransportPingMessage *) message;
3125 if (0 != memcmp (&ping->target,
3126 plugin->env.my_identity,
3127 sizeof (struct GNUNET_PeerIdentity)))
3129 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3130 _("Received `%s' message not destined for me!\n"),
3132 return GNUNET_SYSERR;
3135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3136 "Processing `%s' from `%s'\n",
3138 GNUNET_a2s ((const struct sockaddr *)sender_address,
3139 sender_address_len));
3141 GNUNET_STATISTICS_update (stats,
3142 gettext_noop ("# PING messages received"),
3145 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3146 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3147 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3148 pong->purpose.size =
3149 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3151 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3152 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3153 pong->challenge = ping->challenge;
3154 pong->addrlen = htons(sender_address_len);
3155 memcpy(&pong->signer,
3157 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3158 memcpy (&pong[1], sender_address, sender_address_len);
3159 GNUNET_assert (GNUNET_OK ==
3160 GNUNET_CRYPTO_rsa_sign (my_private_key,
3161 &pong->purpose, &pong->signature));
3162 n = find_neighbour(peer);
3163 GNUNET_assert (n != NULL);
3164 /* first try reliable response transmission */
3168 fal = rl->addresses;
3171 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3174 ntohs (pong->header.size),
3175 TRANSPORT_PONG_PRIORITY,
3176 HELLO_VERIFICATION_TIMEOUT,
3184 GNUNET_STATISTICS_update (stats,
3185 gettext_noop ("# PONGs unicast via reliable transport"),
3195 /* no reliable method found, do multicast */
3196 GNUNET_STATISTICS_update (stats,
3197 gettext_noop ("# PONGs multicast to all available addresses"),
3203 fal = rl->addresses;
3206 transmit_to_peer(NULL, fal,
3207 TRANSPORT_PONG_PRIORITY,
3208 HELLO_VERIFICATION_TIMEOUT,
3210 ntohs(pong->header.size),
3223 * Function called by the plugin for each received message.
3224 * Update data volumes, possibly notify plugins about
3225 * reducing the rate at which they read from the socket
3226 * and generally forward to our receive callback.
3228 * @param cls the "struct TransportPlugin *" we gave to the plugin
3229 * @param peer (claimed) identity of the other peer
3230 * @param message the message, NULL if we only care about
3231 * learning about the delay until we should receive again
3232 * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3233 * @param session identifier used for this session (can be NULL)
3234 * @param sender_address binary address of the sender (if observed)
3235 * @param sender_address_len number of bytes in sender_address
3236 * @return how long the plugin should wait until receiving more data
3237 * (plugins that do not support this, can ignore the return value)
3239 static struct GNUNET_TIME_Relative
3240 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3241 const struct GNUNET_MessageHeader *message,
3242 unsigned int distance,
3243 struct Session *session,
3244 const char *sender_address,
3245 size_t sender_address_len)
3247 struct TransportPlugin *plugin = cls;
3248 struct ReadyList *service_context;
3249 struct TransportClient *cpos;
3250 struct InboundMessage *im;
3251 struct ForeignAddressList *peer_address;
3253 struct NeighbourList *n;
3254 struct GNUNET_TIME_Relative ret;
3256 n = find_neighbour (peer);
3258 n = setup_new_neighbour (peer);
3259 service_context = n->plugins;
3260 while ((service_context != NULL) && (plugin != service_context->plugin))
3261 service_context = service_context->next;
3262 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3263 peer_address = NULL;
3264 if (message != NULL)
3266 if ( (session != NULL) ||
3267 (sender_address != NULL) )
3268 peer_address = add_peer_address (n,
3272 sender_address_len);
3273 if (peer_address != NULL)
3275 peer_address->distance = distance;
3276 if (GNUNET_YES == peer_address->validated)
3277 mark_address_connected (peer_address);
3278 peer_address->timeout
3280 GNUNET_TIME_relative_to_absolute
3281 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3282 schedule_next_ping (peer_address);
3284 /* update traffic received amount ... */
3285 msize = ntohs (message->size);
3286 GNUNET_STATISTICS_update (stats,
3287 gettext_noop ("# bytes received from other peers"),
3290 n->distance = distance;
3292 GNUNET_TIME_relative_to_absolute
3293 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3294 GNUNET_SCHEDULER_cancel (sched,
3297 GNUNET_SCHEDULER_add_delayed (sched,
3298 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3299 &neighbour_timeout_task, n);
3300 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3302 /* dropping message due to frequent inbound volume violations! */
3303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3304 GNUNET_ERROR_TYPE_BULK,
3306 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
3307 n->in_tracker.available_bytes_per_s__,
3308 n->quota_violation_count);
3309 GNUNET_STATISTICS_update (stats,
3310 gettext_noop ("# bandwidth quota violations by other peers"),
3313 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
3315 switch (ntohs (message->type))
3317 case GNUNET_MESSAGE_TYPE_HELLO:
3318 GNUNET_STATISTICS_update (stats,
3319 gettext_noop ("# HELLO messages received from other peers"),
3322 process_hello (plugin, message);
3324 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3325 handle_ping (plugin, message, peer, sender_address, sender_address_len);
3327 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3328 handle_pong (plugin, message, peer, sender_address, sender_address_len);
3332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3333 "Received message of type %u from `%4s', sending to all clients.\n",
3334 ntohs (message->type), GNUNET_i2s (peer));
3336 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3339 n->quota_violation_count++;
3341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3342 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3343 n->in_tracker.available_bytes_per_s__,
3344 n->quota_violation_count);
3346 /* Discount 32k per violation */
3347 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3352 if (n->quota_violation_count > 0)
3354 /* try to add 32k back */
3355 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3357 n->quota_violation_count--;
3360 GNUNET_STATISTICS_update (stats,
3361 gettext_noop ("# payload received from other peers"),
3364 /* transmit message to all clients */
3365 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3366 im->header.size = htons (sizeof (struct InboundMessage) + msize);
3367 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3368 im->latency = GNUNET_TIME_relative_hton (n->latency);
3370 memcpy (&im[1], message, msize);
3372 while (cpos != NULL)
3374 transmit_to_client (cpos, &im->header, GNUNET_YES);
3380 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3383 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3384 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3385 (unsigned long long) n->in_tracker.consumption_since_last_update__,
3386 (unsigned int) n->in_tracker.available_bytes_per_s__,
3387 (unsigned long long) ret.value);
3388 GNUNET_STATISTICS_update (stats,
3389 gettext_noop ("# ms throttling suggested"),
3390 (int64_t) ret.value,
3398 * Handle START-message. This is the first message sent to us
3399 * by any client which causes us to add it to our list.
3401 * @param cls closure (always NULL)
3402 * @param client identification of the client
3403 * @param message the actual message
3406 handle_start (void *cls,
3407 struct GNUNET_SERVER_Client *client,
3408 const struct GNUNET_MessageHeader *message)
3410 struct TransportClient *c;
3411 struct ConnectInfoMessage cim;
3412 struct NeighbourList *n;
3415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3416 "Received `%s' request from client\n", "START");
3421 if (c->client == client)
3423 /* client already on our list! */
3425 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3430 c = GNUNET_malloc (sizeof (struct TransportClient));
3434 if (our_hello != NULL)
3437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3438 "Sending our own `%s' to new client\n", "HELLO");
3440 transmit_to_client (c,
3441 (const struct GNUNET_MessageHeader *) our_hello,
3443 /* tell new client about all existing connections */
3444 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3445 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3449 if (GNUNET_YES == n->received_pong)
3452 cim.latency = GNUNET_TIME_relative_hton (n->latency);
3453 cim.distance = htonl (n->distance);
3454 transmit_to_client (c, &cim.header, GNUNET_NO);
3459 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3464 * Handle HELLO-message.
3466 * @param cls closure (always NULL)
3467 * @param client identification of the client
3468 * @param message the actual message
3471 handle_hello (void *cls,
3472 struct GNUNET_SERVER_Client *client,
3473 const struct GNUNET_MessageHeader *message)
3477 GNUNET_STATISTICS_update (stats,
3478 gettext_noop ("# HELLOs received from clients"),
3481 ret = process_hello (NULL, message);
3482 GNUNET_SERVER_receive_done (client, ret);
3487 * Handle SEND-message.
3489 * @param cls closure (always NULL)
3490 * @param client identification of the client
3491 * @param message the actual message
3494 handle_send (void *cls,
3495 struct GNUNET_SERVER_Client *client,
3496 const struct GNUNET_MessageHeader *message)
3498 struct TransportClient *tc;
3499 struct NeighbourList *n;
3500 const struct OutboundMessage *obm;
3501 const struct GNUNET_MessageHeader *obmm;
3505 size = ntohs (message->size);
3507 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3510 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3513 GNUNET_STATISTICS_update (stats,
3514 gettext_noop ("# payload received for other peers"),
3517 obm = (const struct OutboundMessage *) message;
3519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3520 "Received `%s' request from client with target `%4s'\n",
3521 "SEND", GNUNET_i2s (&obm->peer));
3523 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3524 msize = ntohs (obmm->size);
3525 if (size != msize + sizeof (struct OutboundMessage))
3528 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3531 n = find_neighbour (&obm->peer);
3533 n = setup_new_neighbour (&obm->peer);
3535 while ((tc != NULL) && (tc->client != client))
3539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3540 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3542 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3544 transmit_to_peer (tc, NULL, ntohl (obm->priority),
3545 GNUNET_TIME_relative_ntoh (obm->timeout),
3547 ntohs (obmm->size), GNUNET_NO, n);
3548 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3553 * Handle SET_QUOTA-message.
3555 * @param cls closure (always NULL)
3556 * @param client identification of the client
3557 * @param message the actual message
3560 handle_set_quota (void *cls,
3561 struct GNUNET_SERVER_Client *client,
3562 const struct GNUNET_MessageHeader *message)
3564 const struct QuotaSetMessage *qsm =
3565 (const struct QuotaSetMessage *) message;
3566 struct NeighbourList *n;
3568 GNUNET_STATISTICS_update (stats,
3569 gettext_noop ("# SET QUOTA messages received"),
3572 n = find_neighbour (&qsm->peer);
3575 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3576 GNUNET_STATISTICS_update (stats,
3577 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3584 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3586 (unsigned int) ntohl (qsm->quota.value__),
3587 (unsigned int) n->in_tracker.available_bytes_per_s__,
3588 GNUNET_i2s (&qsm->peer));
3590 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3592 if (0 == ntohl (qsm->quota.value__))
3593 disconnect_neighbour (n, GNUNET_NO);
3594 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3599 * Take the given address and append it to the set of results send back to
3602 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3603 * @param address the resolved name, NULL to indicate the last response
3606 transmit_address_to_client (void *cls, const char *address)
3608 struct GNUNET_SERVER_TransmitContext *tc = cls;
3611 if (NULL == address)
3614 slen = strlen (address) + 1;
3615 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3616 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3617 if (NULL == address)
3618 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3623 * Handle AddressLookup-message.
3625 * @param cls closure (always NULL)
3626 * @param client identification of the client
3627 * @param message the actual message
3630 handle_address_lookup (void *cls,
3631 struct GNUNET_SERVER_Client *client,
3632 const struct GNUNET_MessageHeader *message)
3634 const struct AddressLookupMessage *alum;
3635 struct TransportPlugin *lsPlugin;
3636 const char *nameTransport;
3637 const char *address;
3639 struct GNUNET_SERVER_TransmitContext *tc;
3640 struct GNUNET_TIME_Absolute timeout;
3641 struct GNUNET_TIME_Relative rtimeout;
3644 size = ntohs (message->size);
3645 if (size < sizeof (struct AddressLookupMessage))
3647 GNUNET_break_op (0);
3648 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3651 alum = (const struct AddressLookupMessage *) message;
3652 uint32_t addressLen = ntohl (alum->addrlen);
3653 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3655 GNUNET_break_op (0);
3656 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3659 address = (const char *) &alum[1];
3660 nameTransport = (const char *) &address[addressLen];
3662 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3664 GNUNET_break_op (0);
3665 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3668 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
3669 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
3670 numeric = ntohl (alum->numeric_only);
3671 lsPlugin = find_transport (nameTransport);
3672 if (NULL == lsPlugin)
3674 tc = GNUNET_SERVER_transmit_context_create (client);
3675 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3676 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3677 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3680 tc = GNUNET_SERVER_transmit_context_create (client);
3681 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
3683 address, addressLen,
3686 &transmit_address_to_client, tc);
3690 * List of handlers for the messages understood by this
3693 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3694 {&handle_start, NULL,
3695 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3696 {&handle_hello, NULL,
3697 GNUNET_MESSAGE_TYPE_HELLO, 0},
3698 {&handle_send, NULL,
3699 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3700 {&handle_set_quota, NULL,
3701 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3702 {&handle_address_lookup, NULL,
3703 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3710 * Setup the environment for this plugin.
3713 create_environment (struct TransportPlugin *plug)
3715 plug->env.cfg = cfg;
3716 plug->env.sched = sched;
3717 plug->env.my_identity = &my_identity;
3718 plug->env.cls = plug;
3719 plug->env.receive = &plugin_env_receive;
3720 plug->env.notify_address = &plugin_env_notify_address;
3721 plug->env.session_end = &plugin_env_session_end;
3722 plug->env.max_connections = max_connect_per_transport;
3723 plug->env.stats = stats;
3728 * Start the specified transport (load the plugin).
3731 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
3733 struct TransportPlugin *plug;
3736 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3737 _("Loading `%s' transport plugin\n"), name);
3738 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3739 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3740 create_environment (plug);
3741 plug->short_name = GNUNET_strdup (name);
3742 plug->lib_name = libname;
3743 plug->next = plugins;
3745 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3746 if (plug->api == NULL)
3748 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3749 _("Failed to load transport plugin for `%s'\n"), name);
3750 GNUNET_free (plug->short_name);
3751 plugins = plug->next;
3752 GNUNET_free (libname);
3759 * Called whenever a client is disconnected. Frees our
3760 * resources associated with that client.
3762 * @param cls closure
3763 * @param client identification of the client
3766 client_disconnect_notification (void *cls,
3767 struct GNUNET_SERVER_Client *client)
3769 struct TransportClient *pos;
3770 struct TransportClient *prev;
3771 struct ClientMessageQueueEntry *mqe;
3776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3777 "Client disconnected, cleaning up.\n");
3781 while ((pos != NULL) && (pos->client != client))
3788 while (NULL != (mqe = pos->message_queue_head))
3790 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3791 pos->message_queue_tail,
3793 pos->message_count--;
3797 clients = pos->next;
3799 prev->next = pos->next;
3800 if (GNUNET_YES == pos->tcs_pending)
3805 if (pos->th != NULL)
3807 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3810 GNUNET_break (0 == pos->message_count);
3816 * Iterator to free entries in the validation_map.
3818 * @param cls closure (unused)
3819 * @param key current key code
3820 * @param value value in the hash map (validation to abort)
3821 * @return GNUNET_YES (always)
3824 abort_validation (void *cls,
3825 const GNUNET_HashCode * key,
3828 struct ValidationEntry *va = value;
3830 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3831 GNUNET_free (va->transport_name);
3838 * Function called when the service shuts down. Unloads our plugins
3839 * and cancels pending validations.
3841 * @param cls closure, unused
3842 * @param tc task context (unused)
3845 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3847 struct TransportPlugin *plug;
3848 struct OwnAddressList *al;
3849 struct CheckHelloValidatedContext *chvc;
3851 while (neighbours != NULL)
3852 disconnect_neighbour (neighbours, GNUNET_NO);
3854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3855 "Transport service is unloading plugins...\n");
3857 while (NULL != (plug = plugins))
3859 plugins = plug->next;
3860 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
3862 GNUNET_SCHEDULER_cancel (plug->env.sched,
3863 plug->address_update_task);
3864 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
3866 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3867 GNUNET_free (plug->lib_name);
3868 GNUNET_free (plug->short_name);
3869 while (NULL != (al = plug->addresses))
3871 plug->addresses = al->next;
3876 if (my_private_key != NULL)
3877 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3878 GNUNET_free_non_null (our_hello);
3880 /* free 'chvc' data structure */
3881 while (NULL != (chvc = chvc_head))
3883 chvc_head = chvc->next;
3884 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3889 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3892 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3893 validation_map = NULL;
3896 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3903 * Initiate transport service.
3905 * @param cls closure
3906 * @param s scheduler to use
3907 * @param serv the initialized server
3908 * @param c configuration to use
3912 struct GNUNET_SCHEDULER_Handle *s,
3913 struct GNUNET_SERVER_Handle *serv,
3914 const struct GNUNET_CONFIGURATION_Handle *c)
3919 unsigned long long tneigh;
3924 stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3925 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3926 /* parse configuration */
3928 GNUNET_CONFIGURATION_get_value_number (c,
3933 GNUNET_CONFIGURATION_get_value_filename (c,
3935 "HOSTKEY", &keyfile)))
3937 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3939 ("Transport service is lacking key configuration settings. Exiting.\n"));
3940 GNUNET_SCHEDULER_shutdown (s);
3943 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3946 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3947 validation_map = NULL;
3950 max_connect_per_transport = (uint32_t) tneigh;
3951 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3952 GNUNET_free (keyfile);
3953 if (my_private_key == NULL)
3955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3957 ("Transport service could not access hostkey. Exiting.\n"));
3958 GNUNET_SCHEDULER_shutdown (s);
3961 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3964 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3965 validation_map = NULL;
3968 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3969 GNUNET_CRYPTO_hash (&my_public_key,
3970 sizeof (my_public_key), &my_identity.hashPubKey);
3971 /* setup notification */
3973 GNUNET_SERVER_disconnect_notify (server,
3974 &client_disconnect_notification, NULL);
3975 /* load plugins... */
3978 GNUNET_CONFIGURATION_get_value_string (c,
3979 "TRANSPORT", "PLUGINS", &plugs))
3981 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3982 _("Starting transport plugins `%s'\n"), plugs);
3983 pos = strtok (plugs, " ");
3986 start_transport (server, pos);
3988 pos = strtok (NULL, " ");
3990 GNUNET_free (plugs);
3992 GNUNET_SCHEDULER_add_delayed (sched,
3993 GNUNET_TIME_UNIT_FOREVER_REL,
3994 &shutdown_task, NULL);
3999 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4001 /* process client requests */
4002 GNUNET_SERVER_add_handlers (server, handlers);
4007 * The main function for the transport service.
4009 * @param argc number of arguments from the command line
4010 * @param argv command line arguments
4011 * @return 0 ok, 1 on error
4014 main (int argc, char *const *argv)
4016 return (GNUNET_OK ==
4017 GNUNET_SERVICE_run (argc,
4020 GNUNET_SERVICE_OPTION_NONE,
4021 &run, NULL)) ? 0 : 1;
4024 /* end of gnunet-service-transport.c */