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 * Opaque handle (specific to the plugin) for the
255 * connection to our target; can be NULL.
260 * What was the last latency observed for this plugin
261 * and peer? Invalid if connected is GNUNET_NO.
263 struct GNUNET_TIME_Relative latency;
266 * If we did not successfully transmit a message to the
267 * given peer via this connection during the specified
268 * time, we should consider the connection to be dead.
269 * This is used in the case that a TCP transport simply
270 * stalls writing to the stream but does not formerly
271 * get a signal that the other peer died.
273 struct GNUNET_TIME_Absolute timeout;
276 * Is this plugin currently connected? The first time
277 * we transmit or send data to a peer via a particular
278 * plugin, we set this to GNUNET_YES. If we later get
279 * an error (disconnect notification or transmission
280 * failure), we set it back to GNUNET_NO. Each time the
281 * value is set to GNUNET_YES, we increment the
282 * "connect_attempts" counter. If that one reaches a
283 * particular threshold, we consider the plugin to not
284 * be working properly at this time for the given peer
285 * and remove it from the eligible list.
290 * How often have we tried to connect using this plugin?
292 unsigned int connect_attempts;
295 * Is this plugin ready to transmit to the specific
296 * target? GNUNET_NO if not. Initially, all plugins
297 * are marked ready. If a transmission is in progress,
298 * "transmit_ready" is set to GNUNET_NO.
306 * Entry in linked list of all of our current neighbours.
312 * This is a linked list.
314 struct NeighbourList *next;
317 * Which of our transports is connected to this peer
318 * and what is their status?
320 struct ReadyList *plugins;
323 * List of messages we would like to send to this peer;
324 * must contain at most one message per client.
326 struct MessageQueue *messages;
329 * Identity of this neighbour.
331 struct GNUNET_PeerIdentity id;
334 * ID of task scheduled to run when this peer is about to
335 * time out (will free resources associated with the peer).
337 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
340 * How long until we should consider this peer dead
341 * (if we don't receive another message in the
344 struct GNUNET_TIME_Absolute peer_timeout;
347 * At what time did we reset last_received last?
349 struct GNUNET_TIME_Absolute last_quota_update;
352 * At what time should we try to again add plugins to
355 struct GNUNET_TIME_Absolute retry_plugins_time;
358 * How many bytes have we received since the "last_quota_update"
361 uint64_t last_received;
364 * Global quota for inbound traffic for the neighbour in bytes/ms.
369 * How often has the other peer (recently) violated the
370 * inbound traffic limit? Incremented by 10 per violation,
371 * decremented by 1 per non-violation (for each
374 unsigned int quota_violation_count;
377 * Have we seen an ACK from this neighbour in the past?
378 * (used to make up a fake ACK for clients connecting after
379 * the neighbour connected to us).
387 * Linked list of messages to be transmitted to
388 * the client. Each entry is followed by the
391 struct ClientMessageQueueEntry
394 * This is a linked list.
396 struct ClientMessageQueueEntry *next;
401 * Client connected to the transport service.
403 struct TransportClient
407 * This is a linked list.
409 struct TransportClient *next;
412 * Handle to the client.
414 struct GNUNET_SERVER_Client *client;
417 * Linked list of messages yet to be transmitted to
420 struct ClientMessageQueueEntry *message_queue_head;
423 * Tail of linked list of messages yet to be transmitted to the
426 struct ClientMessageQueueEntry *message_queue_tail;
429 * Is a call to "transmit_send_continuation" pending? If so, we
430 * must not free this struct (even if the corresponding client
431 * disconnects) and instead only remove it from the linked list and
432 * set the "client" field to NULL.
437 * Length of the list of messages pending for this client.
439 unsigned int message_count;
445 * For each HELLO, we may have to validate multiple addresses;
446 * each address gets its own request entry.
448 struct ValidationAddress
451 * This is a linked list.
453 struct ValidationAddress *next;
456 * Name of the transport.
458 char *transport_name;
461 * When should this validated address expire?
463 struct GNUNET_TIME_Absolute expiration;
466 * Length of the address we are validating.
471 * Challenge number we used.
476 * Set to GNUNET_YES if the challenge was met,
477 * GNUNET_SYSERR if we know it failed, GNUNET_NO
478 * if we are waiting on a response.
485 * Entry in linked list of all HELLOs awaiting validation.
487 struct ValidationList
491 * This is a linked list.
493 struct ValidationList *next;
496 * Linked list with one entry per address from the HELLO
497 * that needs to be validated.
499 struct ValidationAddress *addresses;
502 * The public key of the peer.
504 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
507 * When does this record time-out? (assuming the
508 * challenge goes unanswered)
510 struct GNUNET_TIME_Absolute timeout;
516 * HELLOs awaiting validation.
518 static struct ValidationList *pending_validations;
523 static struct GNUNET_HELLO_Message *our_hello;
526 * "version" of "our_hello". Used to see if a given
527 * neighbour has already been sent the latest version
528 * of our HELLO message.
530 static unsigned int our_hello_version;
535 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
540 static struct GNUNET_PeerIdentity my_identity;
545 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
550 struct GNUNET_SCHEDULER_Handle *sched;
555 const struct GNUNET_CONFIGURATION_Handle *cfg;
558 * Linked list of all clients to this service.
560 static struct TransportClient *clients;
563 * All loaded plugins.
565 static struct TransportPlugin *plugins;
570 static struct GNUNET_SERVER_Handle *server;
573 * All known neighbours and their HELLOs.
575 static struct NeighbourList *neighbours;
578 * Number of neighbours we'd like to have.
580 static uint32_t max_connect_per_transport;
584 * Find an entry in the neighbour list for a particular peer.
586 * @return NULL if not found.
588 static struct NeighbourList *
589 find_neighbour (const struct GNUNET_PeerIdentity *key)
591 struct NeighbourList *head = neighbours;
592 while ((head != NULL) &&
593 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
600 * Find an entry in the transport list for a particular transport.
602 * @return NULL if not found.
604 static struct TransportPlugin *
605 find_transport (const char *short_name)
607 struct TransportPlugin *head = plugins;
608 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
615 * Update the quota values for the given neighbour now.
618 update_quota (struct NeighbourList *n)
620 struct GNUNET_TIME_Relative delta;
624 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
625 if (delta.value < MIN_QUOTA_REFRESH_TIME)
626 return; /* not enough time passed for doing quota update */
627 allowed = delta.value * n->quota_in;
628 if (n->last_received < allowed)
630 remaining = allowed - n->last_received;
632 remaining /= n->quota_in;
635 if (remaining > MAX_BANDWIDTH_CARRY)
636 remaining = MAX_BANDWIDTH_CARRY;
637 n->last_received = 0;
638 n->last_quota_update = GNUNET_TIME_absolute_get ();
639 n->last_quota_update.value -= remaining;
640 if (n->quota_violation_count > 0)
641 n->quota_violation_count--;
645 n->last_received -= allowed;
646 n->last_quota_update = GNUNET_TIME_absolute_get ();
647 if (n->last_received > allowed)
649 /* more than twice the allowed rate! */
650 n->quota_violation_count += 10;
657 * Function called to notify a client about the socket
658 * being ready to queue more data. "buf" will be
659 * NULL and "size" zero if the socket was closed for
660 * writing in the meantime.
663 * @param size number of bytes available in buf
664 * @param buf where the callee should write the message
665 * @return number of bytes written to buf
668 transmit_to_client_callback (void *cls, size_t size, void *buf)
670 struct TransportClient *client = cls;
671 struct ClientMessageQueueEntry *q;
674 const struct GNUNET_MessageHeader *msg;
675 struct GNUNET_CONNECTION_TransmitHandle *th;
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Transmission to client failed, closing connection.\n");
682 /* fatal error with client, free message queue! */
683 while (NULL != (q = client->message_queue_head))
685 client->message_queue_head = q->next;
688 client->message_queue_tail = NULL;
689 client->message_count = 0;
694 while (NULL != (q = client->message_queue_head))
696 msg = (const struct GNUNET_MessageHeader *) &q[1];
697 msize = ntohs (msg->size);
698 if (msize + tsize > size)
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 "Transmitting message of type %u to client.\n",
705 client->message_queue_head = q->next;
707 client->message_queue_tail = NULL;
708 memcpy (&cbuf[tsize], msg, msize);
711 client->message_count--;
713 GNUNET_assert (tsize > 0);
716 th = GNUNET_SERVER_notify_transmit_ready (client->client,
718 GNUNET_TIME_UNIT_FOREVER_REL,
719 &transmit_to_client_callback,
721 GNUNET_assert (th != NULL);
728 * Send the specified message to the specified client. Since multiple
729 * messages may be pending for the same client at a time, this code
730 * makes sure that no message is lost.
732 * @param client client to transmit the message to
733 * @param msg the message to send
734 * @param may_drop can this message be dropped if the
735 * message queue for this client is getting far too large?
738 transmit_to_client (struct TransportClient *client,
739 const struct GNUNET_MessageHeader *msg, int may_drop)
741 struct ClientMessageQueueEntry *q;
743 struct GNUNET_CONNECTION_TransmitHandle *th;
745 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
747 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
749 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
750 client->message_count, MAX_PENDING);
751 /* TODO: call to statistics... */
754 client->message_count++;
755 msize = ntohs (msg->size);
756 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
757 memcpy (&q[1], msg, msize);
758 /* append to message queue */
759 if (client->message_queue_tail == NULL)
761 client->message_queue_tail = q;
765 client->message_queue_tail->next = q;
766 client->message_queue_tail = q;
768 if (client->message_queue_head == NULL)
770 client->message_queue_head = q;
771 th = GNUNET_SERVER_notify_transmit_ready (client->client,
773 GNUNET_TIME_UNIT_FOREVER_REL,
774 &transmit_to_client_callback,
776 GNUNET_assert (th != NULL);
782 * Find alternative plugins for communication.
784 * @param neighbour for which neighbour should we try to find
788 try_alternative_plugins (struct NeighbourList *neighbour)
790 struct ReadyList *rl;
792 if ((neighbour->plugins != NULL) &&
793 (neighbour->retry_plugins_time.value >
794 GNUNET_TIME_absolute_get ().value))
795 return; /* don't try right now */
796 neighbour->retry_plugins_time
797 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
799 rl = neighbour->plugins;
802 if (rl->connect_attempts > 0)
803 rl->connect_attempts--; /* amnesty */
811 * The peer specified by the given neighbour has timed-out or a plugin
812 * has disconnected. We may either need to do nothing (other plugins
813 * still up), or trigger a full disconnect and clean up. This
814 * function updates our state and do the necessary notifications.
815 * Also notifies our clients that the neighbour is now officially
818 * @param n the neighbour list entry for the peer
819 * @param check should we just check if all plugins
820 * disconnected or must we ask all plugins to
824 disconnect_neighbour (struct NeighbourList *n,
829 * Check the ready list for the given neighbour and
830 * if a plugin is ready for transmission (and if we
831 * have a message), do so!
833 * @param neighbour target peer for which to check the plugins
836 try_transmission_to_peer (struct NeighbourList *neighbour);
840 * Function called by the GNUNET_TRANSPORT_TransmitFunction
841 * upon "completion" of a send request. This tells the API
842 * that it is now legal to send another message to the given
845 * @param cls closure, identifies the entry on the
846 * message queue that was transmitted and the
847 * client responsible for queueing the message
848 * @param rl identifies plugin used for the transmission for
849 * this neighbour; needs to be re-enabled for
850 * future transmissions
851 * @param target the peer receiving the message
852 * @param result GNUNET_OK on success, if the transmission
853 * failed, we should not tell the client to transmit
857 transmit_send_continuation (void *cls,
858 struct ReadyList *rl,
859 const struct GNUNET_PeerIdentity *target,
862 struct MessageQueue *mq = cls;
863 struct SendOkMessage send_ok_msg;
864 struct NeighbourList *n;
866 GNUNET_assert (mq != NULL);
868 GNUNET_assert (n != NULL);
870 memcmp (&n->id, target,
871 sizeof (struct GNUNET_PeerIdentity)));
875 while ((rl != NULL) && (rl->plugin != mq->plugin))
877 GNUNET_assert (rl != NULL);
879 if (result == GNUNET_OK)
881 rl->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886 "Transmission to peer `%s' failed, marking connection as down.\n",
888 rl->connected = GNUNET_NO;
889 rl->plugin_handle = NULL;
891 if (!mq->internal_msg)
892 rl->transmit_ready = GNUNET_YES;
893 if (mq->client != NULL)
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
896 "Notifying client %p about failed transission to peer `%4s'.\n",
899 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
900 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
901 send_ok_msg.success = htonl (result);
902 send_ok_msg.peer = n->id;
903 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
905 GNUNET_free (mq->message);
907 /* one plugin just became ready again, try transmitting
908 another message (if available) */
909 if (result == GNUNET_OK)
910 try_transmission_to_peer (n);
912 disconnect_neighbour (n, GNUNET_YES);
917 * Check the ready list for the given neighbour and
918 * if a plugin is ready for transmission (and if we
919 * have a message), do so!
922 try_transmission_to_peer (struct NeighbourList *neighbour)
924 struct ReadyList *pos;
925 struct GNUNET_TIME_Relative min_latency;
926 struct ReadyList *rl;
927 struct MessageQueue *mq;
928 struct GNUNET_TIME_Absolute now;
930 if (neighbour->messages == NULL)
931 return; /* nothing to do */
932 try_alternative_plugins (neighbour);
933 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
935 mq = neighbour->messages;
936 now = GNUNET_TIME_absolute_get ();
937 pos = neighbour->plugins;
940 /* set plugins that are inactive for a long time back to disconnected */
941 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
945 "Marking long-time inactive connection to `%4s' as down.\n",
946 GNUNET_i2s (&neighbour->id));
948 pos->connected = GNUNET_NO;
950 if (((GNUNET_YES == pos->transmit_ready) ||
951 (mq->internal_msg)) &&
952 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
953 ((rl == NULL) || (min_latency.value > pos->latency.value)))
956 min_latency = pos->latency;
963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964 "No plugin ready to transmit message\n");
966 return; /* nobody ready */
968 if (GNUNET_NO == rl->connected)
970 rl->connect_attempts++;
971 rl->connected = GNUNET_YES;
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 "Establishing fresh connection with `%4s' via plugin `%s'\n",
975 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
978 neighbour->messages = mq->next;
979 mq->plugin = rl->plugin;
980 if (!mq->internal_msg)
981 rl->transmit_ready = GNUNET_NO;
983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
984 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
985 ntohs (mq->message->type),
986 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
989 = rl->plugin->api->send (rl->plugin->api->cls,
995 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
996 &transmit_send_continuation, mq);
1001 * Send the specified message to the specified peer.
1003 * @param client source of the transmission request (can be NULL)
1004 * @param priority how important is the message
1005 * @param msg message to send
1006 * @param is_internal is this an internal message
1007 * @param neighbour handle to the neighbour for transmission
1010 transmit_to_peer (struct TransportClient *client,
1011 unsigned int priority,
1012 const struct GNUNET_MessageHeader *msg,
1013 int is_internal, struct NeighbourList *neighbour)
1015 struct MessageQueue *mq;
1016 struct MessageQueue *mqe;
1017 struct GNUNET_MessageHeader *m;
1020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021 _("Sending message of type %u to peer `%4s'\n"),
1022 ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1026 /* check for duplicate submission */
1027 mq = neighbour->messages;
1030 if (mq->client == client)
1032 /* client transmitted to same peer twice
1033 before getting SendOk! */
1040 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1041 mq->client = client;
1042 m = GNUNET_malloc (ntohs (msg->size));
1043 memcpy (m, msg, ntohs (msg->size));
1045 mq->neighbour = neighbour;
1046 mq->internal_msg = is_internal;
1047 mq->priority = priority;
1050 mqe = neighbour->messages;
1052 while (mqe->next != NULL)
1057 neighbour->messages = mq;
1058 try_transmission_to_peer (neighbour);
1071 struct GeneratorContext
1073 struct TransportPlugin *plug_pos;
1074 struct AddressList *addr_pos;
1075 struct GNUNET_TIME_Absolute expiration;
1083 address_generator (void *cls, size_t max, void *buf)
1085 struct GeneratorContext *gc = cls;
1088 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1090 gc->plug_pos = gc->plug_pos->next;
1091 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1093 if (NULL == gc->plug_pos)
1095 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1098 gc->addr_pos->addrlen, buf, max);
1099 gc->addr_pos = gc->addr_pos->next;
1105 * Construct our HELLO message from all of the addresses of
1106 * all of the transports.
1111 struct GNUNET_HELLO_Message *hello;
1112 struct TransportClient *cpos;
1113 struct NeighbourList *npos;
1114 struct GeneratorContext gc;
1117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1118 "Refreshing my `%s'\n",
1121 gc.plug_pos = plugins;
1122 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1123 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1124 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1126 while (cpos != NULL)
1128 transmit_to_client (cpos,
1129 (const struct GNUNET_MessageHeader *) hello,
1134 GNUNET_free_non_null (our_hello);
1136 our_hello_version++;
1138 while (npos != NULL)
1141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1142 "Transmitting updated `%s' to neighbour `%4s'\n",
1144 GNUNET_i2s(&npos->id));
1146 transmit_to_peer (NULL, 0,
1147 (const struct GNUNET_MessageHeader *) our_hello,
1155 * Task used to clean up expired addresses for a plugin.
1157 * @param cls closure
1161 expire_address_task (void *cls,
1162 const struct GNUNET_SCHEDULER_TaskContext *tc);
1166 * Update the list of addresses for this plugin,
1167 * expiring those that are past their expiration date.
1169 * @param plugin addresses of which plugin should be recomputed?
1170 * @param fresh set to GNUNET_YES if a new address was added
1171 * and we need to regenerate the HELLO even if nobody
1175 update_addresses (struct TransportPlugin *plugin, int fresh)
1177 struct GNUNET_TIME_Relative min_remaining;
1178 struct GNUNET_TIME_Relative remaining;
1179 struct GNUNET_TIME_Absolute now;
1180 struct AddressList *pos;
1181 struct AddressList *prev;
1182 struct AddressList *next;
1185 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1186 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1187 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1188 now = GNUNET_TIME_absolute_get ();
1189 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1190 expired = GNUNET_NO;
1192 pos = plugin->addresses;
1196 if (pos->expires.value < now.value)
1198 expired = GNUNET_YES;
1200 plugin->addresses = pos->next;
1202 prev->next = pos->next;
1207 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1208 if (remaining.value < min_remaining.value)
1209 min_remaining = remaining;
1215 if (expired || fresh)
1217 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1218 plugin->address_update_task
1219 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1221 GNUNET_SCHEDULER_PRIORITY_IDLE,
1222 GNUNET_SCHEDULER_NO_TASK,
1224 &expire_address_task, plugin);
1230 * Task used to clean up expired addresses for a plugin.
1232 * @param cls closure
1236 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1238 struct TransportPlugin *plugin = cls;
1239 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1240 update_addresses (plugin, GNUNET_NO);
1245 * Function that must be called by each plugin to notify the
1246 * transport service about the addresses under which the transport
1247 * provided by the plugin can be reached.
1249 * @param cls closure
1250 * @param name name of the transport that generated the address
1251 * @param addr one of the addresses of the host, NULL for the last address
1252 * the specific address format depends on the transport
1253 * @param addrlen length of the address
1254 * @param expires when should this address automatically expire?
1257 plugin_env_notify_address (void *cls,
1261 struct GNUNET_TIME_Relative expires)
1263 struct TransportPlugin *p = cls;
1264 struct AddressList *al;
1265 struct GNUNET_TIME_Absolute abex;
1267 abex = GNUNET_TIME_relative_to_absolute (expires);
1268 GNUNET_assert (p == find_transport (name));
1273 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1275 if (al->expires.value < abex.value)
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Plugin `%s' informs us about a new address `%s'\n", name,
1284 GNUNET_a2s(addr, addrlen));
1286 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1288 al->next = p->addresses;
1291 al->addrlen = addrlen;
1292 memcpy (&al[1], addr, addrlen);
1293 update_addresses (p, GNUNET_YES);
1300 struct LookupHelloContext
1302 GNUNET_TRANSPORT_AddressCallback iterator;
1312 lookup_address_callback (void *cls,
1314 struct GNUNET_TIME_Absolute expiration,
1315 const void *addr, size_t addrlen)
1317 struct LookupHelloContext *lhc = cls;
1318 lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
1327 lookup_hello_callback (void *cls,
1328 const struct GNUNET_PeerIdentity *peer,
1329 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1331 struct LookupHelloContext *lhc = cls;
1335 lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
1341 GNUNET_HELLO_iterate_addresses (h,
1342 GNUNET_NO, &lookup_address_callback, lhc);
1347 * Function that allows a transport to query the known
1348 * network addresses for a given peer.
1350 * @param cls closure
1351 * @param timeout after how long should we time out?
1352 * @param target which peer are we looking for?
1353 * @param iter function to call for each known address
1354 * @param iter_cls closure for iter
1357 plugin_env_lookup_address (void *cls,
1358 struct GNUNET_TIME_Relative timeout,
1359 const struct GNUNET_PeerIdentity *target,
1360 GNUNET_TRANSPORT_AddressCallback iter,
1363 struct LookupHelloContext *lhc;
1365 lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
1366 lhc->iterator = iter;
1367 lhc->iterator_cls = iter_cls;
1368 GNUNET_PEERINFO_for_all (cfg,
1370 target, 0, timeout, &lookup_hello_callback, &lhc);
1375 * Notify all of our clients about a peer connecting.
1378 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1379 struct GNUNET_TIME_Relative latency)
1381 struct ConnectInfoMessage cim;
1382 struct TransportClient *cpos;
1385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386 "Informing clients about peer `%4s' connecting to us\n",
1389 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1390 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1391 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60*1000));
1392 cim.latency = GNUNET_TIME_relative_hton (latency);
1393 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1395 while (cpos != NULL)
1397 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1404 * Notify all of our clients about a peer disconnecting.
1407 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1409 struct DisconnectInfoMessage dim;
1410 struct TransportClient *cpos;
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "Informing clients about peer `%4s' disconnecting\n",
1417 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1418 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1419 dim.reserved = htonl (0);
1420 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1422 while (cpos != NULL)
1424 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1431 * Copy any validated addresses to buf.
1433 * @return 0 once all addresses have been
1437 list_validated_addresses (void *cls, size_t max, void *buf)
1439 struct ValidationAddress **va = cls;
1442 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1446 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1448 &(*va)[1], (*va)->addr_len, buf, max);
1455 * HELLO validation cleanup task.
1458 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1460 struct ValidationAddress *va;
1461 struct ValidationList *pos;
1462 struct ValidationList *prev;
1463 struct GNUNET_TIME_Absolute now;
1464 struct GNUNET_TIME_Absolute first;
1465 struct GNUNET_HELLO_Message *hello;
1466 struct GNUNET_PeerIdentity pid;
1467 struct NeighbourList *n;
1470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1471 "HELLO validation cleanup background task running...\n");
1473 now = GNUNET_TIME_absolute_get ();
1475 pos = pending_validations;
1478 if (pos->timeout.value < now.value)
1481 pending_validations = pos->next;
1483 prev->next = pos->next;
1484 va = pos->addresses;
1485 hello = GNUNET_HELLO_create (&pos->publicKey,
1486 &list_validated_addresses, &va);
1487 GNUNET_CRYPTO_hash (&pos->publicKey,
1489 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1494 "HELLO", GNUNET_i2s (&pid));
1496 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1497 n = find_neighbour (&pid);
1499 try_transmission_to_peer (n);
1500 GNUNET_free (hello);
1501 while (NULL != (va = pos->addresses))
1503 pos->addresses = va->next;
1504 GNUNET_free (va->transport_name);
1509 pos = pending_validations;
1518 /* finally, reschedule cleanup if needed; list is
1519 ordered by timeout, so we need the last element... */
1520 if (NULL != pending_validations)
1522 first = pending_validations->timeout;
1523 pos = pending_validations;
1526 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1529 GNUNET_SCHEDULER_add_delayed (sched,
1531 GNUNET_SCHEDULER_PRIORITY_IDLE,
1532 GNUNET_SCHEDULER_NO_TASK,
1533 GNUNET_TIME_absolute_get_remaining (first),
1534 &cleanup_validation, NULL);
1542 * Function that will be called if we receive a validation
1543 * of an address challenge that we transmitted to another
1544 * peer. Note that the validation should only be considered
1545 * acceptable if the challenge matches AND if the sender
1546 * address is at least a plausible address for this peer
1547 * (otherwise we may be seeing a MiM attack).
1549 * @param cls closure
1550 * @param name name of the transport that generated the address
1551 * @param peer who responded to our challenge
1552 * @param challenge the challenge number we presumably used
1553 * @param sender_addr string describing our sender address (as observed
1554 * by the other peer in human-readable format)
1557 plugin_env_notify_validation (void *cls,
1559 const struct GNUNET_PeerIdentity *peer,
1561 const char *sender_addr)
1563 unsigned int not_done;
1565 struct ValidationList *pos;
1566 struct ValidationAddress *va;
1567 struct GNUNET_PeerIdentity id;
1569 pos = pending_validations;
1572 GNUNET_CRYPTO_hash (&pos->publicKey,
1574 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1577 memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1583 /* TODO: call statistics (unmatched PONG) */
1584 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1586 ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
1591 matched = GNUNET_NO;
1592 va = pos->addresses;
1595 if (va->challenge == challenge)
1598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1599 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1601 GNUNET_a2s ((const struct sockaddr*) &va[1],
1604 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1605 _("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"),
1608 va->ok = GNUNET_YES;
1610 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1611 matched = GNUNET_YES;
1613 if (va->ok != GNUNET_YES)
1617 if (GNUNET_NO == matched)
1619 /* TODO: call statistics (unmatched PONG) */
1620 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1622 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1629 "All addresses validated, will now construct `%s' for `%4s'.\n",
1633 pos->timeout.value = 0;
1634 GNUNET_SCHEDULER_add_delayed (sched,
1636 GNUNET_SCHEDULER_PRIORITY_IDLE,
1637 GNUNET_SCHEDULER_NO_TASK,
1638 GNUNET_TIME_UNIT_ZERO,
1639 &cleanup_validation, NULL);
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1655 struct CheckHelloValidatedContext
1658 * Plugin for which we are validating.
1660 struct TransportPlugin *plugin;
1663 * Hello that we are validating.
1665 struct GNUNET_HELLO_Message *hello;
1668 * Validation list being build.
1670 struct ValidationList *e;
1676 * Append the given address to the list of entries
1677 * that need to be validated.
1680 run_validation (void *cls,
1682 struct GNUNET_TIME_Absolute expiration,
1683 const void *addr, size_t addrlen)
1685 struct ValidationList *e = cls;
1686 struct TransportPlugin *tp;
1687 struct ValidationAddress *va;
1688 struct GNUNET_PeerIdentity id;
1690 tp = find_transport (tname);
1693 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1694 GNUNET_ERROR_TYPE_BULK,
1696 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1700 GNUNET_CRYPTO_hash (&e->publicKey,
1702 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1706 GNUNET_a2s(addr, addrlen),
1710 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1711 va->next = e->addresses;
1713 va->transport_name = GNUNET_strdup (tname);
1714 va->addr_len = addrlen;
1715 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1717 memcpy (&va[1], addr, addrlen);
1723 * Check if addresses in validated hello "h" overlap with
1724 * those in "chvc->hello" and update "chvc->hello" accordingly,
1725 * removing those addresses that have already been validated.
1728 check_hello_validated (void *cls,
1729 const struct GNUNET_PeerIdentity *peer,
1730 const struct GNUNET_HELLO_Message *h,
1733 struct CheckHelloValidatedContext *chvc = cls;
1734 struct ValidationAddress *va;
1735 struct TransportPlugin *tp;
1737 struct GNUNET_PeerIdentity apeer;
1739 first_call = GNUNET_NO;
1740 if (chvc->e == NULL)
1742 first_call = GNUNET_YES;
1743 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1744 GNUNET_assert (GNUNET_OK ==
1745 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1746 &chvc->e->publicKey));
1748 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1749 chvc->e->next = pending_validations;
1750 pending_validations = chvc->e;
1754 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1756 GNUNET_TIME_absolute_get (),
1757 &run_validation, chvc->e);
1759 else if (GNUNET_YES == first_call)
1761 /* no existing HELLO, all addresses are new */
1762 GNUNET_HELLO_iterate_addresses (chvc->hello,
1763 GNUNET_NO, &run_validation, chvc->e);
1766 return; /* wait for next call */
1767 /* finally, transmit validation attempts */
1768 GNUNET_assert (GNUNET_OK ==
1769 GNUNET_HELLO_get_id (chvc->hello,
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1774 "HELLO", GNUNET_i2s (&apeer));
1776 va = chvc->e->addresses;
1780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1781 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1784 GNUNET_a2s ((const struct sockaddr*) &va[1],
1786 GNUNET_i2s (&apeer));
1788 tp = find_transport (va->transport_name);
1789 GNUNET_assert (tp != NULL);
1791 tp->api->validate (tp->api->cls,
1794 HELLO_VERIFICATION_TIMEOUT,
1797 va->ok = GNUNET_SYSERR;
1800 GNUNET_SCHEDULER_add_delayed (sched,
1802 GNUNET_SCHEDULER_PRIORITY_IDLE,
1803 GNUNET_SCHEDULER_NO_TASK,
1804 GNUNET_TIME_absolute_get_remaining (chvc->e->timeout),
1805 &cleanup_validation, NULL);
1811 * Process HELLO-message.
1813 * @param plugin transport involved, may be NULL
1814 * @param message the actual message
1815 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1818 process_hello (struct TransportPlugin *plugin,
1819 const struct GNUNET_MessageHeader *message)
1821 struct ValidationList *e;
1823 struct GNUNET_PeerIdentity target;
1824 const struct GNUNET_HELLO_Message *hello;
1825 struct CheckHelloValidatedContext *chvc;
1826 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1828 hsize = ntohs (message->size);
1829 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1830 (hsize < sizeof (struct GNUNET_MessageHeader)))
1833 return GNUNET_SYSERR;
1835 /* first, check if load is too high */
1836 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1838 /* TODO: call to stats? */
1841 hello = (const struct GNUNET_HELLO_Message *) message;
1842 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1844 GNUNET_break_op (0);
1845 return GNUNET_SYSERR;
1847 GNUNET_CRYPTO_hash (&publicKey,
1848 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1849 &target.hashPubKey);
1851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1852 "Processing `%s' message for `%4s'\n",
1853 "HELLO", GNUNET_i2s (&target));
1855 /* check if a HELLO for this peer is already on the validation list */
1856 e = pending_validations;
1859 if (0 == memcmp (&e->publicKey,
1862 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1864 /* TODO: call to stats? */
1866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1867 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1868 "HELLO", GNUNET_i2s (&target));
1874 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1875 chvc->plugin = plugin;
1876 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1877 memcpy (chvc->hello, hello, hsize);
1878 /* finally, check if HELLO was previously validated
1879 (continuation will then schedule actual validation) */
1880 GNUNET_PEERINFO_for_all (cfg,
1884 HELLO_VERIFICATION_TIMEOUT,
1885 &check_hello_validated, chvc);
1891 * The peer specified by the given neighbour has timed-out or a plugin
1892 * has disconnected. We may either need to do nothing (other plugins
1893 * still up), or trigger a full disconnect and clean up. This
1894 * function updates our state and do the necessary notifications.
1895 * Also notifies our clients that the neighbour is now officially
1898 * @param n the neighbour list entry for the peer
1899 * @param check should we just check if all plugins
1900 * disconnected or must we ask all plugins to
1904 disconnect_neighbour (struct NeighbourList *n,
1907 struct ReadyList *rpos;
1908 struct NeighbourList *npos;
1909 struct NeighbourList *nprev;
1910 struct MessageQueue *mq;
1912 if (GNUNET_YES == check)
1915 while (NULL != rpos)
1917 if (GNUNET_YES == rpos->connected)
1918 return; /* still connected */
1924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1925 "Disconnecting from `%4s'\n",
1926 GNUNET_i2s(&n->id));
1928 /* remove n from neighbours list */
1931 while ((npos != NULL) && (npos != n))
1936 GNUNET_assert (npos != NULL);
1938 neighbours = n->next;
1940 nprev->next = n->next;
1942 /* notify all clients about disconnect */
1943 notify_clients_disconnect (&n->id);
1945 /* clean up all plugins, cancel connections and pending transmissions */
1946 while (NULL != (rpos = n->plugins))
1948 n->plugins = rpos->next;
1949 GNUNET_assert (rpos->neighbour == n);
1950 if (GNUNET_YES == rpos->connected)
1951 rpos->plugin->api->cancel (rpos->plugin->api->cls,
1952 rpos->plugin_handle,
1958 /* free all messages on the queue */
1959 while (NULL != (mq = n->messages))
1961 n->messages = mq->next;
1962 GNUNET_assert (mq->neighbour == n);
1965 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1966 GNUNET_SCHEDULER_cancel (sched,
1968 /* finally, free n itself */
1974 * Add an entry for each of our transport plugins
1975 * (that are able to send) to the list of plugins
1976 * for this neighbour.
1978 * @param neighbour to initialize
1981 add_plugins (struct NeighbourList *neighbour)
1983 struct TransportPlugin *tp;
1984 struct ReadyList *rl;
1986 neighbour->retry_plugins_time
1987 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1991 if (tp->api->send != NULL)
1993 rl = GNUNET_malloc (sizeof (struct ReadyList));
1994 rl->next = neighbour->plugins;
1995 neighbour->plugins = rl;
1997 rl->neighbour = neighbour;
1998 rl->transmit_ready = GNUNET_YES;
2006 neighbour_timeout_task (void *cls,
2007 const struct GNUNET_SCHEDULER_TaskContext *tc)
2009 struct NeighbourList *n = cls;
2012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2013 "Neighbour `%4s' has timed out!\n",
2014 GNUNET_i2s(&n->id));
2016 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2017 disconnect_neighbour (n, GNUNET_NO);
2022 * Create a fresh entry in our neighbour list for the given peer.
2023 * Will try to transmit our current HELLO to the new neighbour. Also
2024 * notifies our clients about the new "connection".
2026 * @param peer the peer for which we create the entry
2027 * @return the new neighbour list entry
2029 static struct NeighbourList *
2030 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2032 struct NeighbourList *n;
2035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2036 "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
2039 GNUNET_assert (our_hello != NULL);
2040 n = GNUNET_malloc (sizeof (struct NeighbourList));
2041 n->next = neighbours;
2044 n->last_quota_update = GNUNET_TIME_absolute_get ();
2046 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2047 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2049 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2051 GNUNET_SCHEDULER_PRIORITY_IDLE,
2052 GNUNET_SCHEDULER_NO_TASK,
2053 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2054 &neighbour_timeout_task, n);
2055 transmit_to_peer (NULL, 0,
2056 (const struct GNUNET_MessageHeader *) our_hello,
2058 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2064 * Function called by the plugin for each received message.
2065 * Update data volumes, possibly notify plugins about
2066 * reducing the rate at which they read from the socket
2067 * and generally forward to our receive callback.
2069 * @param plugin_context value to pass to this plugin
2070 * to respond to the given peer (use is optional,
2071 * but may speed up processing)
2072 * @param service_context value passed to the transport-service
2073 * to identify the neighbour; will be NULL on the first
2074 * call for a given peer
2075 * @param latency estimated latency for communicating with the
2077 * @param peer (claimed) identity of the other peer
2078 * @param message the message, NULL if peer was disconnected
2079 * @return the new service_context that the plugin should use
2080 * for future receive calls for messages from this
2083 static struct ReadyList *
2084 plugin_env_receive (void *cls,
2085 void *plugin_context,
2086 struct ReadyList *service_context,
2087 struct GNUNET_TIME_Relative latency,
2088 const struct GNUNET_PeerIdentity *peer,
2089 const struct GNUNET_MessageHeader *message)
2091 const struct GNUNET_MessageHeader ack = {
2092 htons (sizeof (struct GNUNET_MessageHeader)),
2093 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2095 struct TransportPlugin *plugin = cls;
2096 struct TransportClient *cpos;
2097 struct InboundMessage *im;
2099 struct NeighbourList *n;
2101 if (service_context != NULL)
2103 n = service_context->neighbour;
2104 GNUNET_assert (n != NULL);
2108 n = find_neighbour (peer);
2111 if (message == NULL)
2112 return NULL; /* disconnect of peer already marked down */
2113 n = setup_new_neighbour (peer);
2115 service_context = n->plugins;
2116 while ((service_context != NULL) && (plugin != service_context->plugin))
2117 service_context = service_context->next;
2118 GNUNET_assert ((plugin->api->send == NULL) ||
2119 (service_context != NULL));
2121 if (message == NULL)
2124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2125 "Receive failed from `%4s', triggering disconnect\n",
2126 GNUNET_i2s(&n->id));
2128 /* TODO: call stats */
2129 if ((service_context != NULL) &&
2130 (service_context->plugin_handle == plugin_context))
2132 service_context->connected = GNUNET_NO;
2133 service_context->plugin_handle = NULL;
2135 disconnect_neighbour (n, GNUNET_YES);
2139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2140 "Processing message of type `%u' received by plugin...\n",
2141 ntohs (message->type));
2143 if (service_context != NULL)
2145 if (service_context->connected == GNUNET_NO)
2147 service_context->connected = GNUNET_YES;
2148 service_context->transmit_ready = GNUNET_YES;
2149 service_context->connect_attempts++;
2151 service_context->timeout
2152 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2153 service_context->plugin_handle = plugin_context;
2154 service_context->latency = latency;
2156 /* update traffic received amount ... */
2157 msize = ntohs (message->size);
2158 n->last_received += msize;
2159 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2161 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2163 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
2164 GNUNET_SCHEDULER_PRIORITY_IDLE,
2165 GNUNET_SCHEDULER_NO_TASK,
2166 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2167 &neighbour_timeout_task, n);
2169 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2171 /* dropping message due to frequent inbound volume violations! */
2172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2173 GNUNET_ERROR_TYPE_BULK,
2175 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2176 /* TODO: call stats */
2177 GNUNET_assert ( (service_context == NULL) ||
2178 (NULL != service_context->neighbour) );
2179 return service_context;
2181 switch (ntohs (message->type))
2183 case GNUNET_MESSAGE_TYPE_HELLO:
2185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2186 "Receiving `%s' message from `%4s'.\n", "HELLO",
2189 process_hello (plugin, message);
2191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2192 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2195 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2197 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2198 n->saw_ack = GNUNET_YES;
2199 /* intentional fall-through! */
2202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2203 "Received message of type %u from `%4s', sending to all clients.\n",
2204 ntohs (message->type),
2207 /* transmit message to all clients */
2208 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2209 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2210 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2211 im->latency = GNUNET_TIME_relative_hton (latency);
2213 memcpy (&im[1], message, msize);
2216 while (cpos != NULL)
2218 transmit_to_client (cpos, &im->header, GNUNET_YES);
2223 GNUNET_assert ( (service_context == NULL) ||
2224 (NULL != service_context->neighbour) );
2225 return service_context;
2230 * Handle START-message. This is the first message sent to us
2231 * by any client which causes us to add it to our list.
2233 * @param cls closure (always NULL)
2234 * @param client identification of the client
2235 * @param message the actual message
2238 handle_start (void *cls,
2239 struct GNUNET_SERVER_Client *client,
2240 const struct GNUNET_MessageHeader *message)
2242 struct TransportClient *c;
2243 struct ConnectInfoMessage cim;
2244 struct NeighbourList *n;
2245 struct InboundMessage *im;
2246 struct GNUNET_MessageHeader *ack;
2249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2250 "Received `%s' request from client\n", "START");
2255 if (c->client == client)
2257 /* client already on our list! */
2259 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2264 c = GNUNET_malloc (sizeof (struct TransportClient));
2268 if (our_hello != NULL)
2271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2272 "Sending our own `%s' to new client\n",
2275 transmit_to_client (c,
2276 (const struct GNUNET_MessageHeader *) our_hello,
2278 /* tell new client about all existing connections */
2279 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2280 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2281 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2282 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2283 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2284 sizeof (struct GNUNET_MessageHeader));
2285 im->header.size = htons (sizeof (struct InboundMessage) +
2286 sizeof (struct GNUNET_MessageHeader));
2287 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2288 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2289 ack = (struct GNUNET_MessageHeader *) &im[1];
2290 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2291 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2292 for (n = neighbours; n != NULL; n = n->next)
2295 transmit_to_client (c, &cim.header, GNUNET_NO);
2299 transmit_to_client (c, &im->header, GNUNET_NO);
2304 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2309 * Handle HELLO-message.
2311 * @param cls closure (always NULL)
2312 * @param client identification of the client
2313 * @param message the actual message
2316 handle_hello (void *cls,
2317 struct GNUNET_SERVER_Client *client,
2318 const struct GNUNET_MessageHeader *message)
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324 "Received `%s' request from client\n", "HELLO");
2326 ret = process_hello (NULL, message);
2327 GNUNET_SERVER_receive_done (client, ret);
2332 * Handle SEND-message.
2334 * @param cls closure (always NULL)
2335 * @param client identification of the client
2336 * @param message the actual message
2339 handle_send (void *cls,
2340 struct GNUNET_SERVER_Client *client,
2341 const struct GNUNET_MessageHeader *message)
2343 struct TransportClient *tc;
2344 struct NeighbourList *n;
2345 const struct OutboundMessage *obm;
2346 const struct GNUNET_MessageHeader *obmm;
2350 size = ntohs (message->size);
2352 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2355 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2358 obm = (const struct OutboundMessage *) message;
2360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2361 "Received `%s' request from client with target `%4s'\n",
2362 "SEND", GNUNET_i2s (&obm->peer));
2364 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2365 msize = ntohs (obmm->size);
2366 if (size != msize + sizeof (struct OutboundMessage))
2369 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2372 n = find_neighbour (&obm->peer);
2374 n = setup_new_neighbour (&obm->peer);
2376 while ((tc != NULL) && (tc->client != client))
2380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2381 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2383 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2385 transmit_to_peer (tc, ntohl(obm->priority), obmm, GNUNET_NO, n);
2386 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2391 * Handle SET_QUOTA-message.
2393 * @param cls closure (always NULL)
2394 * @param client identification of the client
2395 * @param message the actual message
2398 handle_set_quota (void *cls,
2399 struct GNUNET_SERVER_Client *client,
2400 const struct GNUNET_MessageHeader *message)
2402 const struct QuotaSetMessage *qsm =
2403 (const struct QuotaSetMessage *) message;
2404 struct NeighbourList *n;
2405 struct TransportPlugin *p;
2406 struct ReadyList *rl;
2409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2410 "Received `%s' request from client for peer `%4s'\n",
2411 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2413 n = find_neighbour (&qsm->peer);
2416 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2420 if (n->quota_in < ntohl (qsm->quota_in))
2421 n->last_quota_update = GNUNET_TIME_absolute_get ();
2422 n->quota_in = ntohl (qsm->quota_in);
2427 p->api->set_receive_quota (p->api->cls,
2428 &qsm->peer, ntohl (qsm->quota_in));
2431 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2436 * Handle TRY_CONNECT-message.
2438 * @param cls closure (always NULL)
2439 * @param client identification of the client
2440 * @param message the actual message
2443 handle_try_connect (void *cls,
2444 struct GNUNET_SERVER_Client *client,
2445 const struct GNUNET_MessageHeader *message)
2447 const struct TryConnectMessage *tcm;
2449 tcm = (const struct TryConnectMessage *) message;
2451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2452 "Received `%s' request from client %p asking to connect to `%4s'\n",
2455 GNUNET_i2s (&tcm->peer));
2457 if (NULL == find_neighbour (&tcm->peer))
2458 setup_new_neighbour (&tcm->peer);
2461 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2462 "Client asked to connect to `%4s', but connection already exists\n",
2464 GNUNET_i2s (&tcm->peer));
2466 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2471 * List of handlers for the messages understood by this
2474 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2475 {&handle_start, NULL,
2476 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2477 {&handle_hello, NULL,
2478 GNUNET_MESSAGE_TYPE_HELLO, 0},
2479 {&handle_send, NULL,
2480 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2481 {&handle_set_quota, NULL,
2482 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2483 {&handle_try_connect, NULL,
2484 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2485 sizeof (struct TryConnectMessage)},
2491 * Setup the environment for this plugin.
2494 create_environment (struct TransportPlugin *plug)
2496 plug->env.cfg = cfg;
2497 plug->env.sched = sched;
2498 plug->env.my_public_key = &my_public_key;
2499 plug->env.my_private_key = my_private_key;
2500 plug->env.my_identity = &my_identity;
2501 plug->env.cls = plug;
2502 plug->env.receive = &plugin_env_receive;
2503 plug->env.lookup = &plugin_env_lookup_address;
2504 plug->env.notify_address = &plugin_env_notify_address;
2505 plug->env.notify_validation = &plugin_env_notify_validation;
2506 plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2507 plug->env.max_connections = max_connect_per_transport;
2512 * Start the specified transport (load the plugin).
2515 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2517 struct TransportPlugin *plug;
2520 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2521 _("Loading `%s' transport plugin\n"), name);
2522 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2523 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2524 create_environment (plug);
2525 plug->short_name = GNUNET_strdup (name);
2526 plug->lib_name = libname;
2527 plug->next = plugins;
2529 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2530 if (plug->api == NULL)
2532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2533 _("Failed to load transport plugin for `%s'\n"), name);
2534 GNUNET_free (plug->short_name);
2535 plugins = plug->next;
2536 GNUNET_free (libname);
2543 * Called whenever a client is disconnected. Frees our
2544 * resources associated with that client.
2546 * @param cls closure
2547 * @param client identification of the client
2550 client_disconnect_notification (void *cls,
2551 struct GNUNET_SERVER_Client *client)
2553 struct TransportClient *pos;
2554 struct TransportClient *prev;
2555 struct ClientMessageQueueEntry *mqe;
2558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2559 "Client disconnected, cleaning up.\n");
2563 while ((pos != NULL) && (pos->client != client))
2570 while (NULL != (mqe = pos->message_queue_head))
2572 pos->message_queue_head = mqe->next;
2575 pos->message_queue_head = NULL;
2577 clients = pos->next;
2579 prev->next = pos->next;
2580 if (GNUNET_YES == pos->tcs_pending)
2590 * Initiate transport service.
2592 * @param cls closure
2593 * @param s scheduler to use
2594 * @param serv the initialized server
2595 * @param c configuration to use
2599 struct GNUNET_SCHEDULER_Handle *s,
2600 struct GNUNET_SERVER_Handle *serv,
2601 const struct GNUNET_CONFIGURATION_Handle *c)
2606 unsigned long long tneigh;
2611 /* parse configuration */
2613 GNUNET_CONFIGURATION_get_value_number (c,
2618 GNUNET_CONFIGURATION_get_value_filename (c,
2620 "HOSTKEY", &keyfile)))
2622 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2624 ("Transport service is lacking key configuration settings. Exiting.\n"));
2625 GNUNET_SCHEDULER_shutdown (s);
2628 max_connect_per_transport = (uint32_t) tneigh;
2629 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2630 GNUNET_free (keyfile);
2631 if (my_private_key == NULL)
2633 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2635 ("Transport service could not access hostkey. Exiting.\n"));
2636 GNUNET_SCHEDULER_shutdown (s);
2639 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2640 GNUNET_CRYPTO_hash (&my_public_key,
2641 sizeof (my_public_key), &my_identity.hashPubKey);
2642 /* setup notification */
2644 GNUNET_SERVER_disconnect_notify (server,
2645 &client_disconnect_notification, NULL);
2646 /* load plugins... */
2649 GNUNET_CONFIGURATION_get_value_string (c,
2650 "TRANSPORT", "PLUGINS", &plugs))
2652 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2653 _("Starting transport plugins `%s'\n"), plugs);
2654 pos = strtok (plugs, " ");
2657 start_transport (server, pos);
2659 pos = strtok (NULL, " ");
2661 GNUNET_free (plugs);
2666 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2667 _("Transport service ready.\n"));
2669 /* process client requests */
2670 GNUNET_SERVER_add_handlers (server, handlers);
2675 * Function called when the service shuts
2676 * down. Unloads our plugins.
2678 * @param cls closure
2679 * @param cfg configuration to use
2682 unload_plugins (void *cls,
2683 const struct GNUNET_CONFIGURATION_Handle *cfg)
2685 struct TransportPlugin *plug;
2686 struct AddressList *al;
2689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2690 "Transport service is unloading plugins...\n");
2692 while (NULL != (plug = plugins))
2694 plugins = plug->next;
2695 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2696 GNUNET_free (plug->lib_name);
2697 GNUNET_free (plug->short_name);
2698 while (NULL != (al = plug->addresses))
2700 plug->addresses = al->next;
2705 if (my_private_key != NULL)
2706 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2707 GNUNET_free_non_null (our_hello);
2712 * The main function for the transport service.
2714 * @param argc number of arguments from the command line
2715 * @param argv command line arguments
2716 * @return 0 ok, 1 on error
2719 main (int argc, char *const *argv)
2721 return (GNUNET_OK ==
2722 GNUNET_SERVICE_run (argc,
2725 &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
2728 /* end of gnunet-service-transport.c */