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 * - if we do not receive an ACK in response to our
28 * HELLO, retransmit HELLO!
31 #include "gnunet_client_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_getopt_lib.h"
34 #include "gnunet_hello_lib.h"
35 #include "gnunet_os_lib.h"
36 #include "gnunet_peerinfo_service.h"
37 #include "gnunet_plugin_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_service_lib.h"
40 #include "gnunet_signatures.h"
41 #include "plugin_transport.h"
42 #include "transport.h"
45 * How many messages can we have pending for a given client process
46 * before we start to drop incoming messages? We typically should
47 * have only one client and so this would be the primary buffer for
48 * messages, so the number should be chosen rather generously.
50 * The expectation here is that most of the time the queue is large
51 * enough so that a drop is virtually never required.
53 #define MAX_PENDING 128
56 * How often should we try to reconnect to a peer using a particular
57 * transport plugin before giving up? Note that the plugin may be
58 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
60 #define MAX_CONNECT_RETRY 3
63 * How often must a peer violate bandwidth quotas before we start
64 * to simply drop its messages?
66 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
69 * How long until a HELLO verification attempt should time out?
70 * Must be rather small, otherwise a partially successful HELLO
71 * validation (some addresses working) might not be available
72 * before a client's request for a connection fails for good.
73 * Besides, if a single request to an address takes a long time,
74 * then the peer is unlikely worthwhile anyway.
76 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
79 * How often do we re-add (cheaper) plugins to our list of plugins
80 * to try for a given connected peer?
82 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
85 * After how long do we expire an address in a HELLO
86 * that we just validated? This value is also used
87 * for our own addresses when we create a HELLO.
89 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
93 * Entry in linked list of network addresses.
98 * This is a linked list.
100 struct AddressList *next;
103 * The address, actually a pointer to the end
104 * of this struct. Do not free!
109 * How long until we auto-expire this address (unless it is
110 * re-confirmed by the transport)?
112 struct GNUNET_TIME_Absolute expires;
123 * Entry in linked list of all of our plugins.
125 struct TransportPlugin
129 * This is a linked list.
131 struct TransportPlugin *next;
134 * API of the transport as returned by the plugin's
135 * initialization function.
137 struct GNUNET_TRANSPORT_PluginFunctions *api;
140 * Short name for the plugin (i.e. "tcp").
145 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
150 * List of our known addresses for this transport.
152 struct AddressList *addresses;
155 * Environment this transport service is using
158 struct GNUNET_TRANSPORT_PluginEnvironment env;
161 * ID of task that is used to clean up expired addresses.
163 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
167 * Set to GNUNET_YES if we need to scrap the existing
168 * list of "addresses" and start fresh when we receive
169 * the next address update from a transport. Set to
170 * GNUNET_NO if we should just add the new address
171 * to the list and wait for the commit call.
176 struct NeighbourList;
179 * For each neighbour we keep a list of messages
180 * that we still want to transmit to the neighbour.
186 * This is a linked list.
188 struct MessageQueue *next;
191 * The message we want to transmit.
193 struct GNUNET_MessageHeader *message;
196 * Client responsible for queueing the message;
197 * used to check that a client has not two messages
198 * pending for the same target. Can be NULL.
200 struct TransportClient *client;
203 * Neighbour this entry belongs to.
205 struct NeighbourList *neighbour;
208 * Plugin that we used for the transmission.
209 * NULL until we scheduled a transmission.
211 struct TransportPlugin *plugin;
214 * Internal message of the transport system that should not be
215 * included in the usual SEND-SEND_OK transmission confirmation
216 * traffic management scheme. Typically, "internal_msg" will
217 * be set whenever "client" is NULL (but it is not strictly
223 * How important is the message?
225 unsigned int priority;
231 * For a given Neighbour, which plugins are available
232 * to talk to this peer and what are their costs?
238 * This is a linked list.
240 struct ReadyList *next;
243 * Which of our transport plugins does this entry
246 struct TransportPlugin *plugin;
249 * Neighbour this entry belongs to.
251 struct NeighbourList *neighbour;
254 * What was the last latency observed for this plugin
255 * and peer? Invalid if connected is GNUNET_NO.
257 struct GNUNET_TIME_Relative latency;
260 * If we did not successfully transmit a message to the given peer
261 * via this connection during the specified time, we should consider
262 * the connection to be dead. This is used in the case that a TCP
263 * transport simply stalls writing to the stream but does not
264 * formerly get a signal that the other peer died.
266 struct GNUNET_TIME_Absolute timeout;
269 * Is this plugin currently connected? The first time
270 * we transmit or send data to a peer via a particular
271 * plugin, we set this to GNUNET_YES. If we later get
272 * an error (disconnect notification or transmission
273 * failure), we set it back to GNUNET_NO. Each time the
274 * value is set to GNUNET_YES, we increment the
275 * "connect_attempts" counter. If that one reaches a
276 * particular threshold, we consider the plugin to not
277 * be working properly at this time for the given peer
278 * and remove it from the eligible list.
283 * How often have we tried to connect using this plugin?
285 unsigned int connect_attempts;
288 * Is this plugin ready to transmit to the specific target?
289 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
290 * transmission is in progress, "transmit_ready" is set to
299 * Entry in linked list of all of our current neighbours.
305 * This is a linked list.
307 struct NeighbourList *next;
310 * Which of our transports is connected to this peer
311 * and what is their status?
313 struct ReadyList *plugins;
316 * List of messages we would like to send to this peer;
317 * must contain at most one message per client.
319 struct MessageQueue *messages;
322 * Identity of this neighbour.
324 struct GNUNET_PeerIdentity id;
327 * ID of task scheduled to run when this peer is about to
328 * time out (will free resources associated with the peer).
330 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
333 * How long until we should consider this peer dead
334 * (if we don't receive another message in the
337 struct GNUNET_TIME_Absolute peer_timeout;
340 * At what time did we reset last_received last?
342 struct GNUNET_TIME_Absolute last_quota_update;
345 * At what time should we try to again add plugins to
348 struct GNUNET_TIME_Absolute retry_plugins_time;
351 * How many bytes have we received since the "last_quota_update"
354 uint64_t last_received;
357 * Global quota for inbound traffic for the neighbour in bytes/ms.
362 * How often has the other peer (recently) violated the
363 * inbound traffic limit? Incremented by 10 per violation,
364 * decremented by 1 per non-violation (for each
367 unsigned int quota_violation_count;
370 * Have we seen an ACK from this neighbour in the past?
371 * (used to make up a fake ACK for clients connecting after
372 * the neighbour connected to us).
380 * Linked list of messages to be transmitted to
381 * the client. Each entry is followed by the
384 struct ClientMessageQueueEntry
387 * This is a linked list.
389 struct ClientMessageQueueEntry *next;
394 * Client connected to the transport service.
396 struct TransportClient
400 * This is a linked list.
402 struct TransportClient *next;
405 * Handle to the client.
407 struct GNUNET_SERVER_Client *client;
410 * Linked list of messages yet to be transmitted to
413 struct ClientMessageQueueEntry *message_queue_head;
416 * Tail of linked list of messages yet to be transmitted to the
419 struct ClientMessageQueueEntry *message_queue_tail;
422 * Is a call to "transmit_send_continuation" pending? If so, we
423 * must not free this struct (even if the corresponding client
424 * disconnects) and instead only remove it from the linked list and
425 * set the "client" field to NULL.
430 * Length of the list of messages pending for this client.
432 unsigned int message_count;
438 * For each HELLO, we may have to validate multiple addresses;
439 * each address gets its own request entry.
441 struct ValidationAddress
444 * This is a linked list.
446 struct ValidationAddress *next;
449 * Name of the transport.
451 char *transport_name;
454 * When should this validated address expire?
456 struct GNUNET_TIME_Absolute expiration;
459 * Length of the address we are validating.
464 * Challenge number we used.
469 * Set to GNUNET_YES if the challenge was met,
470 * GNUNET_SYSERR if we know it failed, GNUNET_NO
471 * if we are waiting on a response.
478 * Entry in linked list of all HELLOs awaiting validation.
480 struct ValidationList
484 * This is a linked list.
486 struct ValidationList *next;
489 * Linked list with one entry per address from the HELLO
490 * that needs to be validated.
492 struct ValidationAddress *addresses;
495 * The public key of the peer.
497 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
500 * When does this record time-out? (assuming the
501 * challenge goes unanswered)
503 struct GNUNET_TIME_Absolute timeout;
509 * HELLOs awaiting validation.
511 static struct ValidationList *pending_validations;
516 static struct GNUNET_HELLO_Message *our_hello;
519 * "version" of "our_hello". Used to see if a given
520 * neighbour has already been sent the latest version
521 * of our HELLO message.
523 static unsigned int our_hello_version;
528 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
533 static struct GNUNET_PeerIdentity my_identity;
538 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
543 struct GNUNET_SCHEDULER_Handle *sched;
548 const struct GNUNET_CONFIGURATION_Handle *cfg;
551 * Linked list of all clients to this service.
553 static struct TransportClient *clients;
556 * All loaded plugins.
558 static struct TransportPlugin *plugins;
563 static struct GNUNET_SERVER_Handle *server;
566 * All known neighbours and their HELLOs.
568 static struct NeighbourList *neighbours;
571 * Number of neighbours we'd like to have.
573 static uint32_t max_connect_per_transport;
577 * Find an entry in the neighbour list for a particular peer.
579 * @return NULL if not found.
581 static struct NeighbourList *
582 find_neighbour (const struct GNUNET_PeerIdentity *key)
584 struct NeighbourList *head = neighbours;
585 while ((head != NULL) &&
586 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
593 * Find an entry in the transport list for a particular transport.
595 * @return NULL if not found.
597 static struct TransportPlugin *
598 find_transport (const char *short_name)
600 struct TransportPlugin *head = plugins;
601 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
608 * Update the quota values for the given neighbour now.
611 update_quota (struct NeighbourList *n)
613 struct GNUNET_TIME_Relative delta;
617 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
618 if (delta.value < MIN_QUOTA_REFRESH_TIME)
619 return; /* not enough time passed for doing quota update */
620 allowed = delta.value * n->quota_in;
621 if (n->last_received < allowed)
623 remaining = allowed - n->last_received;
625 remaining /= n->quota_in;
628 if (remaining > MAX_BANDWIDTH_CARRY)
629 remaining = MAX_BANDWIDTH_CARRY;
630 n->last_received = 0;
631 n->last_quota_update = GNUNET_TIME_absolute_get ();
632 n->last_quota_update.value -= remaining;
633 if (n->quota_violation_count > 0)
634 n->quota_violation_count--;
638 n->last_received -= allowed;
639 n->last_quota_update = GNUNET_TIME_absolute_get ();
640 if (n->last_received > allowed)
642 /* more than twice the allowed rate! */
643 n->quota_violation_count += 10;
650 * Function called to notify a client about the socket
651 * being ready to queue more data. "buf" will be
652 * NULL and "size" zero if the socket was closed for
653 * writing in the meantime.
656 * @param size number of bytes available in buf
657 * @param buf where the callee should write the message
658 * @return number of bytes written to buf
661 transmit_to_client_callback (void *cls, size_t size, void *buf)
663 struct TransportClient *client = cls;
664 struct ClientMessageQueueEntry *q;
667 const struct GNUNET_MessageHeader *msg;
668 struct GNUNET_CONNECTION_TransmitHandle *th;
673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
674 "Transmission to client failed, closing connection.\n");
675 /* fatal error with client, free message queue! */
676 while (NULL != (q = client->message_queue_head))
678 client->message_queue_head = q->next;
681 client->message_queue_tail = NULL;
682 client->message_count = 0;
687 while (NULL != (q = client->message_queue_head))
689 msg = (const struct GNUNET_MessageHeader *) &q[1];
690 msize = ntohs (msg->size);
691 if (msize + tsize > size)
694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
695 "Transmitting message of type %u to client.\n",
698 client->message_queue_head = q->next;
700 client->message_queue_tail = NULL;
701 memcpy (&cbuf[tsize], msg, msize);
704 client->message_count--;
708 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
709 th = GNUNET_SERVER_notify_transmit_ready (client->client,
711 GNUNET_TIME_UNIT_FOREVER_REL,
712 &transmit_to_client_callback,
714 GNUNET_assert (th != NULL);
721 * Send the specified message to the specified client. Since multiple
722 * messages may be pending for the same client at a time, this code
723 * makes sure that no message is lost.
725 * @param client client to transmit the message to
726 * @param msg the message to send
727 * @param may_drop can this message be dropped if the
728 * message queue for this client is getting far too large?
731 transmit_to_client (struct TransportClient *client,
732 const struct GNUNET_MessageHeader *msg, int may_drop)
734 struct ClientMessageQueueEntry *q;
736 struct GNUNET_CONNECTION_TransmitHandle *th;
738 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
740 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
742 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
743 client->message_count, MAX_PENDING);
744 /* TODO: call to statistics... */
747 client->message_count++;
748 msize = ntohs (msg->size);
749 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
750 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
751 memcpy (&q[1], msg, msize);
752 /* append to message queue */
753 if (client->message_queue_tail == NULL)
755 client->message_queue_tail = q;
759 client->message_queue_tail->next = q;
760 client->message_queue_tail = q;
762 if (client->message_queue_head == NULL)
764 client->message_queue_head = q;
765 th = GNUNET_SERVER_notify_transmit_ready (client->client,
767 GNUNET_TIME_UNIT_FOREVER_REL,
768 &transmit_to_client_callback,
770 GNUNET_assert (th != NULL);
776 * Find alternative plugins for communication.
778 * @param neighbour for which neighbour should we try to find
782 try_alternative_plugins (struct NeighbourList *neighbour)
784 struct ReadyList *rl;
786 if ((neighbour->plugins != NULL) &&
787 (neighbour->retry_plugins_time.value >
788 GNUNET_TIME_absolute_get ().value))
789 return; /* don't try right now */
790 neighbour->retry_plugins_time
791 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
793 rl = neighbour->plugins;
796 if (rl->connect_attempts > 0)
797 rl->connect_attempts--; /* amnesty */
805 * The peer specified by the given neighbour has timed-out or a plugin
806 * has disconnected. We may either need to do nothing (other plugins
807 * still up), or trigger a full disconnect and clean up. This
808 * function updates our state and do the necessary notifications.
809 * Also notifies our clients that the neighbour is now officially
812 * @param n the neighbour list entry for the peer
813 * @param check should we just check if all plugins
814 * disconnected or must we ask all plugins to
817 static void disconnect_neighbour (struct NeighbourList *n, int check);
821 * Check the ready list for the given neighbour and
822 * if a plugin is ready for transmission (and if we
823 * have a message), do so!
825 * @param neighbour target peer for which to check the plugins
827 static void try_transmission_to_peer (struct NeighbourList *neighbour);
831 * Function called by the GNUNET_TRANSPORT_TransmitFunction
832 * upon "completion" of a send request. This tells the API
833 * that it is now legal to send another message to the given
836 * @param cls closure, identifies the entry on the
837 * message queue that was transmitted and the
838 * client responsible for queueing the message
839 * @param target the peer receiving the message
840 * @param result GNUNET_OK on success, if the transmission
841 * failed, we should not tell the client to transmit
845 transmit_send_continuation (void *cls,
846 const struct GNUNET_PeerIdentity *target,
849 struct MessageQueue *mq = cls;
850 struct ReadyList *rl;
851 struct SendOkMessage send_ok_msg;
852 struct NeighbourList *n;
854 GNUNET_assert (mq != NULL);
856 GNUNET_assert (n != NULL);
858 memcmp (&n->id, target,
859 sizeof (struct GNUNET_PeerIdentity)));
861 while ((rl != NULL) && (rl->plugin != mq->plugin))
863 GNUNET_assert (rl != NULL);
864 if (result == GNUNET_OK)
867 GNUNET_TIME_relative_to_absolute
868 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 "Transmission to peer `%s' failed, marking connection as down.\n",
874 GNUNET_i2s (target));
875 rl->connected = GNUNET_NO;
877 if (!mq->internal_msg)
878 rl->transmit_ready = GNUNET_YES;
879 if (mq->client != NULL)
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
882 "Notifying client %p about failed transission to peer `%4s'.\n",
883 mq->client, GNUNET_i2s (target));
884 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
885 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
886 send_ok_msg.success = htonl (result);
887 send_ok_msg.peer = n->id;
888 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
890 GNUNET_free (mq->message);
892 /* one plugin just became ready again, try transmitting
893 another message (if available) */
894 if (result == GNUNET_OK)
895 try_transmission_to_peer (n);
897 disconnect_neighbour (n, GNUNET_YES);
902 * Check the ready list for the given neighbour and
903 * if a plugin is ready for transmission (and if we
904 * have a message), do so!
907 try_transmission_to_peer (struct NeighbourList *neighbour)
909 struct ReadyList *pos;
910 struct GNUNET_TIME_Relative min_latency;
911 struct ReadyList *rl;
912 struct MessageQueue *mq;
913 struct GNUNET_TIME_Absolute now;
915 if (neighbour->messages == NULL)
916 return; /* nothing to do */
917 try_alternative_plugins (neighbour);
918 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
920 mq = neighbour->messages;
921 now = GNUNET_TIME_absolute_get ();
922 pos = neighbour->plugins;
925 /* set plugins that are inactive for a long time back to disconnected */
926 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
930 "Marking long-time inactive connection to `%4s' as down.\n",
931 GNUNET_i2s (&neighbour->id));
933 pos->connected = GNUNET_NO;
935 if (((GNUNET_YES == pos->transmit_ready) ||
936 (mq->internal_msg)) &&
937 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
938 ((rl == NULL) || (min_latency.value > pos->latency.value)))
941 min_latency = pos->latency;
948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
949 "No plugin ready to transmit message\n");
951 return; /* nobody ready */
953 if (GNUNET_NO == rl->connected)
955 rl->connect_attempts++;
956 rl->connected = GNUNET_YES;
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959 "Establishing fresh connection with `%4s' via plugin `%s'\n",
960 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
963 neighbour->messages = mq->next;
964 mq->plugin = rl->plugin;
965 if (!mq->internal_msg)
966 rl->transmit_ready = GNUNET_NO;
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
969 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
970 ntohs (mq->message->type),
971 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
973 rl->plugin->api->send (rl->plugin->api->cls,
977 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
978 &transmit_send_continuation, mq);
983 * Send the specified message to the specified peer.
985 * @param client source of the transmission request (can be NULL)
986 * @param priority how important is the message
987 * @param msg message to send
988 * @param is_internal is this an internal message
989 * @param neighbour handle to the neighbour for transmission
992 transmit_to_peer (struct TransportClient *client,
993 unsigned int priority,
994 const struct GNUNET_MessageHeader *msg,
995 int is_internal, struct NeighbourList *neighbour)
997 struct MessageQueue *mq;
998 struct MessageQueue *mqe;
999 struct GNUNET_MessageHeader *m;
1002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1003 _("Sending message of type %u to peer `%4s'\n"),
1004 ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1008 /* check for duplicate submission */
1009 mq = neighbour->messages;
1012 if (mq->client == client)
1014 /* client transmitted to same peer twice
1015 before getting SendOk! */
1022 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1023 mq->client = client;
1024 m = GNUNET_malloc (ntohs (msg->size));
1025 memcpy (m, msg, ntohs (msg->size));
1027 mq->neighbour = neighbour;
1028 mq->internal_msg = is_internal;
1029 mq->priority = priority;
1032 mqe = neighbour->messages;
1034 while (mqe->next != NULL)
1039 neighbour->messages = mq;
1040 try_transmission_to_peer (neighbour);
1053 struct GeneratorContext
1055 struct TransportPlugin *plug_pos;
1056 struct AddressList *addr_pos;
1057 struct GNUNET_TIME_Absolute expiration;
1065 address_generator (void *cls, size_t max, void *buf)
1067 struct GeneratorContext *gc = cls;
1070 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1072 gc->plug_pos = gc->plug_pos->next;
1073 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1075 if (NULL == gc->plug_pos)
1077 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1080 gc->addr_pos->addrlen, buf, max);
1081 gc->addr_pos = gc->addr_pos->next;
1087 * Construct our HELLO message from all of the addresses of
1088 * all of the transports.
1093 struct GNUNET_HELLO_Message *hello;
1094 struct TransportClient *cpos;
1095 struct NeighbourList *npos;
1096 struct GeneratorContext gc;
1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1100 "Refreshing my `%s'\n", "HELLO");
1102 gc.plug_pos = plugins;
1103 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1104 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1105 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1107 while (cpos != NULL)
1109 transmit_to_client (cpos,
1110 (const struct GNUNET_MessageHeader *) hello,
1115 GNUNET_free_non_null (our_hello);
1117 our_hello_version++;
1118 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1120 while (npos != NULL)
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1124 "Transmitting updated `%s' to neighbour `%4s'\n",
1125 "HELLO", GNUNET_i2s (&npos->id));
1127 transmit_to_peer (NULL, 0,
1128 (const struct GNUNET_MessageHeader *) our_hello,
1136 * Task used to clean up expired addresses for a plugin.
1138 * @param cls closure
1142 expire_address_task (void *cls,
1143 const struct GNUNET_SCHEDULER_TaskContext *tc);
1147 * Update the list of addresses for this plugin,
1148 * expiring those that are past their expiration date.
1150 * @param plugin addresses of which plugin should be recomputed?
1151 * @param fresh set to GNUNET_YES if a new address was added
1152 * and we need to regenerate the HELLO even if nobody
1156 update_addresses (struct TransportPlugin *plugin, int fresh)
1158 struct GNUNET_TIME_Relative min_remaining;
1159 struct GNUNET_TIME_Relative remaining;
1160 struct GNUNET_TIME_Absolute now;
1161 struct AddressList *pos;
1162 struct AddressList *prev;
1163 struct AddressList *next;
1166 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1167 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1168 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1169 now = GNUNET_TIME_absolute_get ();
1170 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1171 expired = GNUNET_NO;
1173 pos = plugin->addresses;
1177 if (pos->expires.value < now.value)
1179 expired = GNUNET_YES;
1181 plugin->addresses = pos->next;
1183 prev->next = pos->next;
1188 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1189 if (remaining.value < min_remaining.value)
1190 min_remaining = remaining;
1196 if (expired || fresh)
1198 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1199 plugin->address_update_task
1200 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1202 &expire_address_task, plugin);
1208 * Task used to clean up expired addresses for a plugin.
1210 * @param cls closure
1214 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1216 struct TransportPlugin *plugin = cls;
1217 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1218 update_addresses (plugin, GNUNET_NO);
1223 * Function that must be called by each plugin to notify the
1224 * transport service about the addresses under which the transport
1225 * provided by the plugin can be reached.
1227 * @param cls closure
1228 * @param name name of the transport that generated the address
1229 * @param addr one of the addresses of the host, NULL for the last address
1230 * the specific address format depends on the transport
1231 * @param addrlen length of the address
1232 * @param expires when should this address automatically expire?
1235 plugin_env_notify_address (void *cls,
1239 struct GNUNET_TIME_Relative expires)
1241 struct TransportPlugin *p = cls;
1242 struct AddressList *al;
1243 struct GNUNET_TIME_Absolute abex;
1245 abex = GNUNET_TIME_relative_to_absolute (expires);
1246 GNUNET_assert (p == find_transport (name));
1251 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1253 if (al->expires.value < abex.value)
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1261 "Plugin `%s' informs us about a new address `%s'\n", name,
1262 GNUNET_a2s (addr, addrlen));
1264 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1266 al->next = p->addresses;
1269 al->addrlen = addrlen;
1270 memcpy (&al[1], addr, addrlen);
1271 update_addresses (p, GNUNET_YES);
1276 * Notify all of our clients about a peer connecting.
1279 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1280 struct GNUNET_TIME_Relative latency)
1282 struct ConnectInfoMessage cim;
1283 struct TransportClient *cpos;
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1287 "Informing clients about peer `%4s' connecting to us\n",
1290 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1291 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1292 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1293 cim.latency = GNUNET_TIME_relative_hton (latency);
1294 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1296 while (cpos != NULL)
1298 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1305 * Notify all of our clients about a peer disconnecting.
1308 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1310 struct DisconnectInfoMessage dim;
1311 struct TransportClient *cpos;
1314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1315 "Informing clients about peer `%4s' disconnecting\n",
1318 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1319 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1320 dim.reserved = htonl (0);
1321 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1323 while (cpos != NULL)
1325 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1332 * Copy any validated addresses to buf.
1334 * @return 0 once all addresses have been
1338 list_validated_addresses (void *cls, size_t max, void *buf)
1340 struct ValidationAddress **va = cls;
1343 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1347 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1349 &(*va)[1], (*va)->addr_len, buf, max);
1356 * HELLO validation cleanup task.
1359 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1361 struct ValidationAddress *va;
1362 struct ValidationList *pos;
1363 struct ValidationList *prev;
1364 struct GNUNET_TIME_Absolute now;
1365 struct GNUNET_TIME_Absolute first;
1366 struct GNUNET_HELLO_Message *hello;
1367 struct GNUNET_PeerIdentity pid;
1368 struct NeighbourList *n;
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1372 "HELLO validation cleanup background task running...\n");
1374 now = GNUNET_TIME_absolute_get ();
1376 pos = pending_validations;
1379 if (pos->timeout.value < now.value)
1382 pending_validations = pos->next;
1384 prev->next = pos->next;
1385 va = pos->addresses;
1386 hello = GNUNET_HELLO_create (&pos->publicKey,
1387 &list_validated_addresses, &va);
1388 GNUNET_CRYPTO_hash (&pos->publicKey,
1390 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1394 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1395 "HELLO", GNUNET_i2s (&pid));
1397 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1398 n = find_neighbour (&pid);
1400 try_transmission_to_peer (n);
1401 GNUNET_free (hello);
1402 while (NULL != (va = pos->addresses))
1404 pos->addresses = va->next;
1405 GNUNET_free (va->transport_name);
1410 pos = pending_validations;
1419 /* finally, reschedule cleanup if needed; list is
1420 ordered by timeout, so we need the last element... */
1421 if (NULL != pending_validations)
1423 first = pending_validations->timeout;
1424 pos = pending_validations;
1427 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1430 GNUNET_SCHEDULER_add_delayed (sched,
1431 GNUNET_TIME_absolute_get_remaining
1432 (first), &cleanup_validation, NULL);
1440 * Function that will be called if we receive a validation
1441 * of an address challenge that we transmitted to another
1442 * peer. Note that the validation should only be considered
1443 * acceptable if the challenge matches AND if the sender
1444 * address is at least a plausible address for this peer
1445 * (otherwise we may be seeing a MiM attack).
1447 * @param cls closure
1448 * @param name name of the transport that generated the address
1449 * @param peer who responded to our challenge
1450 * @param challenge the challenge number we presumably used
1451 * @param sender_addr string describing our sender address (as observed
1452 * by the other peer in human-readable format)
1455 plugin_env_notify_validation (void *cls,
1457 const struct GNUNET_PeerIdentity *peer,
1458 uint32_t challenge, const char *sender_addr)
1460 unsigned int not_done;
1462 struct ValidationList *pos;
1463 struct ValidationAddress *va;
1464 struct GNUNET_PeerIdentity id;
1466 pos = pending_validations;
1469 GNUNET_CRYPTO_hash (&pos->publicKey,
1471 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1473 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1479 /* TODO: call statistics (unmatched PONG) */
1480 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1482 ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
1487 matched = GNUNET_NO;
1488 va = pos->addresses;
1491 if (va->challenge == challenge)
1494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1495 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1497 GNUNET_a2s ((const struct sockaddr *) &va[1],
1500 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1502 ("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1504 va->ok = GNUNET_YES;
1506 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1507 matched = GNUNET_YES;
1509 if (va->ok != GNUNET_YES)
1513 if (GNUNET_NO == matched)
1515 /* TODO: call statistics (unmatched PONG) */
1516 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1518 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525 "All addresses validated, will now construct `%s' for `%4s'.\n",
1526 "HELLO", GNUNET_i2s (peer));
1528 pos->timeout.value = 0;
1529 GNUNET_SCHEDULER_add_with_priority (sched,
1530 GNUNET_SCHEDULER_PRIORITY_IDLE,
1531 &cleanup_validation, NULL);
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1537 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1538 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1544 struct CheckHelloValidatedContext
1547 * Plugin for which we are validating.
1549 struct TransportPlugin *plugin;
1552 * Hello that we are validating.
1554 struct GNUNET_HELLO_Message *hello;
1557 * Validation list being build.
1559 struct ValidationList *e;
1562 * Context for peerinfo iteration.
1563 * NULL after we are done processing peerinfo's information.
1565 struct GNUNET_PEERINFO_IteratorContext *piter;
1571 * Append the given address to the list of entries
1572 * that need to be validated.
1575 run_validation (void *cls,
1577 struct GNUNET_TIME_Absolute expiration,
1578 const void *addr, size_t addrlen)
1580 struct ValidationList *e = cls;
1581 struct TransportPlugin *tp;
1582 struct ValidationAddress *va;
1583 struct GNUNET_PeerIdentity id;
1585 tp = find_transport (tname);
1588 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1589 GNUNET_ERROR_TYPE_BULK,
1591 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1595 GNUNET_CRYPTO_hash (&e->publicKey,
1597 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1600 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1601 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1603 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1604 va->next = e->addresses;
1606 va->transport_name = GNUNET_strdup (tname);
1607 va->addr_len = addrlen;
1608 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1610 memcpy (&va[1], addr, addrlen);
1616 * Check if addresses in validated hello "h" overlap with
1617 * those in "chvc->hello" and update "chvc->hello" accordingly,
1618 * removing those addresses that have already been validated.
1621 check_hello_validated (void *cls,
1622 const struct GNUNET_PeerIdentity *peer,
1623 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1625 struct CheckHelloValidatedContext *chvc = cls;
1626 struct ValidationAddress *va;
1627 struct TransportPlugin *tp;
1629 struct GNUNET_PeerIdentity apeer;
1631 first_call = GNUNET_NO;
1632 if (chvc->e == NULL)
1635 first_call = GNUNET_YES;
1636 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1637 GNUNET_assert (GNUNET_OK ==
1638 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1639 &chvc->e->publicKey));
1641 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1642 chvc->e->next = pending_validations;
1643 pending_validations = chvc->e;
1647 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1649 GNUNET_TIME_absolute_get (),
1650 &run_validation, chvc->e);
1652 else if (GNUNET_YES == first_call)
1654 /* no existing HELLO, all addresses are new */
1655 GNUNET_HELLO_iterate_addresses (chvc->hello,
1656 GNUNET_NO, &run_validation, chvc->e);
1659 return; /* wait for next call */
1660 /* finally, transmit validation attempts */
1661 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1664 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1665 "HELLO", GNUNET_i2s (&apeer));
1667 va = chvc->e->addresses;
1671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1672 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1675 GNUNET_a2s ((const struct sockaddr *) &va[1],
1676 va->addr_len), GNUNET_i2s (&apeer));
1678 tp = find_transport (va->transport_name);
1679 GNUNET_assert (tp != NULL);
1681 tp->api->validate (tp->api->cls,
1684 HELLO_VERIFICATION_TIMEOUT,
1685 &va[1], va->addr_len))
1686 va->ok = GNUNET_SYSERR;
1689 GNUNET_SCHEDULER_add_delayed (sched,
1690 GNUNET_TIME_absolute_get_remaining (chvc->
1692 &cleanup_validation, NULL);
1698 * Process HELLO-message.
1700 * @param plugin transport involved, may be NULL
1701 * @param message the actual message
1702 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1705 process_hello (struct TransportPlugin *plugin,
1706 const struct GNUNET_MessageHeader *message)
1708 struct ValidationList *e;
1710 struct GNUNET_PeerIdentity target;
1711 const struct GNUNET_HELLO_Message *hello;
1712 struct CheckHelloValidatedContext *chvc;
1713 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1715 hsize = ntohs (message->size);
1716 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1717 (hsize < sizeof (struct GNUNET_MessageHeader)))
1720 return GNUNET_SYSERR;
1722 /* first, check if load is too high */
1723 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1725 /* TODO: call to stats? */
1728 hello = (const struct GNUNET_HELLO_Message *) message;
1729 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1731 GNUNET_break_op (0);
1732 return GNUNET_SYSERR;
1734 GNUNET_CRYPTO_hash (&publicKey,
1735 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1736 &target.hashPubKey);
1738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1739 "Processing `%s' message for `%4s'\n",
1740 "HELLO", GNUNET_i2s (&target));
1742 /* check if a HELLO for this peer is already on the validation list */
1743 e = pending_validations;
1746 if (0 == memcmp (&e->publicKey,
1749 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1751 /* TODO: call to stats? */
1753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1754 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1755 "HELLO", GNUNET_i2s (&target));
1761 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1762 chvc->plugin = plugin;
1763 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1764 memcpy (chvc->hello, hello, hsize);
1765 /* finally, check if HELLO was previously validated
1766 (continuation will then schedule actual validation) */
1767 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1771 HELLO_VERIFICATION_TIMEOUT,
1772 &check_hello_validated, chvc);
1778 * The peer specified by the given neighbour has timed-out or a plugin
1779 * has disconnected. We may either need to do nothing (other plugins
1780 * still up), or trigger a full disconnect and clean up. This
1781 * function updates our state and do the necessary notifications.
1782 * Also notifies our clients that the neighbour is now officially
1785 * @param n the neighbour list entry for the peer
1786 * @param check should we just check if all plugins
1787 * disconnected or must we ask all plugins to
1791 disconnect_neighbour (struct NeighbourList *n, int check)
1793 struct ReadyList *rpos;
1794 struct NeighbourList *npos;
1795 struct NeighbourList *nprev;
1796 struct MessageQueue *mq;
1798 if (GNUNET_YES == check)
1801 while (NULL != rpos)
1803 if (GNUNET_YES == rpos->connected)
1804 return; /* still connected */
1810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1811 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
1813 /* remove n from neighbours list */
1816 while ((npos != NULL) && (npos != n))
1821 GNUNET_assert (npos != NULL);
1823 neighbours = n->next;
1825 nprev->next = n->next;
1827 /* notify all clients about disconnect */
1828 notify_clients_disconnect (&n->id);
1830 /* clean up all plugins, cancel connections and pending transmissions */
1831 while (NULL != (rpos = n->plugins))
1833 n->plugins = rpos->next;
1834 GNUNET_assert (rpos->neighbour == n);
1835 if (GNUNET_YES == rpos->connected)
1836 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
1840 /* free all messages on the queue */
1841 while (NULL != (mq = n->messages))
1843 n->messages = mq->next;
1844 GNUNET_assert (mq->neighbour == n);
1847 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1848 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
1849 /* finally, free n itself */
1855 * Add an entry for each of our transport plugins
1856 * (that are able to send) to the list of plugins
1857 * for this neighbour.
1859 * @param neighbour to initialize
1862 add_plugins (struct NeighbourList *neighbour)
1864 struct TransportPlugin *tp;
1865 struct ReadyList *rl;
1867 neighbour->retry_plugins_time
1868 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1872 if (tp->api->send != NULL)
1874 rl = GNUNET_malloc (sizeof (struct ReadyList));
1875 rl->next = neighbour->plugins;
1876 neighbour->plugins = rl;
1878 rl->neighbour = neighbour;
1879 rl->transmit_ready = GNUNET_YES;
1887 neighbour_timeout_task (void *cls,
1888 const struct GNUNET_SCHEDULER_TaskContext *tc)
1890 struct NeighbourList *n = cls;
1893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1894 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1896 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1897 disconnect_neighbour (n, GNUNET_NO);
1902 * Create a fresh entry in our neighbour list for the given peer.
1903 * Will try to transmit our current HELLO to the new neighbour. Also
1904 * notifies our clients about the new "connection".
1906 * @param peer the peer for which we create the entry
1907 * @return the new neighbour list entry
1909 static struct NeighbourList *
1910 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
1912 struct NeighbourList *n;
1915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1916 "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
1919 GNUNET_assert (our_hello != NULL);
1920 n = GNUNET_malloc (sizeof (struct NeighbourList));
1921 n->next = neighbours;
1924 n->last_quota_update = GNUNET_TIME_absolute_get ();
1926 GNUNET_TIME_relative_to_absolute
1927 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1928 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1930 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1931 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1932 &neighbour_timeout_task, n);
1933 transmit_to_peer (NULL, 0,
1934 (const struct GNUNET_MessageHeader *) our_hello,
1936 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1942 * Function called by the plugin for each received message.
1943 * Update data volumes, possibly notify plugins about
1944 * reducing the rate at which they read from the socket
1945 * and generally forward to our receive callback.
1947 * @param cls the "struct TransportPlugin *" we gave to the plugin
1948 * @param latency estimated latency for communicating with the
1950 * @param peer (claimed) identity of the other peer
1951 * @param message the message, NULL if peer was disconnected
1952 * @return the new service_context that the plugin should use
1953 * for future receive calls for messages from this
1957 plugin_env_receive (void *cls,
1958 struct GNUNET_TIME_Relative latency,
1959 const struct GNUNET_PeerIdentity *peer,
1960 const struct GNUNET_MessageHeader *message)
1962 const struct GNUNET_MessageHeader ack = {
1963 htons (sizeof (struct GNUNET_MessageHeader)),
1964 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
1966 struct ReadyList *service_context;
1967 struct TransportPlugin *plugin = cls;
1968 struct TransportClient *cpos;
1969 struct InboundMessage *im;
1971 struct NeighbourList *n;
1973 n = find_neighbour (peer);
1976 if (message == NULL)
1977 return; /* disconnect of peer already marked down */
1978 n = setup_new_neighbour (peer);
1980 service_context = n->plugins;
1981 while ((service_context != NULL) && (plugin != service_context->plugin))
1982 service_context = service_context->next;
1983 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
1984 if (message == NULL)
1987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1988 "Receive failed from `%4s', triggering disconnect\n",
1989 GNUNET_i2s (&n->id));
1991 /* TODO: call stats */
1992 if (service_context != NULL)
1993 service_context->connected = GNUNET_NO;
1994 disconnect_neighbour (n, GNUNET_YES);
1998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1999 "Processing message of type `%u' received by plugin...\n",
2000 ntohs (message->type));
2002 if (service_context != NULL)
2004 if (service_context->connected == GNUNET_NO)
2006 service_context->connected = GNUNET_YES;
2007 service_context->transmit_ready = GNUNET_YES;
2008 service_context->connect_attempts++;
2010 service_context->timeout
2012 GNUNET_TIME_relative_to_absolute
2013 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2014 service_context->latency = latency;
2016 /* update traffic received amount ... */
2017 msize = ntohs (message->size);
2018 n->last_received += msize;
2019 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2021 GNUNET_TIME_relative_to_absolute
2022 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2024 GNUNET_SCHEDULER_add_delayed (sched,
2025 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2026 &neighbour_timeout_task, n);
2028 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2030 /* dropping message due to frequent inbound volume violations! */
2031 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2032 GNUNET_ERROR_TYPE_BULK,
2034 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2035 /* TODO: call stats */
2036 GNUNET_assert ((service_context == NULL) ||
2037 (NULL != service_context->neighbour));
2040 switch (ntohs (message->type))
2042 case GNUNET_MESSAGE_TYPE_HELLO:
2044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2045 "Receiving `%s' message from `%4s'.\n", "HELLO",
2048 process_hello (plugin, message);
2050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2051 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2054 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2056 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2057 n->saw_ack = GNUNET_YES;
2058 /* intentional fall-through! */
2061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062 "Received message of type %u from `%4s', sending to all clients.\n",
2063 ntohs (message->type), GNUNET_i2s (peer));
2065 /* transmit message to all clients */
2066 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2067 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2068 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2069 im->latency = GNUNET_TIME_relative_hton (latency);
2071 memcpy (&im[1], message, msize);
2074 while (cpos != NULL)
2076 transmit_to_client (cpos, &im->header, GNUNET_YES);
2081 GNUNET_assert ((service_context == NULL) ||
2082 (NULL != service_context->neighbour));
2087 * Handle START-message. This is the first message sent to us
2088 * by any client which causes us to add it to our list.
2090 * @param cls closure (always NULL)
2091 * @param client identification of the client
2092 * @param message the actual message
2095 handle_start (void *cls,
2096 struct GNUNET_SERVER_Client *client,
2097 const struct GNUNET_MessageHeader *message)
2099 struct TransportClient *c;
2100 struct ConnectInfoMessage cim;
2101 struct NeighbourList *n;
2102 struct InboundMessage *im;
2103 struct GNUNET_MessageHeader *ack;
2106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2107 "Received `%s' request from client\n", "START");
2112 if (c->client == client)
2114 /* client already on our list! */
2116 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2121 c = GNUNET_malloc (sizeof (struct TransportClient));
2125 if (our_hello != NULL)
2128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2129 "Sending our own `%s' to new client\n", "HELLO");
2131 transmit_to_client (c,
2132 (const struct GNUNET_MessageHeader *) our_hello,
2134 /* tell new client about all existing connections */
2135 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2136 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2138 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2139 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2140 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2141 sizeof (struct GNUNET_MessageHeader));
2142 im->header.size = htons (sizeof (struct InboundMessage) +
2143 sizeof (struct GNUNET_MessageHeader));
2144 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2145 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2146 ack = (struct GNUNET_MessageHeader *) &im[1];
2147 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2148 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2149 for (n = neighbours; n != NULL; n = n->next)
2152 transmit_to_client (c, &cim.header, GNUNET_NO);
2156 transmit_to_client (c, &im->header, GNUNET_NO);
2161 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2166 * Handle HELLO-message.
2168 * @param cls closure (always NULL)
2169 * @param client identification of the client
2170 * @param message the actual message
2173 handle_hello (void *cls,
2174 struct GNUNET_SERVER_Client *client,
2175 const struct GNUNET_MessageHeader *message)
2180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2181 "Received `%s' request from client\n", "HELLO");
2183 ret = process_hello (NULL, message);
2184 GNUNET_SERVER_receive_done (client, ret);
2189 * Handle SEND-message.
2191 * @param cls closure (always NULL)
2192 * @param client identification of the client
2193 * @param message the actual message
2196 handle_send (void *cls,
2197 struct GNUNET_SERVER_Client *client,
2198 const struct GNUNET_MessageHeader *message)
2200 struct TransportClient *tc;
2201 struct NeighbourList *n;
2202 const struct OutboundMessage *obm;
2203 const struct GNUNET_MessageHeader *obmm;
2207 size = ntohs (message->size);
2209 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2212 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2215 obm = (const struct OutboundMessage *) message;
2217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2218 "Received `%s' request from client with target `%4s'\n",
2219 "SEND", GNUNET_i2s (&obm->peer));
2221 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2222 msize = ntohs (obmm->size);
2223 if (size != msize + sizeof (struct OutboundMessage))
2226 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2229 n = find_neighbour (&obm->peer);
2231 n = setup_new_neighbour (&obm->peer);
2233 while ((tc != NULL) && (tc->client != client))
2237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2238 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2240 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2242 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2243 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2248 * Handle SET_QUOTA-message.
2250 * @param cls closure (always NULL)
2251 * @param client identification of the client
2252 * @param message the actual message
2255 handle_set_quota (void *cls,
2256 struct GNUNET_SERVER_Client *client,
2257 const struct GNUNET_MessageHeader *message)
2259 const struct QuotaSetMessage *qsm =
2260 (const struct QuotaSetMessage *) message;
2261 struct NeighbourList *n;
2262 struct TransportPlugin *p;
2263 struct ReadyList *rl;
2266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2267 "Received `%s' request from client for peer `%4s'\n",
2268 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2270 n = find_neighbour (&qsm->peer);
2273 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2277 if (n->quota_in < ntohl (qsm->quota_in))
2278 n->last_quota_update = GNUNET_TIME_absolute_get ();
2279 n->quota_in = ntohl (qsm->quota_in);
2284 p->api->set_receive_quota (p->api->cls,
2285 &qsm->peer, ntohl (qsm->quota_in));
2288 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2293 * Handle TRY_CONNECT-message.
2295 * @param cls closure (always NULL)
2296 * @param client identification of the client
2297 * @param message the actual message
2300 handle_try_connect (void *cls,
2301 struct GNUNET_SERVER_Client *client,
2302 const struct GNUNET_MessageHeader *message)
2304 const struct TryConnectMessage *tcm;
2306 tcm = (const struct TryConnectMessage *) message;
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2309 "Received `%s' request from client %p asking to connect to `%4s'\n",
2310 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2312 if (NULL == find_neighbour (&tcm->peer))
2313 setup_new_neighbour (&tcm->peer);
2316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2317 "Client asked to connect to `%4s', but connection already exists\n",
2318 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2320 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2324 transmit_address_to_client (void *cls, const char *address)
2326 struct GNUNET_SERVER_TransmitContext *tc = cls;
2329 if (NULL == address)
2332 slen = strlen (address) + 1;
2333 GNUNET_SERVER_transmit_context_append (tc, address, slen,
2334 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2335 if (NULL == address)
2336 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2340 * Handle AddressLookup-message.
2342 * @param cls closure (always NULL)
2343 * @param client identification of the client
2344 * @param message the actual message
2347 handle_address_lookup (void *cls,
2348 struct GNUNET_SERVER_Client *client,
2349 const struct GNUNET_MessageHeader *message)
2351 const struct AddressLookupMessage *alum;
2352 struct TransportPlugin *lsPlugin;
2353 const char *nameTransport;
2354 const char *address;
2356 struct GNUNET_SERVER_TransmitContext *tc;
2358 size = ntohs (message->size);
2359 if (size < sizeof (struct AddressLookupMessage))
2361 GNUNET_break_op (0);
2362 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2365 alum = (const struct AddressLookupMessage *) message;
2366 uint32_t addressLen = ntohl (alum->addrlen);
2367 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2369 GNUNET_break_op (0);
2370 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2373 address = (const char *) &alum[1];
2374 nameTransport = (const char *) &address[addressLen];
2376 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2378 GNUNET_break_op (0);
2379 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2382 struct GNUNET_TIME_Absolute timeout =
2383 GNUNET_TIME_absolute_ntoh (alum->timeout);
2384 struct GNUNET_TIME_Relative rtimeout =
2385 GNUNET_TIME_absolute_get_remaining (timeout);
2386 lsPlugin = find_transport (nameTransport);
2387 if (NULL == lsPlugin)
2389 tc = GNUNET_SERVER_transmit_context_create (client);
2390 GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
2391 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2392 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2395 tc = GNUNET_SERVER_transmit_context_create (client);
2396 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2397 address, addressLen, GNUNET_YES,
2399 &transmit_address_to_client, tc);
2403 * List of handlers for the messages understood by this
2406 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2407 {&handle_start, NULL,
2408 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2409 {&handle_hello, NULL,
2410 GNUNET_MESSAGE_TYPE_HELLO, 0},
2411 {&handle_send, NULL,
2412 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2413 {&handle_set_quota, NULL,
2414 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2415 {&handle_try_connect, NULL,
2416 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2417 sizeof (struct TryConnectMessage)},
2418 {&handle_address_lookup, NULL,
2419 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2426 * Setup the environment for this plugin.
2429 create_environment (struct TransportPlugin *plug)
2431 plug->env.cfg = cfg;
2432 plug->env.sched = sched;
2433 plug->env.my_public_key = &my_public_key;
2434 plug->env.my_private_key = my_private_key;
2435 plug->env.my_identity = &my_identity;
2436 plug->env.cls = plug;
2437 plug->env.receive = &plugin_env_receive;
2438 plug->env.notify_address = &plugin_env_notify_address;
2439 plug->env.notify_validation = &plugin_env_notify_validation;
2440 plug->env.default_quota_in =
2441 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2442 plug->env.max_connections = max_connect_per_transport;
2447 * Start the specified transport (load the plugin).
2450 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2452 struct TransportPlugin *plug;
2455 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2456 _("Loading `%s' transport plugin\n"), name);
2457 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2458 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2459 create_environment (plug);
2460 plug->short_name = GNUNET_strdup (name);
2461 plug->lib_name = libname;
2462 plug->next = plugins;
2464 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2465 if (plug->api == NULL)
2467 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2468 _("Failed to load transport plugin for `%s'\n"), name);
2469 GNUNET_free (plug->short_name);
2470 plugins = plug->next;
2471 GNUNET_free (libname);
2478 * Called whenever a client is disconnected. Frees our
2479 * resources associated with that client.
2481 * @param cls closure
2482 * @param client identification of the client
2485 client_disconnect_notification (void *cls,
2486 struct GNUNET_SERVER_Client *client)
2488 struct TransportClient *pos;
2489 struct TransportClient *prev;
2490 struct ClientMessageQueueEntry *mqe;
2493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2494 "Client disconnected, cleaning up.\n");
2498 while ((pos != NULL) && (pos->client != client))
2505 while (NULL != (mqe = pos->message_queue_head))
2507 pos->message_queue_head = mqe->next;
2510 pos->message_queue_head = NULL;
2512 clients = pos->next;
2514 prev->next = pos->next;
2515 if (GNUNET_YES == pos->tcs_pending)
2525 * Function called when the service shuts down. Unloads our plugins.
2527 * @param cls closure, unused
2528 * @param tc task context (unused)
2531 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2533 struct TransportPlugin *plug;
2534 struct AddressList *al;
2537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2538 "Transport service is unloading plugins...\n");
2540 while (NULL != (plug = plugins))
2542 plugins = plug->next;
2543 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2544 GNUNET_free (plug->lib_name);
2545 GNUNET_free (plug->short_name);
2546 while (NULL != (al = plug->addresses))
2548 plug->addresses = al->next;
2553 if (my_private_key != NULL)
2554 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2555 GNUNET_free_non_null (our_hello);
2560 * Initiate transport service.
2562 * @param cls closure
2563 * @param s scheduler to use
2564 * @param serv the initialized server
2565 * @param c configuration to use
2569 struct GNUNET_SCHEDULER_Handle *s,
2570 struct GNUNET_SERVER_Handle *serv,
2571 const struct GNUNET_CONFIGURATION_Handle *c)
2576 unsigned long long tneigh;
2581 /* parse configuration */
2583 GNUNET_CONFIGURATION_get_value_number (c,
2588 GNUNET_CONFIGURATION_get_value_filename (c,
2590 "HOSTKEY", &keyfile)))
2592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2594 ("Transport service is lacking key configuration settings. Exiting.\n"));
2595 GNUNET_SCHEDULER_shutdown (s);
2598 max_connect_per_transport = (uint32_t) tneigh;
2599 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2600 GNUNET_free (keyfile);
2601 if (my_private_key == NULL)
2603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2605 ("Transport service could not access hostkey. Exiting.\n"));
2606 GNUNET_SCHEDULER_shutdown (s);
2609 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2610 GNUNET_CRYPTO_hash (&my_public_key,
2611 sizeof (my_public_key), &my_identity.hashPubKey);
2612 /* setup notification */
2614 GNUNET_SERVER_disconnect_notify (server,
2615 &client_disconnect_notification, NULL);
2616 /* load plugins... */
2619 GNUNET_CONFIGURATION_get_value_string (c,
2620 "TRANSPORT", "PLUGINS", &plugs))
2622 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2623 _("Starting transport plugins `%s'\n"), plugs);
2624 pos = strtok (plugs, " ");
2627 start_transport (server, pos);
2629 pos = strtok (NULL, " ");
2631 GNUNET_free (plugs);
2633 GNUNET_SCHEDULER_add_delayed (sched,
2634 GNUNET_TIME_UNIT_FOREVER_REL,
2635 &unload_plugins, NULL);
2639 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2641 /* process client requests */
2642 GNUNET_SERVER_add_handlers (server, handlers);
2647 * The main function for the transport service.
2649 * @param argc number of arguments from the command line
2650 * @param argv command line arguments
2651 * @return 0 ok, 1 on error
2654 main (int argc, char *const *argv)
2656 return (GNUNET_OK ==
2657 GNUNET_SERVICE_run (argc,
2660 GNUNET_SERVICE_OPTION_NONE,
2661 &run, NULL)) ? 0 : 1;
2664 /* end of gnunet-service-transport.c */