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?
71 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
74 * How often do we re-add (cheaper) plugins to our list of plugins
75 * to try for a given connected peer?
77 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
80 * After how long do we expire an address in a HELLO
81 * that we just validated? This value is also used
82 * for our own addresses when we create a HELLO.
84 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
88 * Entry in linked list of network addresses.
93 * This is a linked list.
95 struct AddressList *next;
98 * The address, actually a pointer to the end
99 * of this struct. Do not free!
104 * How long until we auto-expire this address (unless it is
105 * re-confirmed by the transport)?
107 struct GNUNET_TIME_Absolute expires;
118 * Entry in linked list of all of our plugins.
120 struct TransportPlugin
124 * This is a linked list.
126 struct TransportPlugin *next;
129 * API of the transport as returned by the plugin's
130 * initialization function.
132 struct GNUNET_TRANSPORT_PluginFunctions *api;
135 * Short name for the plugin (i.e. "tcp").
140 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
145 * List of our known addresses for this transport.
147 struct AddressList *addresses;
150 * Environment this transport service is using
153 struct GNUNET_TRANSPORT_PluginEnvironment env;
156 * ID of task that is used to clean up expired addresses.
158 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
162 * Set to GNUNET_YES if we need to scrap the existing
163 * list of "addresses" and start fresh when we receive
164 * the next address update from a transport. Set to
165 * GNUNET_NO if we should just add the new address
166 * to the list and wait for the commit call.
171 struct NeighbourList;
174 * For each neighbour we keep a list of messages
175 * that we still want to transmit to the neighbour.
181 * This is a linked list.
183 struct MessageQueue *next;
186 * The message we want to transmit.
188 struct GNUNET_MessageHeader *message;
191 * Client responsible for queueing the message;
192 * used to check that a client has not two messages
193 * pending for the same target. Can be NULL.
195 struct TransportClient *client;
198 * Neighbour this entry belongs to.
200 struct NeighbourList *neighbour;
203 * Plugin that we used for the transmission.
204 * NULL until we scheduled a transmission.
206 struct TransportPlugin *plugin;
209 * Internal message of the transport system that should not be
210 * included in the usual SEND-SEND_OK transmission confirmation
211 * traffic management scheme. Typically, "internal_msg" will
212 * be set whenever "client" is NULL (but it is not strictly
221 * For a given Neighbour, which plugins are available
222 * to talk to this peer and what are their costs?
228 * This is a linked list.
230 struct ReadyList *next;
233 * Which of our transport plugins does this entry
236 struct TransportPlugin *plugin;
239 * Neighbour this entry belongs to.
241 struct NeighbourList *neighbour;
244 * Opaque handle (specific to the plugin) for the
245 * connection to our target; can be NULL.
250 * What was the last latency observed for this plugin
251 * and peer? Invalid if connected is GNUNET_NO.
253 struct GNUNET_TIME_Relative latency;
256 * If we did not successfully transmit a message to the
257 * given peer via this connection during the specified
258 * time, we should consider the connection to be dead.
259 * This is used in the case that a TCP transport simply
260 * stalls writing to the stream but does not formerly
261 * get a signal that the other peer died.
263 struct GNUNET_TIME_Absolute timeout;
266 * Is this plugin currently connected? The first time
267 * we transmit or send data to a peer via a particular
268 * plugin, we set this to GNUNET_YES. If we later get
269 * an error (disconnect notification or transmission
270 * failure), we set it back to GNUNET_NO. Each time the
271 * value is set to GNUNET_YES, we increment the
272 * "connect_attempts" counter. If that one reaches a
273 * particular threshold, we consider the plugin to not
274 * be working properly at this time for the given peer
275 * and remove it from the eligible list.
280 * How often have we tried to connect using this plugin?
282 unsigned int connect_attempts;
285 * Is this plugin ready to transmit to the specific
286 * target? GNUNET_NO if not. Initially, all plugins
287 * are marked ready. If a transmission is in progress,
288 * "transmit_ready" is set to GNUNET_NO.
296 * Entry in linked list of all of our current neighbours.
302 * This is a linked list.
304 struct NeighbourList *next;
307 * Which of our transports is connected to this peer
308 * and what is their status?
310 struct ReadyList *plugins;
313 * List of messages we would like to send to this peer;
314 * must contain at most one message per client.
316 struct MessageQueue *messages;
319 * Identity of this neighbour.
321 struct GNUNET_PeerIdentity id;
324 * ID of task scheduled to run when this peer is about to
325 * time out (will free resources associated with the peer).
327 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
330 * How long until we should consider this peer dead
331 * (if we don't receive another message in the
334 struct GNUNET_TIME_Absolute peer_timeout;
337 * At what time did we reset last_received last?
339 struct GNUNET_TIME_Absolute last_quota_update;
342 * At what time should we try to again add plugins to
345 struct GNUNET_TIME_Absolute retry_plugins_time;
348 * How many bytes have we received since the "last_quota_update"
351 uint64_t last_received;
354 * Global quota for inbound traffic for the neighbour in bytes/ms.
359 * What is the latest version of our HELLO that we have
360 * sent to this neighbour?
362 unsigned int hello_version_sent;
365 * How often has the other peer (recently) violated the
366 * inbound traffic limit? Incremented by 10 per violation,
367 * decremented by 1 per non-violation (for each
370 unsigned int quota_violation_count;
373 * Have we seen an ACK from this neighbour in the past?
374 * (used to make up a fake ACK for clients connecting after
375 * the neighbour connected to us).
383 * Linked list of messages to be transmitted to
384 * the client. Each entry is followed by the
387 struct ClientMessageQueueEntry
390 * This is a linked list.
392 struct ClientMessageQueueEntry *next;
397 * Client connected to the transport service.
399 struct TransportClient
403 * This is a linked list.
405 struct TransportClient *next;
408 * Handle to the client.
410 struct GNUNET_SERVER_Client *client;
413 * Linked list of messages yet to be transmitted to
416 struct ClientMessageQueueEntry *message_queue_head;
419 * Tail of linked list of messages yet to be transmitted to the
422 struct ClientMessageQueueEntry *message_queue_tail;
425 * Is a call to "transmit_send_continuation" pending? If so, we
426 * must not free this struct (even if the corresponding client
427 * disconnects) and instead only remove it from the linked list and
428 * set the "client" field to NULL.
433 * Length of the list of messages pending for this client.
435 unsigned int message_count;
441 * Message used to ask a peer to validate receipt (to check an address
442 * from a HELLO). Followed by the address used. Note that the
443 * recipients response does not affirm that he has this address,
444 * only that he got the challenge message.
446 struct ValidationChallengeMessage
450 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
452 struct GNUNET_MessageHeader header;
455 * What are we signing and why?
457 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
460 * Random challenge number (in network byte order).
462 uint32_t challenge GNUNET_PACKED;
465 * Who is the intended recipient?
467 struct GNUNET_PeerIdentity target;
472 * Message used to validate a HELLO. If this was
473 * the right recipient, the response is a signature
474 * of the original validation request. The
475 * challenge is included in the confirmation to make
476 * matching of replies to requests possible.
478 struct ValidationChallengeResponse
482 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
484 struct GNUNET_MessageHeader header;
487 * Random challenge number (in network byte order).
489 uint32_t challenge GNUNET_PACKED;
492 * Who signed this message?
494 struct GNUNET_PeerIdentity sender;
499 struct GNUNET_CRYPTO_RsaSignature signature;
505 * For each HELLO, we may have to validate multiple addresses;
506 * each address gets its own request entry.
508 struct ValidationAddress
511 * This is a linked list.
513 struct ValidationAddress *next;
516 * Our challenge message. Points to after this
517 * struct, so this field should not be freed.
519 struct ValidationChallengeMessage *msg;
522 * Name of the transport.
524 char *transport_name;
527 * When should this validated address expire?
529 struct GNUNET_TIME_Absolute expiration;
532 * Length of the address we are validating.
537 * Set to GNUNET_YES if the challenge was met,
538 * GNUNET_SYSERR if we know it failed, GNUNET_NO
539 * if we are waiting on a response.
546 * Entry in linked list of all HELLOs awaiting validation.
548 struct ValidationList
552 * This is a linked list.
554 struct ValidationList *next;
557 * Linked list with one entry per address from the HELLO
558 * that needs to be validated.
560 struct ValidationAddress *addresses;
563 * The public key of the peer.
565 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
568 * When does this record time-out? (assuming the
569 * challenge goes unanswered)
571 struct GNUNET_TIME_Absolute timeout;
577 * HELLOs awaiting validation.
579 static struct ValidationList *pending_validations;
584 static struct GNUNET_HELLO_Message *our_hello;
587 * "version" of "our_hello". Used to see if a given
588 * neighbour has already been sent the latest version
589 * of our HELLO message.
591 static unsigned int our_hello_version;
596 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
601 static struct GNUNET_PeerIdentity my_identity;
606 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
611 struct GNUNET_SCHEDULER_Handle *sched;
616 struct GNUNET_CONFIGURATION_Handle *cfg;
619 * Linked list of all clients to this service.
621 static struct TransportClient *clients;
624 * All loaded plugins.
626 static struct TransportPlugin *plugins;
631 static struct GNUNET_SERVER_Handle *server;
634 * All known neighbours and their HELLOs.
636 static struct NeighbourList *neighbours;
639 * Number of neighbours we'd like to have.
641 static uint32_t max_connect_per_transport;
645 * Find an entry in the neighbour list for a particular peer.
647 * @return NULL if not found.
649 static struct NeighbourList *
650 find_neighbour (const struct GNUNET_PeerIdentity *key)
652 struct NeighbourList *head = neighbours;
653 while ((head != NULL) &&
654 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
661 * Find an entry in the transport list for a particular transport.
663 * @return NULL if not found.
665 static struct TransportPlugin *
666 find_transport (const char *short_name)
668 struct TransportPlugin *head = plugins;
669 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
676 * Update the quota values for the given neighbour now.
679 update_quota (struct NeighbourList *n)
681 struct GNUNET_TIME_Relative delta;
685 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
686 if (delta.value < MIN_QUOTA_REFRESH_TIME)
687 return; /* not enough time passed for doing quota update */
688 allowed = delta.value * n->quota_in;
689 if (n->last_received < allowed)
691 remaining = allowed - n->last_received;
693 remaining /= n->quota_in;
696 if (remaining > MAX_BANDWIDTH_CARRY)
697 remaining = MAX_BANDWIDTH_CARRY;
698 n->last_received = 0;
699 n->last_quota_update = GNUNET_TIME_absolute_get ();
700 n->last_quota_update.value -= remaining;
701 if (n->quota_violation_count > 0)
702 n->quota_violation_count--;
706 n->last_received -= allowed;
707 n->last_quota_update = GNUNET_TIME_absolute_get ();
708 if (n->last_received > allowed)
710 /* more than twice the allowed rate! */
711 n->quota_violation_count += 10;
718 * Function called to notify a client about the socket
719 * being ready to queue more data. "buf" will be
720 * NULL and "size" zero if the socket was closed for
721 * writing in the meantime.
724 * @param size number of bytes available in buf
725 * @param buf where the callee should write the message
726 * @return number of bytes written to buf
729 transmit_to_client_callback (void *cls, size_t size, void *buf)
731 struct TransportClient *client = cls;
732 struct ClientMessageQueueEntry *q;
735 const struct GNUNET_MessageHeader *msg;
736 struct GNUNET_NETWORK_TransmitHandle *th;
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
742 "Transmission to client failed, closing connection.\n");
743 /* fatal error with client, free message queue! */
744 while (NULL != (q = client->message_queue_head))
746 client->message_queue_head = q->next;
749 client->message_queue_tail = NULL;
750 client->message_count = 0;
755 while (NULL != (q = client->message_queue_head))
757 msg = (const struct GNUNET_MessageHeader *) &q[1];
758 msize = ntohs (msg->size);
759 if (msize + tsize > size)
761 client->message_queue_head = q->next;
763 client->message_queue_tail = NULL;
764 memcpy (&cbuf[tsize], msg, msize);
767 client->message_count--;
769 GNUNET_assert (tsize > 0);
772 th = GNUNET_SERVER_notify_transmit_ready (client->client,
774 GNUNET_TIME_UNIT_FOREVER_REL,
775 &transmit_to_client_callback,
777 GNUNET_assert (th != NULL);
784 * Send the specified message to the specified client. Since multiple
785 * messages may be pending for the same client at a time, this code
786 * makes sure that no message is lost.
788 * @param client client to transmit the message to
789 * @param msg the message to send
790 * @param may_drop can this message be dropped if the
791 * message queue for this client is getting far too large?
794 transmit_to_client (struct TransportClient *client,
795 const struct GNUNET_MessageHeader *msg, int may_drop)
797 struct ClientMessageQueueEntry *q;
799 struct GNUNET_NETWORK_TransmitHandle *th;
801 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
803 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
805 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
806 client->message_count, MAX_PENDING);
807 /* TODO: call to statistics... */
810 client->message_count++;
811 msize = ntohs (msg->size);
812 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
813 memcpy (&q[1], msg, msize);
814 /* append to message queue */
815 if (client->message_queue_tail == NULL)
817 client->message_queue_tail = q;
821 client->message_queue_tail->next = q;
822 client->message_queue_tail = q;
824 if (client->message_queue_head == NULL)
826 client->message_queue_head = q;
827 th = GNUNET_SERVER_notify_transmit_ready (client->client,
829 GNUNET_TIME_UNIT_FOREVER_REL,
830 &transmit_to_client_callback,
832 GNUNET_assert (th != NULL);
838 * Find alternative plugins for communication.
840 * @param neighbour for which neighbour should we try to find
844 try_alternative_plugins (struct NeighbourList *neighbour)
846 struct ReadyList *rl;
848 if ((neighbour->plugins != NULL) &&
849 (neighbour->retry_plugins_time.value >
850 GNUNET_TIME_absolute_get ().value))
851 return; /* don't try right now */
852 neighbour->retry_plugins_time
853 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
855 rl = neighbour->plugins;
858 if (rl->connect_attempts > 0)
859 rl->connect_attempts--; /* amnesty */
867 * Check the ready list for the given neighbour and
868 * if a plugin is ready for transmission (and if we
869 * have a message), do so!
871 * @param neighbour target peer for which to check the plugins
873 static void try_transmission_to_peer (struct NeighbourList *neighbour);
877 * Function called by the GNUNET_TRANSPORT_TransmitFunction
878 * upon "completion" of a send request. This tells the API
879 * that it is now legal to send another message to the given
882 * @param cls closure, identifies the entry on the
883 * message queue that was transmitted and the
884 * client responsible for queueing the message
885 * @param rl identifies plugin used for the transmission for
886 * this neighbour; needs to be re-enabled for
887 * future transmissions
888 * @param target the peer receiving the message
889 * @param result GNUNET_OK on success, if the transmission
890 * failed, we should not tell the client to transmit
894 transmit_send_continuation (void *cls,
895 struct ReadyList *rl,
896 const struct GNUNET_PeerIdentity *target,
899 struct MessageQueue *mq = cls;
900 struct SendOkMessage send_ok_msg;
901 struct NeighbourList *n;
903 GNUNET_assert (mq != NULL);
905 GNUNET_assert (n != NULL);
907 memcmp (&n->id, target,
908 sizeof (struct GNUNET_PeerIdentity)));
912 while ((rl != NULL) && (rl->plugin != mq->plugin))
914 GNUNET_assert (rl != NULL);
916 if (result == GNUNET_OK)
918 rl->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
923 "Transmission failed, marking connection as down.\n");
924 rl->connected = GNUNET_NO;
926 if (!mq->internal_msg)
927 rl->transmit_ready = GNUNET_YES;
928 if (mq->client != NULL)
930 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
931 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
932 send_ok_msg.success = htonl (result);
933 send_ok_msg.peer = n->id;
934 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
936 GNUNET_free (mq->message);
938 /* one plugin just became ready again, try transmitting
939 another message (if available) */
940 try_transmission_to_peer (n);
947 * We could not use an existing (or validated) connection to
948 * talk to a peer. Try addresses that have not yet been
951 * @param n neighbour we want to communicate with
952 * @return plugin ready to talk, or NULL if none is available
954 static struct ReadyList *
955 try_unvalidated_addresses (struct NeighbourList *n)
957 struct ValidationList *vl;
958 struct ValidationAddress *va;
959 struct GNUNET_PeerIdentity id;
960 struct GNUNET_TIME_Absolute now;
963 struct ReadyList *rl;
964 struct TransportPlugin *plugin;
967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968 "Trying to connect to `%4s' using unvalidated addresses\n",
969 GNUNET_i2s (&n->id));
971 /* NOTE: this function needs to not only identify the
972 plugin but also setup "plugin_handle", binding it to the
973 right address using the plugin's "send_to" API */
974 now = GNUNET_TIME_absolute_get ();
975 vl = pending_validations;
978 GNUNET_CRYPTO_hash (&vl->publicKey,
980 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
982 if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990 "No unvalidated address found for peer `%4s'\n",
991 GNUNET_i2s (&n->id));
1001 if (va->expiration.value > now.value)
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 "All %u unvalidated addresses for peer have expired\n",
1014 total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
1015 for (va = vl->addresses; va != NULL; va = va->next)
1017 if (va->expiration.value <= now.value)
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1026 "Trying unvalidated address of `%s' transport\n",
1027 va->transport_name);
1029 plugin = find_transport (va->transport_name);
1035 rl = GNUNET_malloc (sizeof (struct ReadyList));
1036 rl->next = n->plugins;
1038 rl->plugin = plugin;
1039 rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
1043 GNUNET_TIME_UNIT_ZERO,
1044 &va->msg[1], va->addr_len);
1045 rl->transmit_ready = GNUNET_YES;
1053 * Check the ready list for the given neighbour and
1054 * if a plugin is ready for transmission (and if we
1055 * have a message), do so!
1058 try_transmission_to_peer (struct NeighbourList *neighbour)
1060 struct ReadyList *pos;
1061 struct GNUNET_TIME_Relative min_latency;
1062 struct ReadyList *rl;
1063 struct MessageQueue *mq;
1064 struct GNUNET_TIME_Absolute now;
1066 if (neighbour->messages == NULL)
1067 return; /* nothing to do */
1068 try_alternative_plugins (neighbour);
1069 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1071 mq = neighbour->messages;
1072 now = GNUNET_TIME_absolute_get ();
1073 pos = neighbour->plugins;
1076 /* set plugins that are inactive for a long time back to disconnected */
1077 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1081 "Marking long-time inactive connection to `%4s' as down.\n",
1082 GNUNET_i2s (&neighbour->id));
1084 pos->connected = GNUNET_NO;
1086 if (((GNUNET_YES == pos->transmit_ready) ||
1087 (mq->internal_msg)) &&
1088 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1089 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1092 min_latency = pos->latency;
1097 rl = try_unvalidated_addresses (neighbour);
1101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1102 "No plugin ready to transmit message\n");
1104 return; /* nobody ready */
1106 if (GNUNET_NO == rl->connected)
1108 rl->connect_attempts++;
1109 rl->connected = GNUNET_YES;
1111 neighbour->messages = mq->next;
1112 mq->plugin = rl->plugin;
1113 if (!mq->internal_msg)
1114 rl->transmit_ready = GNUNET_NO;
1116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1117 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1118 ntohs (mq->message->type),
1119 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
1122 = rl->plugin->api->send (rl->plugin->api->cls,
1127 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1128 &transmit_send_continuation, mq);
1133 * Send the specified message to the specified peer.
1135 * @param client source of the transmission request (can be NULL)
1136 * @param msg message to send
1137 * @param is_internal is this an internal message
1138 * @param neighbour handle to the neighbour for transmission
1141 transmit_to_peer (struct TransportClient *client,
1142 const struct GNUNET_MessageHeader *msg,
1143 int is_internal, struct NeighbourList *neighbour)
1145 struct MessageQueue *mq;
1146 struct MessageQueue *mqe;
1147 struct GNUNET_MessageHeader *m;
1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1151 _("Sending message of type %u to peer `%4s'\n"),
1152 ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1156 /* check for duplicate submission */
1157 mq = neighbour->messages;
1160 if (mq->client == client)
1162 /* client transmitted to same peer twice
1163 before getting SendOk! */
1170 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1171 mq->client = client;
1172 m = GNUNET_malloc (ntohs (msg->size));
1173 memcpy (m, msg, ntohs (msg->size));
1175 mq->neighbour = neighbour;
1176 mq->internal_msg = is_internal;
1179 mqe = neighbour->messages;
1181 while (mqe->next != NULL)
1186 neighbour->messages = mq;
1187 try_transmission_to_peer (neighbour);
1197 struct GeneratorContext
1199 struct TransportPlugin *plug_pos;
1200 struct AddressList *addr_pos;
1201 struct GNUNET_TIME_Absolute expiration;
1206 address_generator (void *cls, size_t max, void *buf)
1208 struct GeneratorContext *gc = cls;
1211 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1213 gc->plug_pos = gc->plug_pos->next;
1214 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1216 if (NULL == gc->plug_pos)
1218 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1221 gc->addr_pos->addrlen, buf, max);
1222 gc->addr_pos = gc->addr_pos->next;
1228 * Construct our HELLO message from all of the addresses of
1229 * all of the transports.
1234 struct GNUNET_HELLO_Message *hello;
1235 struct TransportClient *cpos;
1236 struct NeighbourList *npos;
1237 struct GeneratorContext gc;
1240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1241 "Refreshing my HELLO\n");
1243 gc.plug_pos = plugins;
1244 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1245 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1246 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1248 while (cpos != NULL)
1250 transmit_to_client (cpos,
1251 (const struct GNUNET_MessageHeader *) hello,
1256 GNUNET_free_non_null (our_hello);
1258 our_hello_version++;
1260 while (npos != NULL)
1262 transmit_to_peer (NULL,
1263 (const struct GNUNET_MessageHeader *) our_hello,
1271 * Task used to clean up expired addresses for a plugin.
1273 * @param cls closure
1277 expire_address_task (void *cls,
1278 const struct GNUNET_SCHEDULER_TaskContext *tc);
1282 * Update the list of addresses for this plugin,
1283 * expiring those that are past their expiration date.
1285 * @param plugin addresses of which plugin should be recomputed?
1286 * @param fresh set to GNUNET_YES if a new address was added
1287 * and we need to regenerate the HELLO even if nobody
1291 update_addresses (struct TransportPlugin *plugin, int fresh)
1293 struct GNUNET_TIME_Relative min_remaining;
1294 struct GNUNET_TIME_Relative remaining;
1295 struct GNUNET_TIME_Absolute now;
1296 struct AddressList *pos;
1297 struct AddressList *prev;
1298 struct AddressList *next;
1301 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
1302 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1303 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1304 now = GNUNET_TIME_absolute_get ();
1305 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1306 expired = GNUNET_NO;
1308 pos = plugin->addresses;
1312 if (pos->expires.value < now.value)
1314 expired = GNUNET_YES;
1316 plugin->addresses = pos->next;
1318 prev->next = pos->next;
1323 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1324 if (remaining.value < min_remaining.value)
1325 min_remaining = remaining;
1331 if (expired || fresh)
1333 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1334 plugin->address_update_task
1335 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1337 GNUNET_SCHEDULER_PRIORITY_IDLE,
1338 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1340 &expire_address_task, plugin);
1346 * Task used to clean up expired addresses for a plugin.
1348 * @param cls closure
1352 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1354 struct TransportPlugin *plugin = cls;
1355 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1356 update_addresses (plugin, GNUNET_NO);
1361 * Function that must be called by each plugin to notify the
1362 * transport service about the addresses under which the transport
1363 * provided by the plugin can be reached.
1365 * @param cls closure
1366 * @param name name of the transport that generated the address
1367 * @param addr one of the addresses of the host, NULL for the last address
1368 * the specific address format depends on the transport
1369 * @param addrlen length of the address
1370 * @param expires when should this address automatically expire?
1373 plugin_env_notify_address (void *cls,
1377 struct GNUNET_TIME_Relative expires)
1379 struct TransportPlugin *p = cls;
1380 struct AddressList *al;
1381 struct GNUNET_TIME_Absolute abex;
1384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1385 "Plugin `%s' informs us about a new address `%s'\n", name,
1386 GNUNET_a2s(addr, addrlen));
1388 abex = GNUNET_TIME_relative_to_absolute (expires);
1389 GNUNET_assert (p == find_transport (name));
1394 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1396 if (al->expires.value < abex.value)
1402 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1404 al->next = p->addresses;
1407 al->addrlen = addrlen;
1408 memcpy (&al[1], addr, addrlen);
1409 update_addresses (p, GNUNET_YES);
1413 struct LookupHelloContext
1415 GNUNET_TRANSPORT_AddressCallback iterator;
1422 lookup_address_callback (void *cls,
1424 struct GNUNET_TIME_Absolute expiration,
1425 const void *addr, size_t addrlen)
1427 struct LookupHelloContext *lhc = cls;
1428 lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
1434 lookup_hello_callback (void *cls,
1435 const struct GNUNET_PeerIdentity *peer,
1436 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1438 struct LookupHelloContext *lhc = cls;
1442 lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
1448 GNUNET_HELLO_iterate_addresses (h,
1449 GNUNET_NO, &lookup_address_callback, lhc);
1454 * Function that allows a transport to query the known
1455 * network addresses for a given peer.
1457 * @param cls closure
1458 * @param timeout after how long should we time out?
1459 * @param target which peer are we looking for?
1460 * @param iter function to call for each known address
1461 * @param iter_cls closure for iter
1464 plugin_env_lookup_address (void *cls,
1465 struct GNUNET_TIME_Relative timeout,
1466 const struct GNUNET_PeerIdentity *target,
1467 GNUNET_TRANSPORT_AddressCallback iter,
1470 struct LookupHelloContext *lhc;
1472 lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
1473 lhc->iterator = iter;
1474 lhc->iterator_cls = iter_cls;
1475 GNUNET_PEERINFO_for_all (cfg,
1477 target, 0, timeout, &lookup_hello_callback, &lhc);
1482 * Notify all of our clients about a peer connecting.
1485 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1486 struct GNUNET_TIME_Relative latency)
1488 struct ConnectInfoMessage cim;
1489 struct TransportClient *cpos;
1492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493 "Informing clients about peer `%4s' connecting to us\n",
1496 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1497 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1498 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60*1000));
1499 cim.latency = GNUNET_TIME_relative_hton (latency);
1500 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1502 while (cpos != NULL)
1504 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1511 * Notify all of our clients about a peer disconnecting.
1514 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1516 struct DisconnectInfoMessage dim;
1517 struct TransportClient *cpos;
1520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1521 "Informing clients about peer `%4s' disconnecting\n",
1524 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1525 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1526 dim.reserved = htonl (0);
1527 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1529 while (cpos != NULL)
1531 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1538 * Copy any validated addresses to buf.
1540 * @return 0 once all addresses have been
1544 list_validated_addresses (void *cls, size_t max, void *buf)
1546 struct ValidationAddress **va = cls;
1549 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1553 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1555 &(*va)->msg[1], (*va)->addr_len, buf, max);
1562 * HELLO validation cleanup task.
1565 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1567 struct ValidationAddress *va;
1568 struct ValidationList *pos;
1569 struct ValidationList *prev;
1570 struct GNUNET_TIME_Absolute now;
1571 struct GNUNET_HELLO_Message *hello;
1572 struct GNUNET_PeerIdentity pid;
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1576 "HELLO validation cleanup background task running...\n");
1578 now = GNUNET_TIME_absolute_get ();
1580 pos = pending_validations;
1583 if (pos->timeout.value < now.value)
1586 pending_validations = pos->next;
1588 prev->next = pos->next;
1589 va = pos->addresses;
1590 hello = GNUNET_HELLO_create (&pos->publicKey,
1591 &list_validated_addresses, &va);
1592 GNUNET_CRYPTO_hash (&pos->publicKey,
1594 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1598 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1599 "HELLO", GNUNET_i2s (&pid));
1601 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1602 GNUNET_free (hello);
1603 while (NULL != (va = pos->addresses))
1605 pos->addresses = va->next;
1606 GNUNET_free (va->transport_name);
1611 pos = pending_validations;
1620 /* finally, reschedule cleanup if needed; list is
1621 ordered by timeout, so we need the last element... */
1622 pos = pending_validations;
1623 while ((pos != NULL) && (pos->next != NULL))
1626 GNUNET_SCHEDULER_add_delayed (sched,
1628 GNUNET_SCHEDULER_PRIORITY_IDLE,
1629 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1630 GNUNET_TIME_absolute_get_remaining
1631 (pos->timeout), &cleanup_validation, NULL);
1635 struct CheckHelloValidatedContext
1638 * Plugin for which we are validating.
1640 struct TransportPlugin *plugin;
1643 * Hello that we are validating.
1645 struct GNUNET_HELLO_Message *hello;
1648 * Validation list being build.
1650 struct ValidationList *e;
1656 * Append the given address to the list of entries
1657 * that need to be validated.
1660 run_validation (void *cls,
1662 struct GNUNET_TIME_Absolute expiration,
1663 const void *addr, size_t addrlen)
1665 struct ValidationList *e = cls;
1666 struct TransportPlugin *tp;
1667 struct ValidationAddress *va;
1668 struct ValidationChallengeMessage *vcm;
1669 struct GNUNET_PeerIdentity id;
1671 tp = find_transport (tname);
1674 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1675 GNUNET_ERROR_TYPE_BULK,
1677 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1681 GNUNET_CRYPTO_hash (&e->publicKey,
1683 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1687 GNUNET_a2s(addr, addrlen),
1691 va = GNUNET_malloc (sizeof (struct ValidationAddress) +
1692 sizeof (struct ValidationChallengeMessage) + addrlen);
1693 va->next = e->addresses;
1695 vcm = (struct ValidationChallengeMessage *) &va[1];
1697 va->transport_name = GNUNET_strdup (tname);
1698 va->addr_len = addrlen;
1700 htons (sizeof (struct ValidationChallengeMessage) + addrlen);
1701 vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1703 htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
1704 sizeof (struct GNUNET_MessageHeader));
1705 vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
1706 vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1709 memcpy (&vcm[1], addr, addrlen);
1715 * Check if addresses in validated hello "h" overlap with
1716 * those in "chvc->hello" and update "chvc->hello" accordingly,
1717 * removing those addresses that have already been validated.
1720 check_hello_validated (void *cls,
1721 const struct GNUNET_PeerIdentity *peer,
1722 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1724 struct CheckHelloValidatedContext *chvc = cls;
1725 struct ValidationAddress *va;
1726 struct TransportPlugin *tp;
1729 first_call = GNUNET_NO;
1730 if (chvc->e == NULL)
1732 first_call = GNUNET_YES;
1733 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1734 GNUNET_assert (GNUNET_OK ==
1735 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1736 &chvc->e->publicKey));
1738 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1739 chvc->e->next = pending_validations;
1740 pending_validations = chvc->e;
1744 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1746 GNUNET_TIME_absolute_get (),
1747 &run_validation, chvc->e);
1749 else if (GNUNET_YES == first_call)
1751 /* no existing HELLO, all addresses are new */
1752 GNUNET_HELLO_iterate_addresses (chvc->hello,
1753 GNUNET_NO, &run_validation, chvc->e);
1756 return; /* wait for next call */
1757 /* finally, transmit validation attempts */
1758 va = chvc->e->addresses;
1762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1763 "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
1765 "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
1767 tp = find_transport (va->transport_name);
1768 GNUNET_assert (tp != NULL);
1770 tp->api->send_to (tp->api->cls,
1772 (const struct GNUNET_MessageHeader *) our_hello,
1774 HELLO_VERIFICATION_TIMEOUT,
1775 &va->msg[1], va->addr_len))
1776 va->ok = GNUNET_SYSERR;
1779 if (chvc->e->next == NULL)
1780 GNUNET_SCHEDULER_add_delayed (sched,
1782 GNUNET_SCHEDULER_PRIORITY_IDLE,
1783 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1784 GNUNET_TIME_absolute_get_remaining
1785 (chvc->e->timeout), &cleanup_validation,
1792 * Process HELLO-message.
1794 * @param plugin transport involved, may be NULL
1795 * @param message the actual message
1796 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1799 process_hello (struct TransportPlugin *plugin,
1800 const struct GNUNET_MessageHeader *message)
1802 struct ValidationList *e;
1804 struct GNUNET_PeerIdentity target;
1805 const struct GNUNET_HELLO_Message *hello;
1806 struct CheckHelloValidatedContext *chvc;
1807 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1809 hsize = ntohs (message->size);
1810 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1811 (hsize < sizeof (struct GNUNET_MessageHeader)))
1814 return GNUNET_SYSERR;
1816 /* first, check if load is too high */
1817 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1819 /* TODO: call to stats? */
1822 hello = (const struct GNUNET_HELLO_Message *) message;
1823 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1825 GNUNET_break_op (0);
1826 return GNUNET_SYSERR;
1828 GNUNET_CRYPTO_hash (&publicKey,
1829 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1830 &target.hashPubKey);
1832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833 "Processing `%s' message for `%4s'\n",
1834 "HELLO", GNUNET_i2s (&target));
1836 /* check if a HELLO for this peer is already on the validation list */
1837 e = pending_validations;
1840 if (0 == memcmp (&e->publicKey,
1843 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1845 /* TODO: call to stats? */
1847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1848 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1849 "HELLO", GNUNET_i2s (&target));
1855 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1856 chvc->plugin = plugin;
1857 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1858 memcpy (chvc->hello, hello, hsize);
1859 /* finally, check if HELLO was previously validated
1860 (continuation will then schedule actual validation) */
1861 GNUNET_PEERINFO_for_all (cfg,
1865 HELLO_VERIFICATION_TIMEOUT,
1866 &check_hello_validated, chvc);
1872 * Handle PING-message. If the plugin that gave us the message is
1873 * able to queue the PONG immediately, we only queue one PONG.
1874 * Otherwise we send at most TWO PONG messages, one via an unconfirmed
1875 * transport and one via a confirmed transport. Both addresses are
1876 * selected randomly among those available.
1878 * @param plugin plugin that gave us the message
1879 * @param sender claimed sender of the PING
1880 * @param plugin_context context that might be used to send response
1881 * @param message the actual message
1884 process_ping (struct TransportPlugin *plugin,
1885 const struct GNUNET_PeerIdentity *sender,
1886 void *plugin_context,
1887 const struct GNUNET_MessageHeader *message)
1889 const struct ValidationChallengeMessage *vcm;
1890 struct ValidationChallengeResponse vcr;
1892 struct NeighbourList *n;
1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1896 "Processing PING\n");
1898 msize = ntohs (message->size);
1899 if (msize < sizeof (struct ValidationChallengeMessage))
1901 GNUNET_break_op (0);
1904 vcm = (const struct ValidationChallengeMessage *) message;
1905 if (0 != memcmp (&vcm->target,
1906 &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1908 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1909 _("Received `%s' message not destined for me!\n"), "PING");
1910 /* TODO: call statistics */
1913 if ((ntohl (vcm->purpose.size) !=
1914 msize - sizeof (struct GNUNET_MessageHeader))
1915 || (ntohl (vcm->purpose.purpose) !=
1916 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
1918 GNUNET_break_op (0);
1921 msize -= sizeof (struct ValidationChallengeMessage);
1923 plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
1925 GNUNET_break_op (0);
1928 vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
1929 vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1930 vcr.challenge = vcm->challenge;
1931 vcr.sender = my_identity;
1932 GNUNET_assert (GNUNET_OK ==
1933 GNUNET_CRYPTO_rsa_sign (my_private_key,
1934 &vcm->purpose, &vcr.signature));
1936 GNUNET_assert (GNUNET_OK ==
1937 GNUNET_CRYPTO_rsa_verify
1938 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
1939 &vcr.signature, &my_public_key));
1942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1943 "Trying to transmit PONG using inbound connection\n");
1945 n = find_neighbour (sender);
1951 transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n);
1956 * Handle PONG-message.
1958 * @param message the actual message
1961 process_pong (struct TransportPlugin *plugin,
1962 const struct GNUNET_MessageHeader *message)
1964 const struct ValidationChallengeResponse *vcr;
1965 struct ValidationList *pos;
1966 struct GNUNET_PeerIdentity peer;
1967 struct ValidationAddress *va;
1972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1973 "Processing PONG\n");
1975 vcr = (const struct ValidationChallengeResponse *) message;
1976 pos = pending_validations;
1979 GNUNET_CRYPTO_hash (&pos->publicKey,
1981 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1984 memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
1990 /* TODO: call statistics (unmatched PONG) */
1991 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1993 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1997 all_done = GNUNET_YES;
1998 matched = GNUNET_NO;
1999 va = pos->addresses;
2002 if (va->msg->challenge == vcr->challenge)
2005 GNUNET_CRYPTO_rsa_verify
2006 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
2007 &vcr->signature, &pos->publicKey))
2009 /* this could rarely happen if we used the same
2010 challenge number for the peer for two different
2011 transports / addresses, but the likelihood is
2013 GNUNET_break_op (0);
2018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2019 "Confirmed validity of peer address.\n");
2021 va->ok = GNUNET_YES;
2023 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2024 matched = GNUNET_YES;
2027 if (va->ok != GNUNET_YES)
2028 all_done = GNUNET_NO;
2031 if (GNUNET_NO == matched)
2033 /* TODO: call statistics (unmatched PONG) */
2034 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2036 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
2039 if (GNUNET_YES == all_done)
2041 pos->timeout.value = 0;
2042 GNUNET_SCHEDULER_add_delayed (sched,
2044 GNUNET_SCHEDULER_PRIORITY_IDLE,
2045 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2046 GNUNET_TIME_UNIT_ZERO,
2047 &cleanup_validation, NULL);
2053 * The peer specified by the given neighbour has timed-out. Update
2054 * our state and do the necessary notifications. Also notifies
2055 * our clients that the neighbour is now officially gone.
2057 * @param n the neighbour list entry for the peer
2060 disconnect_neighbour (struct NeighbourList *n)
2062 struct ReadyList *rpos;
2063 struct NeighbourList *npos;
2064 struct NeighbourList *nprev;
2065 struct MessageQueue *mq;
2068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2069 "Disconnecting from neighbour\n");
2071 /* remove n from neighbours list */
2074 while ((npos != NULL) && (npos != n))
2079 GNUNET_assert (npos != NULL);
2081 neighbours = n->next;
2083 nprev->next = n->next;
2085 /* notify all clients about disconnect */
2086 notify_clients_disconnect (&n->id);
2088 /* clean up all plugins, cancel connections & pending transmissions */
2089 while (NULL != (rpos = n->plugins))
2091 n->plugins = rpos->next;
2092 GNUNET_assert (rpos->neighbour == n);
2093 rpos->plugin->api->cancel (rpos->plugin->api->cls,
2094 rpos->plugin_handle, rpos, &n->id);
2098 /* free all messages on the queue */
2099 while (NULL != (mq = n->messages))
2101 n->messages = mq->next;
2102 GNUNET_assert (mq->neighbour == n);
2106 /* finally, free n itself */
2112 * Add an entry for each of our transport plugins
2113 * (that are able to send) to the list of plugins
2114 * for this neighbour.
2116 * @param neighbour to initialize
2119 add_plugins (struct NeighbourList *neighbour)
2121 struct TransportPlugin *tp;
2122 struct ReadyList *rl;
2124 neighbour->retry_plugins_time
2125 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2129 if (tp->api->send != NULL)
2131 rl = GNUNET_malloc (sizeof (struct ReadyList));
2132 rl->next = neighbour->plugins;
2133 neighbour->plugins = rl;
2135 rl->neighbour = neighbour;
2136 rl->transmit_ready = GNUNET_YES;
2144 neighbour_timeout_task (void *cls,
2145 const struct GNUNET_SCHEDULER_TaskContext *tc)
2147 struct NeighbourList *n = cls;
2150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2151 "Neighbour has timed out!\n");
2153 n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
2154 disconnect_neighbour (n);
2160 * Create a fresh entry in our neighbour list for the given peer.
2161 * Will try to transmit our current HELLO to the new neighbour. Also
2162 * notifies our clients about the new "connection".
2164 * @param peer the peer for which we create the entry
2165 * @return the new neighbour list entry
2167 static struct NeighbourList *
2168 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2170 struct NeighbourList *n;
2173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2174 "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
2177 GNUNET_assert (our_hello != NULL);
2178 n = GNUNET_malloc (sizeof (struct NeighbourList));
2179 n->next = neighbours;
2182 n->last_quota_update = GNUNET_TIME_absolute_get ();
2184 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2185 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2187 n->hello_version_sent = our_hello_version;
2188 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2190 GNUNET_SCHEDULER_PRIORITY_IDLE,
2191 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2192 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2193 &neighbour_timeout_task, n);
2194 transmit_to_peer (NULL,
2195 (const struct GNUNET_MessageHeader *) our_hello,
2197 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2203 * Function called by the plugin for each received message.
2204 * Update data volumes, possibly notify plugins about
2205 * reducing the rate at which they read from the socket
2206 * and generally forward to our receive callback.
2208 * @param plugin_context value to pass to this plugin
2209 * to respond to the given peer (use is optional,
2210 * but may speed up processing)
2211 * @param service_context value passed to the transport-service
2212 * to identify the neighbour; will be NULL on the first
2213 * call for a given peer
2214 * @param latency estimated latency for communicating with the
2216 * @param peer (claimed) identity of the other peer
2217 * @param message the message, NULL if peer was disconnected
2218 * @return the new service_context that the plugin should use
2219 * for future receive calls for messages from this
2222 static struct ReadyList *
2223 plugin_env_receive (void *cls,
2224 void *plugin_context,
2225 struct ReadyList *service_context,
2226 struct GNUNET_TIME_Relative latency,
2227 const struct GNUNET_PeerIdentity *peer,
2228 const struct GNUNET_MessageHeader *message)
2230 const struct GNUNET_MessageHeader ack = {
2231 htons (sizeof (struct GNUNET_MessageHeader)),
2232 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2234 struct TransportPlugin *plugin = cls;
2235 struct TransportClient *cpos;
2236 struct InboundMessage *im;
2238 struct NeighbourList *n;
2240 if (service_context != NULL)
2242 n = service_context->neighbour;
2243 GNUNET_assert (n != NULL);
2247 n = find_neighbour (peer);
2250 if (message == NULL)
2251 return NULL; /* disconnect of peer already marked down */
2252 n = setup_new_neighbour (peer);
2254 service_context = n->plugins;
2255 while ((service_context != NULL) && (plugin != service_context->plugin))
2256 service_context = service_context->next;
2257 GNUNET_assert ((plugin->api->send == NULL) ||
2258 (service_context != NULL));
2260 if (message == NULL)
2262 if ((service_context != NULL) &&
2263 (service_context->plugin_handle == plugin_context))
2265 service_context->connected = GNUNET_NO;
2266 service_context->plugin_handle = NULL;
2268 /* TODO: call stats */
2272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2273 "Processing message of type `%u' received by plugin...\n",
2274 ntohs (message->type));
2276 if (service_context != NULL)
2278 if (service_context->connected == GNUNET_NO)
2280 service_context->connected = GNUNET_YES;
2281 service_context->transmit_ready = GNUNET_YES;
2282 service_context->connect_attempts++;
2284 service_context->timeout
2285 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2286 service_context->plugin_handle = plugin_context;
2287 service_context->latency = latency;
2289 /* update traffic received amount ... */
2290 msize = ntohs (message->size);
2291 n->last_received += msize;
2292 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2294 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2296 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
2297 GNUNET_SCHEDULER_PRIORITY_IDLE,
2298 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2299 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2300 &neighbour_timeout_task, n);
2302 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2304 /* dropping message due to frequent inbound volume violations! */
2305 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2306 GNUNET_ERROR_TYPE_BULK,
2308 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2309 /* TODO: call stats */
2310 GNUNET_assert (NULL != service_context->neighbour);
2311 return service_context;
2313 switch (ntohs (message->type))
2315 case GNUNET_MESSAGE_TYPE_HELLO:
2317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2318 "Receiving `%s' message from other peer.\n", "HELLO");
2320 process_hello (plugin, message);
2322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2323 "Sending `%s' message to connecting peer.\n", "ACK");
2325 transmit_to_peer (NULL, &ack, GNUNET_YES, n);
2327 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2328 process_ping (plugin, peer, plugin_context, message);
2330 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2331 process_pong (plugin, message);
2333 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2334 n->saw_ack = GNUNET_YES;
2335 /* intentional fall-through! */
2338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2339 "Received message of type %u from other peer, sending to all clients.\n",
2340 ntohs (message->type));
2342 /* transmit message to all clients */
2343 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2344 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2345 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2346 im->latency = GNUNET_TIME_relative_hton (latency);
2348 memcpy (&im[1], message, msize);
2351 while (cpos != NULL)
2353 transmit_to_client (cpos, &im->header, GNUNET_YES);
2358 GNUNET_assert (NULL != service_context->neighbour);
2359 return service_context;
2364 * Handle START-message. This is the first message sent to us
2365 * by any client which causes us to add it to our list.
2367 * @param cls closure (always NULL)
2368 * @param client identification of the client
2369 * @param message the actual message
2372 handle_start (void *cls,
2373 struct GNUNET_SERVER_Client *client,
2374 const struct GNUNET_MessageHeader *message)
2376 struct TransportClient *c;
2377 struct ConnectInfoMessage cim;
2378 struct NeighbourList *n;
2379 struct InboundMessage *im;
2380 struct GNUNET_MessageHeader *ack;
2383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2384 "Received `%s' request from client\n", "START");
2389 if (c->client == client)
2391 /* client already on our list! */
2393 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2398 c = GNUNET_malloc (sizeof (struct TransportClient));
2402 if (our_hello != NULL)
2405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2406 "Sending our own HELLO to new client\n");
2408 transmit_to_client (c,
2409 (const struct GNUNET_MessageHeader *) our_hello,
2411 /* tell new client about all existing connections */
2412 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2413 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2414 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2415 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2416 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2417 sizeof (struct GNUNET_MessageHeader));
2418 im->header.size = htons (sizeof (struct InboundMessage) +
2419 sizeof (struct GNUNET_MessageHeader));
2420 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2421 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2422 ack = (struct GNUNET_MessageHeader *) &im[1];
2423 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2424 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2425 for (n = neighbours; n != NULL; n = n->next)
2428 transmit_to_client (c, &cim.header, GNUNET_NO);
2432 transmit_to_client (c, &im->header, GNUNET_NO);
2437 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2442 * Handle HELLO-message.
2444 * @param cls closure (always NULL)
2445 * @param client identification of the client
2446 * @param message the actual message
2449 handle_hello (void *cls,
2450 struct GNUNET_SERVER_Client *client,
2451 const struct GNUNET_MessageHeader *message)
2456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2457 "Received `%s' request from client\n", "HELLO");
2459 ret = process_hello (NULL, message);
2460 GNUNET_SERVER_receive_done (client, ret);
2465 * Handle SEND-message.
2467 * @param cls closure (always NULL)
2468 * @param client identification of the client
2469 * @param message the actual message
2472 handle_send (void *cls,
2473 struct GNUNET_SERVER_Client *client,
2474 const struct GNUNET_MessageHeader *message)
2476 struct TransportClient *tc;
2477 struct NeighbourList *n;
2478 const struct OutboundMessage *obm;
2479 const struct GNUNET_MessageHeader *obmm;
2483 size = ntohs (message->size);
2485 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2488 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2491 obm = (const struct OutboundMessage *) message;
2493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2494 "Received `%s' request from client with target `%4s'\n",
2495 "SEND", GNUNET_i2s (&obm->peer));
2497 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2498 msize = ntohs (obmm->size);
2499 if (size != msize + sizeof (struct OutboundMessage))
2502 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2505 n = find_neighbour (&obm->peer);
2507 n = setup_new_neighbour (&obm->peer);
2509 while ((tc != NULL) && (tc->client != client))
2513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2514 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2516 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2518 transmit_to_peer (tc, obmm, GNUNET_NO, n);
2519 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2524 * Handle SET_QUOTA-message.
2526 * @param cls closure (always NULL)
2527 * @param client identification of the client
2528 * @param message the actual message
2531 handle_set_quota (void *cls,
2532 struct GNUNET_SERVER_Client *client,
2533 const struct GNUNET_MessageHeader *message)
2535 const struct QuotaSetMessage *qsm =
2536 (const struct QuotaSetMessage *) message;
2537 struct NeighbourList *n;
2538 struct TransportPlugin *p;
2539 struct ReadyList *rl;
2542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2543 "Received `%s' request from client for peer `%4s'\n",
2544 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2546 n = find_neighbour (&qsm->peer);
2549 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2553 if (n->quota_in < ntohl (qsm->quota_in))
2554 n->last_quota_update = GNUNET_TIME_absolute_get ();
2555 n->quota_in = ntohl (qsm->quota_in);
2560 p->api->set_receive_quota (p->api->cls,
2561 &qsm->peer, ntohl (qsm->quota_in));
2564 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2569 * Handle TRY_CONNECT-message.
2571 * @param cls closure (always NULL)
2572 * @param client identification of the client
2573 * @param message the actual message
2576 handle_try_connect (void *cls,
2577 struct GNUNET_SERVER_Client *client,
2578 const struct GNUNET_MessageHeader *message)
2580 const struct TryConnectMessage *tcm;
2582 tcm = (const struct TryConnectMessage *) message;
2584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585 "Received `%s' request from client asking to connect to `%4s'\n",
2586 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2588 if (NULL == find_neighbour (&tcm->peer))
2589 setup_new_neighbour (&tcm->peer);
2590 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2595 * List of handlers for the messages understood by this
2598 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2599 {&handle_start, NULL,
2600 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2601 {&handle_hello, NULL,
2602 GNUNET_MESSAGE_TYPE_HELLO, 0},
2603 {&handle_send, NULL,
2604 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2605 {&handle_set_quota, NULL,
2606 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2607 {&handle_try_connect, NULL,
2608 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2609 sizeof (struct TryConnectMessage)},
2615 * Setup the environment for this plugin.
2618 create_environment (struct TransportPlugin *plug)
2620 plug->env.cfg = cfg;
2621 plug->env.sched = sched;
2622 plug->env.my_public_key = &my_public_key;
2623 plug->env.cls = plug;
2624 plug->env.receive = &plugin_env_receive;
2625 plug->env.lookup = &plugin_env_lookup_address;
2626 plug->env.notify_address = &plugin_env_notify_address;
2627 plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2628 plug->env.max_connections = max_connect_per_transport;
2633 * Start the specified transport (load the plugin).
2636 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2638 struct TransportPlugin *plug;
2641 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2642 _("Loading `%s' transport plugin\n"), name);
2643 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2644 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2645 create_environment (plug);
2646 plug->short_name = GNUNET_strdup (name);
2647 plug->lib_name = libname;
2648 plug->next = plugins;
2650 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2651 if (plug->api == NULL)
2653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2654 _("Failed to load transport plugin for `%s'\n"), name);
2655 GNUNET_free (plug->short_name);
2656 plugins = plug->next;
2657 GNUNET_free (libname);
2664 * Called whenever a client is disconnected. Frees our
2665 * resources associated with that client.
2667 * @param cls closure
2668 * @param client identification of the client
2671 client_disconnect_notification (void *cls,
2672 struct GNUNET_SERVER_Client *client)
2674 struct TransportClient *pos;
2675 struct TransportClient *prev;
2676 struct ClientMessageQueueEntry *mqe;
2679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2680 "Client disconnected, cleaning up.\n");
2684 while ((pos != NULL) && (pos->client != client))
2691 while (NULL != (mqe = pos->message_queue_head))
2693 pos->message_queue_head = mqe->next;
2696 pos->message_queue_head = NULL;
2698 clients = pos->next;
2700 prev->next = pos->next;
2701 if (GNUNET_YES == pos->tcs_pending)
2711 * Initiate transport service.
2713 * @param cls closure
2714 * @param s scheduler to use
2715 * @param serv the initialized server
2716 * @param c configuration to use
2720 struct GNUNET_SCHEDULER_Handle *s,
2721 struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
2726 unsigned long long tneigh;
2731 /* parse configuration */
2733 GNUNET_CONFIGURATION_get_value_number (c,
2738 GNUNET_CONFIGURATION_get_value_filename (c,
2740 "HOSTKEY", &keyfile)))
2742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2744 ("Transport service is lacking key configuration settings. Exiting.\n"));
2745 GNUNET_SCHEDULER_shutdown (s);
2748 max_connect_per_transport = (uint32_t) tneigh;
2749 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2750 GNUNET_free (keyfile);
2751 if (my_private_key == NULL)
2753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2755 ("Transport service could not access hostkey. Exiting.\n"));
2756 GNUNET_SCHEDULER_shutdown (s);
2759 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2760 GNUNET_CRYPTO_hash (&my_public_key,
2761 sizeof (my_public_key), &my_identity.hashPubKey);
2762 /* setup notification */
2764 GNUNET_SERVER_disconnect_notify (server,
2765 &client_disconnect_notification, NULL);
2766 /* load plugins... */
2769 GNUNET_CONFIGURATION_get_value_string (c,
2770 "TRANSPORT", "PLUGINS", &plugs))
2772 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2773 _("Starting transport plugins `%s'\n"), plugs);
2774 pos = strtok (plugs, " ");
2777 start_transport (server, pos);
2779 pos = strtok (NULL, " ");
2781 GNUNET_free (plugs);
2786 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2787 _("Transport service ready.\n"));
2789 /* process client requests */
2790 GNUNET_SERVER_add_handlers (server, handlers);
2795 * Function called when the service shuts
2796 * down. Unloads our plugins.
2798 * @param cls closure
2799 * @param cfg configuration to use
2802 unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
2804 struct TransportPlugin *plug;
2805 struct AddressList *al;
2808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2809 "Transport service is unloading plugins...\n");
2811 while (NULL != (plug = plugins))
2813 plugins = plug->next;
2814 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2815 GNUNET_free (plug->lib_name);
2816 GNUNET_free (plug->short_name);
2817 while (NULL != (al = plug->addresses))
2819 plug->addresses = al->next;
2824 if (my_private_key != NULL)
2825 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2830 * The main function for the transport service.
2832 * @param argc number of arguments from the command line
2833 * @param argv command line arguments
2834 * @return 0 ok, 1 on error
2837 main (int argc, char *const *argv)
2839 return (GNUNET_OK ==
2840 GNUNET_SERVICE_run (argc,
2843 &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
2846 /* end of gnunet-service-transport.c */