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_getopt_lib.h"
33 #include "gnunet_hello_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_peerinfo_service.h"
36 #include "gnunet_plugin_lib.h"
37 #include "gnunet_protocols.h"
38 #include "gnunet_service_lib.h"
39 #include "gnunet_signatures.h"
40 #include "plugin_transport.h"
41 #include "transport.h"
44 * How many messages can we have pending for a given client process
45 * before we start to drop incoming messages? We typically should
46 * have only one client and so this would be the primary buffer for
47 * messages, so the number should be chosen rather generously.
49 * The expectation here is that most of the time the queue is large
50 * enough so that a drop is virtually never required.
52 #define MAX_PENDING 128
55 * How often should we try to reconnect to a peer using a particular
56 * transport plugin before giving up? Note that the plugin may be
57 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
59 #define MAX_CONNECT_RETRY 3
62 * How often must a peer violate bandwidth quotas before we start
63 * to simply drop its messages?
65 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
68 * How long until a HELLO verification attempt should time out?
70 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
73 * How often do we re-add (cheaper) plugins to our list of plugins
74 * to try for a given connected peer?
76 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
79 * After how long do we expire an address in a HELLO
80 * that we just validated? This value is also used
81 * for our own addresses when we create a HELLO.
83 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
86 * After how long do we consider a connection to a peer dead
87 * if we don't receive messages from the peer?
89 #define IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
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
226 * For a given Neighbour, which plugins are available
227 * to talk to this peer and what are their costs?
233 * This is a linked list.
235 struct ReadyList *next;
238 * Which of our transport plugins does this entry
241 struct TransportPlugin *plugin;
244 * Neighbour this entry belongs to.
246 struct NeighbourList *neighbour;
249 * Opaque handle (specific to the plugin) for the
250 * connection to our target; can be NULL.
255 * What was the last latency observed for this plugin
256 * and peer? Invalid if connected is GNUNET_NO.
258 struct GNUNET_TIME_Relative latency;
261 * If we did not successfully transmit a message to the
262 * given peer via this connection during the specified
263 * time, we should consider the connection to be dead.
264 * This is used in the case that a TCP transport simply
265 * stalls writing to the stream but does not formerly
266 * get a signal that the other peer died.
268 struct GNUNET_TIME_Absolute timeout;
271 * Is this plugin currently connected? The first time
272 * we transmit or send data to a peer via a particular
273 * plugin, we set this to GNUNET_YES. If we later get
274 * an error (disconnect notification or transmission
275 * failure), we set it back to GNUNET_NO. Each time the
276 * value is set to GNUNET_YES, we increment the
277 * "connect_attempts" counter. If that one reaches a
278 * particular threshold, we consider the plugin to not
279 * be working properly at this time for the given peer
280 * and remove it from the eligible list.
285 * How often have we tried to connect using this plugin?
287 unsigned int connect_attempts;
290 * Is this plugin ready to transmit to the specific
291 * target? GNUNET_NO if not. Initially, all plugins
292 * are marked ready. If a transmission is in progress,
293 * "transmit_ready" is set to GNUNET_NO.
301 * Entry in linked list of all of our current neighbours.
307 * This is a linked list.
309 struct NeighbourList *next;
312 * Which of our transports is connected to this peer
313 * and what is their status?
315 struct ReadyList *plugins;
318 * List of messages we would like to send to this peer;
319 * must contain at most one message per client.
321 struct MessageQueue *messages;
324 * Identity of this neighbour.
326 struct GNUNET_PeerIdentity id;
329 * ID of task scheduled to run when this peer is about to
330 * time out (will free resources associated with the peer).
332 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
335 * How long until we should consider this peer dead
336 * (if we don't receive another message in the
339 struct GNUNET_TIME_Absolute peer_timeout;
342 * At what time did we reset last_received last?
344 struct GNUNET_TIME_Absolute last_quota_update;
347 * At what time should we try to again add plugins to
350 struct GNUNET_TIME_Absolute retry_plugins_time;
353 * How many bytes have we received since the "last_quota_update"
356 uint64_t last_received;
359 * Global quota for outbound traffic for the neighbour in bytes/ms.
364 * What is the latest version of our HELLO that we have
365 * sent to this neighbour?
367 unsigned int hello_version_sent;
370 * How often has the other peer (recently) violated the
371 * inbound traffic limit? Incremented by 10 per violation,
372 * decremented by 1 per non-violation (for each
375 unsigned int quota_violation_count;
378 * Have we seen an ACK from this neighbour in the past?
379 * (used to make up a fake ACK for clients connecting after
380 * the neighbour connected to us).
388 * Linked list of messages to be transmitted to
389 * the client. Each entry is followed by the
392 struct ClientMessageQueueEntry
395 * This is a linked list.
397 struct ClientMessageQueueEntry *next;
402 * Client connected to the transport service.
404 struct TransportClient
408 * This is a linked list.
410 struct TransportClient *next;
413 * Handle to the client.
415 struct GNUNET_SERVER_Client *client;
418 * Linked list of messages yet to be transmitted to
421 struct ClientMessageQueueEntry *message_queue_head;
424 * Tail of linked list of messages yet to be transmitted to the
427 struct ClientMessageQueueEntry *message_queue_tail;
430 * Is a call to "transmit_send_continuation" pending? If so, we
431 * must not free this struct (even if the corresponding client
432 * disconnects) and instead only remove it from the linked list and
433 * set the "client" field to NULL.
438 * Length of the list of messages pending for this client.
440 unsigned int message_count;
446 * Message used to ask a peer to validate receipt (to check an address
447 * from a HELLO). Followed by the address used. Note that the
448 * recipients response does not affirm that he has this address,
449 * only that he got the challenge message.
451 struct ValidationChallengeMessage
455 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
457 struct GNUNET_MessageHeader header;
460 * What are we signing and why?
462 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
465 * Random challenge number (in network byte order).
467 uint32_t challenge GNUNET_PACKED;
470 * Who is the intended recipient?
472 struct GNUNET_PeerIdentity target;
477 * Message used to validate a HELLO. If this was
478 * the right recipient, the response is a signature
479 * of the original validation request. The
480 * challenge is included in the confirmation to make
481 * matching of replies to requests possible.
483 struct ValidationChallengeResponse
487 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
489 struct GNUNET_MessageHeader header;
492 * Random challenge number (in network byte order).
494 uint32_t challenge GNUNET_PACKED;
497 * Who signed this message?
499 struct GNUNET_PeerIdentity sender;
504 struct GNUNET_CRYPTO_RsaSignature signature;
510 * For each HELLO, we may have to validate multiple addresses;
511 * each address gets its own request entry.
513 struct ValidationAddress
516 * This is a linked list.
518 struct ValidationAddress *next;
521 * Our challenge message. Points to after this
522 * struct, so this field should not be freed.
524 struct ValidationChallengeMessage *msg;
527 * Name of the transport.
529 char *transport_name;
532 * When should this validated address expire?
534 struct GNUNET_TIME_Absolute expiration;
537 * Length of the address we are validating.
542 * Set to GNUNET_YES if the challenge was met,
543 * GNUNET_SYSERR if we know it failed, GNUNET_NO
544 * if we are waiting on a response.
551 * Entry in linked list of all HELLOs awaiting validation.
553 struct ValidationList
557 * This is a linked list.
559 struct ValidationList *next;
562 * Linked list with one entry per address from the HELLO
563 * that needs to be validated.
565 struct ValidationAddress *addresses;
568 * The public key of the peer.
570 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
573 * When does this record time-out? (assuming the
574 * challenge goes unanswered)
576 struct GNUNET_TIME_Absolute timeout;
582 * HELLOs awaiting validation.
584 static struct ValidationList *pending_validations;
589 static struct GNUNET_HELLO_Message *our_hello;
592 * "version" of "our_hello". Used to see if a given
593 * neighbour has already been sent the latest version
594 * of our HELLO message.
596 static unsigned int our_hello_version;
601 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
606 static struct GNUNET_PeerIdentity my_identity;
611 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
616 struct GNUNET_SCHEDULER_Handle *sched;
621 struct GNUNET_CONFIGURATION_Handle *cfg;
624 * Linked list of all clients to this service.
626 static struct TransportClient *clients;
629 * All loaded plugins.
631 static struct TransportPlugin *plugins;
636 static struct GNUNET_SERVER_Handle *server;
639 * All known neighbours and their HELLOs.
641 static struct NeighbourList *neighbours;
644 * Default bandwidth quota for receiving for new peers in bytes/ms.
646 static uint32_t default_quota_in;
649 * Default bandwidth quota for sending for new peers in bytes/ms.
651 static uint32_t default_quota_out;
654 * Number of neighbours we'd like to have.
656 static uint32_t max_connect_per_transport;
660 * Find an entry in the neighbour list for a particular peer.
662 * @return NULL if not found.
664 static struct NeighbourList *
665 find_neighbour (const struct GNUNET_PeerIdentity *key)
667 struct NeighbourList *head = neighbours;
668 while ((head != NULL) &&
669 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
676 * Find an entry in the transport list for a particular transport.
678 * @return NULL if not found.
680 static struct TransportPlugin *
681 find_transport (const char *short_name)
683 struct TransportPlugin *head = plugins;
684 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
691 * Update the quota values for the given neighbour now.
694 update_quota (struct NeighbourList *n)
696 struct GNUNET_TIME_Relative delta;
700 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
701 if (delta.value < MIN_QUOTA_REFRESH_TIME)
702 return; /* not enough time passed for doing quota update */
703 allowed = delta.value * n->quota_in;
704 if (n->last_received < allowed)
706 remaining = allowed - n->last_received;
708 remaining /= n->quota_in;
711 if (remaining > MAX_BANDWIDTH_CARRY)
712 remaining = MAX_BANDWIDTH_CARRY;
713 n->last_received = 0;
714 n->last_quota_update = GNUNET_TIME_absolute_get ();
715 n->last_quota_update.value -= remaining;
716 if (n->quota_violation_count > 0)
717 n->quota_violation_count--;
721 n->last_received -= allowed;
722 n->last_quota_update = GNUNET_TIME_absolute_get ();
723 if (n->last_received > allowed)
725 /* more than twice the allowed rate! */
726 n->quota_violation_count += 10;
733 * Function called to notify a client about the socket
734 * being ready to queue more data. "buf" will be
735 * NULL and "size" zero if the socket was closed for
736 * writing in the meantime.
739 * @param size number of bytes available in buf
740 * @param buf where the callee should write the message
741 * @return number of bytes written to buf
744 transmit_to_client_callback (void *cls, size_t size, void *buf)
746 struct TransportClient *client = cls;
747 struct ClientMessageQueueEntry *q;
750 const struct GNUNET_MessageHeader *msg;
751 struct GNUNET_NETWORK_TransmitHandle *th;
756 /* fatal error with client, free message queue! */
757 while (NULL != (q = client->message_queue_head))
759 client->message_queue_head = q->next;
762 client->message_queue_tail = NULL;
763 client->message_count = 0;
768 while (NULL != (q = client->message_queue_head))
770 msg = (const struct GNUNET_MessageHeader *) &q[1];
771 msize = ntohs (msg->size);
772 if (msize + tsize > size)
774 client->message_queue_head = q->next;
776 client->message_queue_tail = NULL;
777 memcpy (&cbuf[tsize], msg, msize);
780 client->message_count--;
782 GNUNET_assert (tsize > 0);
785 th = GNUNET_SERVER_notify_transmit_ready (client->client,
787 GNUNET_TIME_UNIT_FOREVER_REL,
788 &transmit_to_client_callback,
790 GNUNET_assert (th != NULL);
797 * Send the specified message to the specified client. Since multiple
798 * messages may be pending for the same client at a time, this code
799 * makes sure that no message is lost.
801 * @param client client to transmit the message to
802 * @param msg the message to send
803 * @param may_drop can this message be dropped if the
804 * message queue for this client is getting far too large?
807 transmit_to_client (struct TransportClient *client,
808 const struct GNUNET_MessageHeader *msg, int may_drop)
810 struct ClientMessageQueueEntry *q;
812 struct GNUNET_NETWORK_TransmitHandle *th;
814 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
816 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
818 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
819 client->message_count, MAX_PENDING);
820 /* TODO: call to statistics... */
823 client->message_count++;
824 msize = ntohs (msg->size);
825 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
826 memcpy (&q[1], msg, msize);
827 /* append to message queue */
828 if (client->message_queue_tail == NULL)
830 client->message_queue_tail = q;
834 client->message_queue_tail->next = q;
835 client->message_queue_tail = q;
837 if (client->message_queue_head == NULL)
839 client->message_queue_head = q;
840 th = GNUNET_SERVER_notify_transmit_ready (client->client,
842 GNUNET_TIME_UNIT_FOREVER_REL,
843 &transmit_to_client_callback,
845 GNUNET_assert (th != NULL);
851 * Find alternative plugins for communication.
853 * @param neighbour for which neighbour should we try to find
857 try_alternative_plugins (struct NeighbourList *neighbour)
859 struct ReadyList *rl;
861 if ((neighbour->plugins != NULL) &&
862 (neighbour->retry_plugins_time.value >
863 GNUNET_TIME_absolute_get ().value))
864 return; /* don't try right now */
865 neighbour->retry_plugins_time
866 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
868 rl = neighbour->plugins;
871 if (rl->connect_attempts > 0)
872 rl->connect_attempts--; /* amnesty */
880 * Check the ready list for the given neighbour and
881 * if a plugin is ready for transmission (and if we
882 * have a message), do so!
884 * @param neighbour target peer for which to check the plugins
886 static void try_transmission_to_peer (struct NeighbourList *neighbour);
890 * Function called by the GNUNET_TRANSPORT_TransmitFunction
891 * upon "completion" of a send request. This tells the API
892 * that it is now legal to send another message to the given
895 * @param cls closure, identifies the entry on the
896 * message queue that was transmitted and the
897 * client responsible for queueing the message
898 * @param rl identifies plugin used for the transmission for
899 * this neighbour; needs to be re-enabled for
900 * future transmissions
901 * @param target the peer receiving the message
902 * @param result GNUNET_OK on success, if the transmission
903 * failed, we should not tell the client to transmit
907 transmit_send_continuation (void *cls,
908 struct ReadyList *rl,
909 const struct GNUNET_PeerIdentity *target,
912 struct MessageQueue *mq = cls;
913 struct SendOkMessage send_ok_msg;
914 struct NeighbourList *n;
916 GNUNET_assert (mq != NULL);
918 GNUNET_assert (n != NULL);
920 memcmp (&n->id, target,
921 sizeof (struct GNUNET_PeerIdentity)));
925 while ((rl != NULL) && (rl->plugin != mq->plugin))
927 GNUNET_assert (rl != NULL);
929 if (result == GNUNET_OK)
930 rl->timeout = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
932 rl->connected = GNUNET_NO;
933 if (!mq->internal_msg)
934 rl->transmit_ready = GNUNET_YES;
935 if (mq->client != NULL)
937 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
938 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
939 send_ok_msg.success = htonl (result);
940 send_ok_msg.peer = n->id;
941 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
943 GNUNET_free (mq->message);
945 /* one plugin just became ready again, try transmitting
946 another message (if available) */
947 try_transmission_to_peer (n);
954 * We could not use an existing (or validated) connection to
955 * talk to a peer. Try addresses that have not yet been
958 * @param n neighbour we want to communicate with
959 * @return plugin ready to talk, or NULL if none is available
961 static struct ReadyList *
962 try_unvalidated_addresses (struct NeighbourList *n)
964 struct ValidationList *vl;
965 struct ValidationAddress *va;
966 struct GNUNET_PeerIdentity id;
967 struct GNUNET_TIME_Absolute now;
970 struct ReadyList *rl;
971 struct TransportPlugin *plugin;
974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 "Trying to connect to `%4s' using unvalidated addresses\n",
976 GNUNET_i2s (&n->id));
978 /* NOTE: this function needs to not only identify the
979 plugin but also setup "plugin_handle", binding it to the
980 right address using the plugin's "send_to" API */
981 now = GNUNET_TIME_absolute_get ();
982 vl = pending_validations;
985 GNUNET_CRYPTO_hash (&vl->publicKey,
987 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
989 if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997 "No unvalidated address found for peer `%4s'\n",
998 GNUNET_i2s (&n->id));
1008 if (va->expiration.value > now.value)
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "All %u unvalidated addresses for peer have expired\n",
1021 total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
1022 for (va = vl->addresses; va != NULL; va = va->next)
1024 if (va->expiration.value <= now.value)
1032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1033 "Trying unvalidated address of `%s' transport\n",
1034 va->transport_name);
1036 plugin = find_transport (va->transport_name);
1042 rl = GNUNET_malloc (sizeof (struct ReadyList));
1043 rl->next = n->plugins;
1045 rl->plugin = plugin;
1046 rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
1050 GNUNET_TIME_UNIT_ZERO,
1051 &va->msg[1], va->addr_len);
1052 rl->transmit_ready = GNUNET_YES;
1060 * Check the ready list for the given neighbour and
1061 * if a plugin is ready for transmission (and if we
1062 * have a message), do so!
1065 try_transmission_to_peer (struct NeighbourList *neighbour)
1067 struct ReadyList *pos;
1068 struct GNUNET_TIME_Relative min_latency;
1069 struct ReadyList *rl;
1070 struct MessageQueue *mq;
1071 struct GNUNET_TIME_Absolute now;
1073 if (neighbour->messages == NULL)
1074 return; /* nothing to do */
1075 try_alternative_plugins (neighbour);
1076 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1078 mq = neighbour->messages;
1079 now = GNUNET_TIME_absolute_get ();
1080 pos = neighbour->plugins;
1083 /* set plugins that are inactive for a long time back to disconnected */
1084 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088 "Marking long-time inactive connection to `%4s' as down.\n",
1089 GNUNET_i2s (&neighbour->id));
1091 pos->connected = GNUNET_NO;
1093 if (((GNUNET_YES == pos->transmit_ready) ||
1094 (mq->internal_msg)) &&
1095 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1096 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1099 min_latency = pos->latency;
1104 rl = try_unvalidated_addresses (neighbour);
1108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109 "No plugin ready to transmit message\n");
1111 return; /* nobody ready */
1113 if (GNUNET_NO == rl->connected)
1115 rl->connect_attempts++;
1116 rl->connected = GNUNET_YES;
1118 neighbour->messages = mq->next;
1119 mq->plugin = rl->plugin;
1120 if (!mq->internal_msg)
1121 rl->transmit_ready = GNUNET_NO;
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1125 ntohs (mq->message->type),
1126 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
1129 = rl->plugin->api->send (rl->plugin->api->cls,
1134 IDLE_CONNECTION_TIMEOUT,
1135 &transmit_send_continuation, mq);
1140 * Send the specified message to the specified peer.
1142 * @param client source of the transmission request (can be NULL)
1143 * @param msg message to send
1144 * @param is_internal is this an internal message
1145 * @param neighbour handle to the neighbour for transmission
1148 transmit_to_peer (struct TransportClient *client,
1149 const struct GNUNET_MessageHeader *msg,
1150 int is_internal, struct NeighbourList *neighbour)
1152 struct MessageQueue *mq;
1153 struct MessageQueue *mqe;
1154 struct GNUNET_MessageHeader *m;
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 _("Sending message of type %u to peer `%4s'\n"),
1159 ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1163 /* check for duplicate submission */
1164 mq = neighbour->messages;
1167 if (mq->client == client)
1169 /* client transmitted to same peer twice
1170 before getting SendOk! */
1177 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1178 mq->client = client;
1179 m = GNUNET_malloc (ntohs (msg->size));
1180 memcpy (m, msg, ntohs (msg->size));
1182 mq->neighbour = neighbour;
1183 mq->internal_msg = is_internal;
1186 mqe = neighbour->messages;
1188 while (mqe->next != NULL)
1193 neighbour->messages = mq;
1194 try_transmission_to_peer (neighbour);
1204 struct GeneratorContext
1206 struct TransportPlugin *plug_pos;
1207 struct AddressList *addr_pos;
1208 struct GNUNET_TIME_Absolute expiration;
1213 address_generator (void *cls, size_t max, void *buf)
1215 struct GeneratorContext *gc = cls;
1218 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1220 gc->plug_pos = gc->plug_pos->next;
1221 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1223 if (NULL == gc->plug_pos)
1225 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1228 gc->addr_pos->addrlen, buf, max);
1229 gc->addr_pos = gc->addr_pos->next;
1235 * Construct our HELLO message from all of the addresses of
1236 * all of the transports.
1241 struct GNUNET_HELLO_Message *hello;
1242 struct TransportClient *cpos;
1243 struct NeighbourList *npos;
1244 struct GeneratorContext gc;
1247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1248 "Refreshing my HELLO\n");
1250 gc.plug_pos = plugins;
1251 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1252 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1253 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1255 while (cpos != NULL)
1257 transmit_to_client (cpos,
1258 (const struct GNUNET_MessageHeader *) hello,
1263 GNUNET_free_non_null (our_hello);
1265 our_hello_version++;
1267 while (npos != NULL)
1269 transmit_to_peer (NULL,
1270 (const struct GNUNET_MessageHeader *) our_hello,
1278 * Task used to clean up expired addresses for a plugin.
1280 * @param cls closure
1284 expire_address_task (void *cls,
1285 const struct GNUNET_SCHEDULER_TaskContext *tc);
1289 * Update the list of addresses for this plugin,
1290 * expiring those that are past their expiration date.
1292 * @param plugin addresses of which plugin should be recomputed?
1293 * @param fresh set to GNUNET_YES if a new address was added
1294 * and we need to regenerate the HELLO even if nobody
1298 update_addresses (struct TransportPlugin *plugin, int fresh)
1300 struct GNUNET_TIME_Relative min_remaining;
1301 struct GNUNET_TIME_Relative remaining;
1302 struct GNUNET_TIME_Absolute now;
1303 struct AddressList *pos;
1304 struct AddressList *prev;
1305 struct AddressList *next;
1308 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
1309 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1310 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1311 now = GNUNET_TIME_absolute_get ();
1312 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1313 expired = GNUNET_NO;
1315 pos = plugin->addresses;
1319 if (pos->expires.value < now.value)
1321 expired = GNUNET_YES;
1323 plugin->addresses = pos->next;
1325 prev->next = pos->next;
1330 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1331 if (remaining.value < min_remaining.value)
1332 min_remaining = remaining;
1338 if (expired || fresh)
1340 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1341 plugin->address_update_task
1342 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1344 GNUNET_SCHEDULER_PRIORITY_IDLE,
1345 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1347 &expire_address_task, plugin);
1353 * Task used to clean up expired addresses for a plugin.
1355 * @param cls closure
1359 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1361 struct TransportPlugin *plugin = cls;
1362 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1363 update_addresses (plugin, GNUNET_NO);
1368 * Function that must be called by each plugin to notify the
1369 * transport service about the addresses under which the transport
1370 * provided by the plugin can be reached.
1372 * @param cls closure
1373 * @param name name of the transport that generated the address
1374 * @param addr one of the addresses of the host, NULL for the last address
1375 * the specific address format depends on the transport
1376 * @param addrlen length of the address
1377 * @param expires when should this address automatically expire?
1380 plugin_env_notify_address (void *cls,
1384 struct GNUNET_TIME_Relative expires)
1386 struct TransportPlugin *p = cls;
1387 struct AddressList *al;
1388 struct GNUNET_TIME_Absolute abex;
1391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1392 "Plugin `%s' informs us about a new address\n", name);
1394 abex = GNUNET_TIME_relative_to_absolute (expires);
1395 GNUNET_assert (p == find_transport (name));
1400 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1402 if (al->expires.value < abex.value)
1408 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1410 al->next = p->addresses;
1413 al->addrlen = addrlen;
1414 memcpy (&al[1], addr, addrlen);
1415 update_addresses (p, GNUNET_YES);
1419 struct LookupHelloContext
1421 GNUNET_TRANSPORT_AddressCallback iterator;
1428 lookup_address_callback (void *cls,
1430 struct GNUNET_TIME_Absolute expiration,
1431 const void *addr, size_t addrlen)
1433 struct LookupHelloContext *lhc = cls;
1434 lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
1440 lookup_hello_callback (void *cls,
1441 const struct GNUNET_PeerIdentity *peer,
1442 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1444 struct LookupHelloContext *lhc = cls;
1448 lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
1454 GNUNET_HELLO_iterate_addresses (h,
1455 GNUNET_NO, &lookup_address_callback, lhc);
1460 * Function that allows a transport to query the known
1461 * network addresses for a given peer.
1463 * @param cls closure
1464 * @param timeout after how long should we time out?
1465 * @param target which peer are we looking for?
1466 * @param iter function to call for each known address
1467 * @param iter_cls closure for iter
1470 plugin_env_lookup_address (void *cls,
1471 struct GNUNET_TIME_Relative timeout,
1472 const struct GNUNET_PeerIdentity *target,
1473 GNUNET_TRANSPORT_AddressCallback iter,
1476 struct LookupHelloContext *lhc;
1478 lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
1479 lhc->iterator = iter;
1480 lhc->iterator_cls = iter_cls;
1481 GNUNET_PEERINFO_for_all (cfg,
1483 target, 0, timeout, &lookup_hello_callback, &lhc);
1488 * Notify all of our clients about a peer connecting.
1491 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1492 struct GNUNET_TIME_Relative latency)
1494 struct ConnectInfoMessage cim;
1495 struct TransportClient *cpos;
1498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1499 "Informing clients about peer `%4s' connecting to us\n",
1502 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1503 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1504 cim.quota_out = htonl (default_quota_out);
1505 cim.latency = GNUNET_TIME_relative_hton (latency);
1506 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1508 while (cpos != NULL)
1510 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1517 * Notify all of our clients about a peer disconnecting.
1520 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1522 struct DisconnectInfoMessage dim;
1523 struct TransportClient *cpos;
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 "Informing clients about peer `%4s' disconnecting\n",
1530 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1531 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1532 dim.reserved = htonl (0);
1533 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1535 while (cpos != NULL)
1537 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1544 * Copy any validated addresses to buf.
1546 * @return 0 once all addresses have been
1550 list_validated_addresses (void *cls, size_t max, void *buf)
1552 struct ValidationAddress **va = cls;
1555 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1559 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1561 &(*va)->msg[1], (*va)->addr_len, buf, max);
1568 * HELLO validation cleanup task.
1571 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1573 struct ValidationAddress *va;
1574 struct ValidationList *pos;
1575 struct ValidationList *prev;
1576 struct GNUNET_TIME_Absolute now;
1577 struct GNUNET_HELLO_Message *hello;
1578 struct GNUNET_PeerIdentity pid;
1581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1582 "HELLO validation cleanup background task running...\n");
1584 now = GNUNET_TIME_absolute_get ();
1586 pos = pending_validations;
1589 if (pos->timeout.value < now.value)
1592 pending_validations = pos->next;
1594 prev->next = pos->next;
1595 va = pos->addresses;
1596 hello = GNUNET_HELLO_create (&pos->publicKey,
1597 &list_validated_addresses, &va);
1598 GNUNET_CRYPTO_hash (&pos->publicKey,
1600 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1605 "HELLO", GNUNET_i2s (&pid));
1607 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1608 GNUNET_free (hello);
1609 while (NULL != (va = pos->addresses))
1611 pos->addresses = va->next;
1612 GNUNET_free (va->transport_name);
1617 pos = pending_validations;
1626 /* finally, reschedule cleanup if needed; list is
1627 ordered by timeout, so we need the last element... */
1628 pos = pending_validations;
1629 while ((pos != NULL) && (pos->next != NULL))
1632 GNUNET_SCHEDULER_add_delayed (sched,
1634 GNUNET_SCHEDULER_PRIORITY_IDLE,
1635 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1636 GNUNET_TIME_absolute_get_remaining
1637 (pos->timeout), &cleanup_validation, NULL);
1641 struct CheckHelloValidatedContext
1644 * Plugin for which we are validating.
1646 struct TransportPlugin *plugin;
1649 * Hello that we are validating.
1651 struct GNUNET_HELLO_Message *hello;
1654 * Validation list being build.
1656 struct ValidationList *e;
1661 * Append the given address to the list of entries
1662 * that need to be validated.
1665 run_validation (void *cls,
1667 struct GNUNET_TIME_Absolute expiration,
1668 const void *addr, size_t addrlen)
1670 struct ValidationList *e = cls;
1671 struct TransportPlugin *tp;
1672 struct ValidationAddress *va;
1673 struct ValidationChallengeMessage *vcm;
1675 tp = find_transport (tname);
1678 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1679 GNUNET_ERROR_TYPE_BULK,
1681 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1685 va = GNUNET_malloc (sizeof (struct ValidationAddress) +
1686 sizeof (struct ValidationChallengeMessage) + addrlen);
1687 va->next = e->addresses;
1689 vcm = (struct ValidationChallengeMessage *) &va[1];
1691 va->transport_name = GNUNET_strdup (tname);
1692 va->addr_len = addrlen;
1694 htons (sizeof (struct ValidationChallengeMessage) + addrlen);
1695 vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1697 htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
1698 sizeof (struct GNUNET_MessageHeader));
1699 vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
1700 vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1702 /* Note: vcm->target is set in check_hello_validated */
1703 memcpy (&vcm[1], addr, addrlen);
1709 * Check if addresses in validated hello "h" overlap with
1710 * those in "chvc->hello" and update "chvc->hello" accordingly,
1711 * removing those addresses that have already been validated.
1714 check_hello_validated (void *cls,
1715 const struct GNUNET_PeerIdentity *peer,
1716 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1718 struct CheckHelloValidatedContext *chvc = cls;
1719 struct ValidationAddress *va;
1720 struct TransportPlugin *tp;
1723 first_call = GNUNET_NO;
1724 if (chvc->e == NULL)
1726 first_call = GNUNET_YES;
1727 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1728 GNUNET_assert (GNUNET_OK ==
1729 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1730 &chvc->e->publicKey));
1732 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1733 chvc->e->next = pending_validations;
1734 pending_validations = chvc->e;
1738 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1740 GNUNET_TIME_absolute_get (),
1741 &run_validation, chvc->e);
1743 else if (GNUNET_YES == first_call)
1745 /* no existing HELLO, all addresses are new */
1746 GNUNET_HELLO_iterate_addresses (chvc->hello,
1747 GNUNET_NO, &run_validation, chvc->e);
1750 return; /* wait for next call */
1751 /* finally, transmit validation attempts */
1752 va = chvc->e->addresses;
1755 GNUNET_CRYPTO_hash (&chvc->e->publicKey,
1757 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1758 &va->msg->target.hashPubKey);
1760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1761 "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
1763 "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
1765 tp = find_transport (va->transport_name);
1766 GNUNET_assert (tp != NULL);
1768 tp->api->send_to (tp->api->cls,
1770 (const struct GNUNET_MessageHeader *) our_hello,
1772 HELLO_VERIFICATION_TIMEOUT,
1773 &va->msg[1], va->addr_len))
1774 va->ok = GNUNET_SYSERR;
1777 if (chvc->e->next == NULL)
1778 GNUNET_SCHEDULER_add_delayed (sched,
1780 GNUNET_SCHEDULER_PRIORITY_IDLE,
1781 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1782 GNUNET_TIME_absolute_get_remaining
1783 (chvc->e->timeout), &cleanup_validation,
1790 * Process HELLO-message.
1792 * @param plugin transport involved, may be NULL
1793 * @param message the actual message
1794 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1797 process_hello (struct TransportPlugin *plugin,
1798 const struct GNUNET_MessageHeader *message)
1800 struct ValidationList *e;
1802 struct GNUNET_PeerIdentity target;
1803 const struct GNUNET_HELLO_Message *hello;
1804 struct CheckHelloValidatedContext *chvc;
1805 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1807 hsize = ntohs (message->size);
1808 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1809 (hsize < sizeof (struct GNUNET_MessageHeader)))
1812 return GNUNET_SYSERR;
1814 /* first, check if load is too high */
1815 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1817 /* TODO: call to stats? */
1820 hello = (const struct GNUNET_HELLO_Message *) message;
1821 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1823 GNUNET_break_op (0);
1824 return GNUNET_SYSERR;
1826 GNUNET_CRYPTO_hash (&publicKey,
1827 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1828 &target.hashPubKey);
1830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831 "Processing `%s' message for `%4s'\n",
1832 "HELLO", GNUNET_i2s (&target));
1834 /* check if a HELLO for this peer is already on the validation list */
1835 e = pending_validations;
1838 if (0 == memcmp (&e->publicKey,
1841 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1843 /* TODO: call to stats? */
1848 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1849 chvc->plugin = plugin;
1850 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1851 memcpy (chvc->hello, hello, hsize);
1852 /* finally, check if HELLO was previously validated
1853 (continuation will then schedule actual validation) */
1854 GNUNET_PEERINFO_for_all (cfg,
1858 HELLO_VERIFICATION_TIMEOUT,
1859 &check_hello_validated, chvc);
1865 * Handle PING-message. If the plugin that gave us the message is
1866 * able to queue the PONG immediately, we only queue one PONG.
1867 * Otherwise we send at most TWO PONG messages, one via an unconfirmed
1868 * transport and one via a confirmed transport. Both addresses are
1869 * selected randomly among those available.
1871 * @param plugin plugin that gave us the message
1872 * @param sender claimed sender of the PING
1873 * @param plugin_context context that might be used to send response
1874 * @param message the actual message
1877 process_ping (struct TransportPlugin *plugin,
1878 const struct GNUNET_PeerIdentity *sender,
1879 void *plugin_context,
1880 const struct GNUNET_MessageHeader *message)
1882 const struct ValidationChallengeMessage *vcm;
1883 struct ValidationChallengeResponse vcr;
1885 struct NeighbourList *n;
1888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1889 "Processing PING\n");
1891 msize = ntohs (message->size);
1892 if (msize < sizeof (struct ValidationChallengeMessage))
1894 GNUNET_break_op (0);
1897 vcm = (const struct ValidationChallengeMessage *) message;
1898 if (0 != memcmp (&vcm->target,
1899 &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1901 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1902 _("Received `%s' message not destined for me!\n"), "PING");
1903 /* TODO: call statistics */
1906 if ((ntohl (vcm->purpose.size) !=
1907 msize - sizeof (struct GNUNET_MessageHeader))
1908 || (ntohl (vcm->purpose.purpose) !=
1909 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
1911 GNUNET_break_op (0);
1914 msize -= sizeof (struct ValidationChallengeMessage);
1916 plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
1918 GNUNET_break_op (0);
1921 vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
1922 vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1923 vcr.challenge = vcm->challenge;
1924 vcr.sender = my_identity;
1925 GNUNET_assert (GNUNET_OK ==
1926 GNUNET_CRYPTO_rsa_sign (my_private_key,
1927 &vcm->purpose, &vcr.signature));
1929 GNUNET_assert (GNUNET_OK ==
1930 GNUNET_CRYPTO_rsa_verify
1931 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
1932 &vcr.signature, &my_public_key));
1935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1936 "Trying to transmit PONG using inbound connection\n");
1938 n = find_neighbour (sender);
1944 transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n);
1949 * Handle PONG-message.
1951 * @param message the actual message
1954 process_pong (struct TransportPlugin *plugin,
1955 const struct GNUNET_MessageHeader *message)
1957 const struct ValidationChallengeResponse *vcr;
1958 struct ValidationList *pos;
1959 struct GNUNET_PeerIdentity peer;
1960 struct ValidationAddress *va;
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1966 "Processing PONG\n");
1968 vcr = (const struct ValidationChallengeResponse *) message;
1969 pos = pending_validations;
1972 GNUNET_CRYPTO_hash (&pos->publicKey,
1974 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1977 memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
1983 /* TODO: call statistics (unmatched PONG) */
1984 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1986 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1990 all_done = GNUNET_YES;
1991 matched = GNUNET_NO;
1992 va = pos->addresses;
1995 if (va->msg->challenge == vcr->challenge)
1998 GNUNET_CRYPTO_rsa_verify
1999 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
2000 &vcr->signature, &pos->publicKey))
2002 /* this could rarely happen if we used the same
2003 challenge number for the peer for two different
2004 transports / addresses, but the likelihood is
2006 GNUNET_break_op (0);
2011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2012 "Confirmed validity of peer address.\n");
2014 va->ok = GNUNET_YES;
2016 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2017 matched = GNUNET_YES;
2020 if (va->ok != GNUNET_YES)
2021 all_done = GNUNET_NO;
2024 if (GNUNET_NO == matched)
2026 /* TODO: call statistics (unmatched PONG) */
2027 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2029 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
2032 if (GNUNET_YES == all_done)
2034 pos->timeout.value = 0;
2035 GNUNET_SCHEDULER_add_delayed (sched,
2037 GNUNET_SCHEDULER_PRIORITY_IDLE,
2038 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2039 GNUNET_TIME_UNIT_ZERO,
2040 &cleanup_validation, NULL);
2046 * The peer specified by the given neighbour has timed-out. Update
2047 * our state and do the necessary notifications. Also notifies
2048 * our clients that the neighbour is now officially gone.
2050 * @param n the neighbour list entry for the peer
2053 disconnect_neighbour (struct NeighbourList *n)
2055 struct ReadyList *rpos;
2056 struct NeighbourList *npos;
2057 struct NeighbourList *nprev;
2058 struct MessageQueue *mq;
2061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2062 "Disconnecting from neighbour\n");
2064 /* remove n from neighbours list */
2067 while ((npos != NULL) && (npos != n))
2072 GNUNET_assert (npos != NULL);
2074 neighbours = n->next;
2076 nprev->next = n->next;
2078 /* notify all clients about disconnect */
2079 notify_clients_disconnect (&n->id);
2081 /* clean up all plugins, cancel connections & pending transmissions */
2082 while (NULL != (rpos = n->plugins))
2084 n->plugins = rpos->next;
2085 GNUNET_assert (rpos->neighbour == n);
2086 rpos->plugin->api->cancel (rpos->plugin->api->cls,
2087 rpos->plugin_handle, rpos, &n->id);
2091 /* free all messages on the queue */
2092 while (NULL != (mq = n->messages))
2094 n->messages = mq->next;
2095 GNUNET_assert (mq->neighbour == n);
2099 /* finally, free n itself */
2105 * Add an entry for each of our transport plugins
2106 * (that are able to send) to the list of plugins
2107 * for this neighbour.
2109 * @param neighbour to initialize
2112 add_plugins (struct NeighbourList *neighbour)
2114 struct TransportPlugin *tp;
2115 struct ReadyList *rl;
2117 neighbour->retry_plugins_time
2118 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2122 if (tp->api->send != NULL)
2124 rl = GNUNET_malloc (sizeof (struct ReadyList));
2125 rl->next = neighbour->plugins;
2126 neighbour->plugins = rl;
2128 rl->neighbour = neighbour;
2129 rl->transmit_ready = GNUNET_YES;
2137 neighbour_timeout_task (void *cls,
2138 const struct GNUNET_SCHEDULER_TaskContext *tc)
2140 struct NeighbourList *n = cls;
2143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2144 "Neighbour has timed out!\n");
2146 n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
2147 disconnect_neighbour (n);
2153 * Create a fresh entry in our neighbour list for the given peer.
2154 * Will try to transmit our current HELLO to the new neighbour. Also
2155 * notifies our clients about the new "connection".
2157 * @param peer the peer for which we create the entry
2158 * @return the new neighbour list entry
2160 static struct NeighbourList *
2161 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2163 struct NeighbourList *n;
2166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2167 "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
2170 GNUNET_assert (our_hello != NULL);
2171 n = GNUNET_malloc (sizeof (struct NeighbourList));
2172 n->next = neighbours;
2175 n->last_quota_update = GNUNET_TIME_absolute_get ();
2177 GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2178 n->quota_in = default_quota_in;
2180 n->hello_version_sent = our_hello_version;
2181 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2183 GNUNET_SCHEDULER_PRIORITY_IDLE,
2184 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2185 IDLE_CONNECTION_TIMEOUT,
2186 &neighbour_timeout_task, n);
2187 transmit_to_peer (NULL,
2188 (const struct GNUNET_MessageHeader *) our_hello,
2190 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2196 * Function called by the plugin for each received message.
2197 * Update data volumes, possibly notify plugins about
2198 * reducing the rate at which they read from the socket
2199 * and generally forward to our receive callback.
2201 * @param plugin_context value to pass to this plugin
2202 * to respond to the given peer (use is optional,
2203 * but may speed up processing)
2204 * @param service_context value passed to the transport-service
2205 * to identify the neighbour; will be NULL on the first
2206 * call for a given peer
2207 * @param latency estimated latency for communicating with the
2209 * @param peer (claimed) identity of the other peer
2210 * @param message the message, NULL if peer was disconnected
2211 * @return the new service_context that the plugin should use
2212 * for future receive calls for messages from this
2215 static struct ReadyList *
2216 plugin_env_receive (void *cls,
2217 void *plugin_context,
2218 struct ReadyList *service_context,
2219 struct GNUNET_TIME_Relative latency,
2220 const struct GNUNET_PeerIdentity *peer,
2221 const struct GNUNET_MessageHeader *message)
2223 const struct GNUNET_MessageHeader ack = {
2224 htons (sizeof (struct GNUNET_MessageHeader)),
2225 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2227 struct TransportPlugin *plugin = cls;
2228 struct TransportClient *cpos;
2229 struct InboundMessage *im;
2231 struct NeighbourList *n;
2233 if (service_context != NULL)
2235 n = service_context->neighbour;
2236 GNUNET_assert (n != NULL);
2240 n = find_neighbour (peer);
2243 if (message == NULL)
2244 return NULL; /* disconnect of peer already marked down */
2245 n = setup_new_neighbour (peer);
2247 service_context = n->plugins;
2248 while ((service_context != NULL) && (plugin != service_context->plugin))
2249 service_context = service_context->next;
2250 GNUNET_assert ((plugin->api->send == NULL) ||
2251 (service_context != NULL));
2253 if (message == NULL)
2255 if ((service_context != NULL) &&
2256 (service_context->plugin_handle == plugin_context))
2258 service_context->connected = GNUNET_NO;
2259 service_context->plugin_handle = NULL;
2261 /* TODO: call stats */
2265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2266 "Processing message of type `%u' received by plugin...\n",
2267 ntohs (message->type));
2269 if (service_context != NULL)
2271 if (service_context->connected == GNUNET_NO)
2273 service_context->connected = GNUNET_YES;
2274 service_context->transmit_ready = GNUNET_YES;
2275 service_context->connect_attempts++;
2277 service_context->timeout
2278 = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2279 service_context->plugin_handle = plugin_context;
2280 service_context->latency = latency;
2282 /* update traffic received amount ... */
2283 msize = ntohs (message->size);
2284 n->last_received += msize;
2285 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2287 GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2289 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
2290 GNUNET_SCHEDULER_PRIORITY_IDLE,
2291 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2292 IDLE_CONNECTION_TIMEOUT,
2293 &neighbour_timeout_task, n);
2295 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2297 /* dropping message due to frequent inbound volume violations! */
2298 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2299 GNUNET_ERROR_TYPE_BULK,
2301 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2302 /* TODO: call stats */
2303 GNUNET_assert (NULL != service_context->neighbour);
2304 return service_context;
2306 switch (ntohs (message->type))
2308 case GNUNET_MESSAGE_TYPE_HELLO:
2310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2311 "Receiving `%s' message from other peer.\n", "HELLO");
2313 process_hello (plugin, message);
2315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2316 "Sending `%s' message to connecting peer.\n", "ACK");
2318 transmit_to_peer (NULL, &ack, GNUNET_YES, n);
2320 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2321 process_ping (plugin, peer, plugin_context, message);
2323 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2324 process_pong (plugin, message);
2326 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2327 n->saw_ack = GNUNET_YES;
2328 /* intentional fall-through! */
2331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2332 "Received message of type %u from other peer, sending to all clients.\n",
2333 ntohs (message->type));
2335 /* transmit message to all clients */
2336 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2337 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2338 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2339 im->latency = GNUNET_TIME_relative_hton (latency);
2341 memcpy (&im[1], message, msize);
2344 while (cpos != NULL)
2346 transmit_to_client (cpos, &im->header, GNUNET_YES);
2351 GNUNET_assert (NULL != service_context->neighbour);
2352 return service_context;
2357 * Handle START-message. This is the first message sent to us
2358 * by any client which causes us to add it to our list.
2360 * @param cls closure (always NULL)
2361 * @param client identification of the client
2362 * @param message the actual message
2365 handle_start (void *cls,
2366 struct GNUNET_SERVER_Client *client,
2367 const struct GNUNET_MessageHeader *message)
2369 struct TransportClient *c;
2370 struct ConnectInfoMessage cim;
2371 struct NeighbourList *n;
2372 struct InboundMessage *im;
2373 struct GNUNET_MessageHeader *ack;
2376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2377 "Received `%s' request from client\n", "START");
2382 if (c->client == client)
2384 /* client already on our list! */
2386 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2391 c = GNUNET_malloc (sizeof (struct TransportClient));
2395 if (our_hello != NULL)
2398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399 "Sending our own HELLO to new client\n");
2401 transmit_to_client (c,
2402 (const struct GNUNET_MessageHeader *) our_hello,
2404 /* tell new client about all existing connections */
2405 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2406 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2407 cim.quota_out = htonl (default_quota_out);
2408 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2409 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2410 sizeof (struct GNUNET_MessageHeader));
2411 im->header.size = htons (sizeof (struct InboundMessage) +
2412 sizeof (struct GNUNET_MessageHeader));
2413 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2414 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2415 ack = (struct GNUNET_MessageHeader *) &im[1];
2416 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2417 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2418 for (n = neighbours; n != NULL; n = n->next)
2421 transmit_to_client (c, &cim.header, GNUNET_NO);
2425 transmit_to_client (c, &im->header, GNUNET_NO);
2430 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2435 * Handle HELLO-message.
2437 * @param cls closure (always NULL)
2438 * @param client identification of the client
2439 * @param message the actual message
2442 handle_hello (void *cls,
2443 struct GNUNET_SERVER_Client *client,
2444 const struct GNUNET_MessageHeader *message)
2449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2450 "Received `%s' request from client\n", "HELLO");
2452 ret = process_hello (NULL, message);
2453 GNUNET_SERVER_receive_done (client, ret);
2458 * Handle SEND-message.
2460 * @param cls closure (always NULL)
2461 * @param client identification of the client
2462 * @param message the actual message
2465 handle_send (void *cls,
2466 struct GNUNET_SERVER_Client *client,
2467 const struct GNUNET_MessageHeader *message)
2469 struct TransportClient *tc;
2470 struct NeighbourList *n;
2471 const struct OutboundMessage *obm;
2472 const struct GNUNET_MessageHeader *obmm;
2476 size = ntohs (message->size);
2478 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2481 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2484 obm = (const struct OutboundMessage *) message;
2486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2487 "Received `%s' request from client with target `%4s'\n",
2488 "SEND", GNUNET_i2s (&obm->peer));
2490 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2491 msize = ntohs (obmm->size);
2492 if (size != msize + sizeof (struct OutboundMessage))
2495 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2498 n = find_neighbour (&obm->peer);
2500 n = setup_new_neighbour (&obm->peer);
2502 while ((tc != NULL) && (tc->client != client))
2506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2507 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2509 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2511 transmit_to_peer (tc, obmm, GNUNET_NO, n);
2512 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2517 * Handle SET_QUOTA-message.
2519 * @param cls closure (always NULL)
2520 * @param client identification of the client
2521 * @param message the actual message
2524 handle_set_quota (void *cls,
2525 struct GNUNET_SERVER_Client *client,
2526 const struct GNUNET_MessageHeader *message)
2528 const struct QuotaSetMessage *qsm =
2529 (const struct QuotaSetMessage *) message;
2530 struct NeighbourList *n;
2531 struct TransportPlugin *p;
2532 struct ReadyList *rl;
2535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2536 "Received `%s' request from client for peer `%4s'\n",
2537 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2539 n = find_neighbour (&qsm->peer);
2542 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2546 if (n->quota_in < ntohl (qsm->quota_in))
2547 n->last_quota_update = GNUNET_TIME_absolute_get ();
2548 n->quota_in = ntohl (qsm->quota_in);
2553 p->api->set_receive_quota (p->api->cls,
2554 &qsm->peer, ntohl (qsm->quota_in));
2557 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2562 * Handle TRY_CONNECT-message.
2564 * @param cls closure (always NULL)
2565 * @param client identification of the client
2566 * @param message the actual message
2569 handle_try_connect (void *cls,
2570 struct GNUNET_SERVER_Client *client,
2571 const struct GNUNET_MessageHeader *message)
2573 const struct TryConnectMessage *tcm;
2575 tcm = (const struct TryConnectMessage *) message;
2577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2578 "Received `%s' request from client asking to connect to `%4s'\n",
2579 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2581 if (NULL == find_neighbour (&tcm->peer))
2582 setup_new_neighbour (&tcm->peer);
2583 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2588 * List of handlers for the messages understood by this
2591 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2592 {&handle_start, NULL,
2593 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2594 {&handle_hello, NULL,
2595 GNUNET_MESSAGE_TYPE_HELLO, 0},
2596 {&handle_send, NULL,
2597 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2598 {&handle_set_quota, NULL,
2599 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2600 {&handle_try_connect, NULL,
2601 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2602 sizeof (struct TryConnectMessage)},
2608 * Setup the environment for this plugin.
2611 create_environment (struct TransportPlugin *plug)
2613 plug->env.cfg = cfg;
2614 plug->env.sched = sched;
2615 plug->env.my_public_key = &my_public_key;
2616 plug->env.cls = plug;
2617 plug->env.receive = &plugin_env_receive;
2618 plug->env.lookup = &plugin_env_lookup_address;
2619 plug->env.notify_address = &plugin_env_notify_address;
2620 plug->env.default_quota_in = default_quota_in;
2621 plug->env.max_connections = max_connect_per_transport;
2626 * Start the specified transport (load the plugin).
2629 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2631 struct TransportPlugin *plug;
2634 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2635 _("Loading `%s' transport plugin\n"), name);
2636 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2637 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2638 create_environment (plug);
2639 plug->short_name = GNUNET_strdup (name);
2640 plug->lib_name = libname;
2641 plug->next = plugins;
2643 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2644 if (plug->api == NULL)
2646 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2647 _("Failed to load transport plugin for `%s'\n"), name);
2648 GNUNET_free (plug->short_name);
2649 plugins = plug->next;
2650 GNUNET_free (libname);
2657 * Called whenever a client is disconnected. Frees our
2658 * resources associated with that client.
2660 * @param cls closure
2661 * @param client identification of the client
2664 client_disconnect_notification (void *cls,
2665 struct GNUNET_SERVER_Client *client)
2667 struct TransportClient *pos;
2668 struct TransportClient *prev;
2669 struct ClientMessageQueueEntry *mqe;
2672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2673 "Client disconnected, cleaning up.\n");
2677 while ((pos != NULL) && (pos->client != client))
2684 while (NULL != (mqe = pos->message_queue_head))
2686 pos->message_queue_head = mqe->next;
2689 pos->message_queue_head = NULL;
2691 clients = pos->next;
2693 prev->next = pos->next;
2694 if (GNUNET_YES == pos->tcs_pending)
2704 * Initiate transport service.
2706 * @param cls closure
2707 * @param s scheduler to use
2708 * @param serv the initialized server
2709 * @param c configuration to use
2713 struct GNUNET_SCHEDULER_Handle *s,
2714 struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
2719 unsigned long long qin;
2720 unsigned long long qout;
2721 unsigned long long tneigh;
2726 /* parse configuration */
2728 GNUNET_CONFIGURATION_get_value_number (c,
2733 GNUNET_CONFIGURATION_get_value_number (c,
2735 "DEFAULT_QUOTA_OUT",
2738 GNUNET_CONFIGURATION_get_value_number (c,
2743 GNUNET_CONFIGURATION_get_value_filename (c,
2745 "HOSTKEY", &keyfile)))
2747 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2749 ("Transport service is lacking key configuration settings. Exiting.\n"));
2750 GNUNET_SCHEDULER_shutdown (s);
2753 max_connect_per_transport = (uint32_t) tneigh;
2754 default_quota_in = (uint32_t) qin;
2755 default_quota_out = (uint32_t) qout;
2756 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2757 GNUNET_free (keyfile);
2758 if (my_private_key == NULL)
2760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2762 ("Transport service could not access hostkey. Exiting.\n"));
2763 GNUNET_SCHEDULER_shutdown (s);
2766 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2767 GNUNET_CRYPTO_hash (&my_public_key,
2768 sizeof (my_public_key), &my_identity.hashPubKey);
2769 /* setup notification */
2771 GNUNET_SERVER_disconnect_notify (server,
2772 &client_disconnect_notification, NULL);
2773 /* load plugins... */
2776 GNUNET_CONFIGURATION_get_value_string (c,
2777 "TRANSPORT", "PLUGINS", &plugs))
2779 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2780 _("Starting transport plugins `%s'\n"), plugs);
2781 pos = strtok (plugs, " ");
2784 start_transport (server, pos);
2786 pos = strtok (NULL, " ");
2788 GNUNET_free (plugs);
2792 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2793 /* process client requests */
2794 GNUNET_SERVER_add_handlers (server, handlers);
2799 * Function called when the service shuts
2800 * down. Unloads our plugins.
2802 * @param cls closure
2803 * @param cfg configuration to use
2806 unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
2808 struct TransportPlugin *plug;
2809 struct AddressList *al;
2812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2813 "Transport service is unloading plugins...\n");
2815 while (NULL != (plug = plugins))
2817 plugins = plug->next;
2818 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2819 GNUNET_free (plug->lib_name);
2820 GNUNET_free (plug->short_name);
2821 while (NULL != (al = plug->addresses))
2823 plug->addresses = al->next;
2828 if (my_private_key != NULL)
2829 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2834 * The main function for the transport service.
2836 * @param argc number of arguments from the command line
2837 * @param argv command line arguments
2838 * @return 0 ok, 1 on error
2841 main (int argc, char *const *argv)
2843 return (GNUNET_OK ==
2844 GNUNET_SERVICE_run (argc,
2847 &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
2850 /* end of gnunet-service-transport.c */