2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
27 * - if we do not receive an ACK in response to our
28 * HELLO, retransmit HELLO!
31 #include "gnunet_client_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_getopt_lib.h"
34 #include "gnunet_hello_lib.h"
35 #include "gnunet_os_lib.h"
36 #include "gnunet_peerinfo_service.h"
37 #include "gnunet_plugin_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_service_lib.h"
40 #include "gnunet_signatures.h"
41 #include "plugin_transport.h"
42 #include "transport.h"
45 * How many messages can we have pending for a given client process
46 * before we start to drop incoming messages? We typically should
47 * have only one client and so this would be the primary buffer for
48 * messages, so the number should be chosen rather generously.
50 * The expectation here is that most of the time the queue is large
51 * enough so that a drop is virtually never required.
53 #define MAX_PENDING 128
56 * How often should we try to reconnect to a peer using a particular
57 * transport plugin before giving up? Note that the plugin may be
58 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
60 #define MAX_CONNECT_RETRY 3
63 * How often must a peer violate bandwidth quotas before we start
64 * to simply drop its messages?
66 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
69 * How long until a HELLO verification attempt should time out?
70 * Must be rather small, otherwise a partially successful HELLO
71 * validation (some addresses working) might not be available
72 * before a client's request for a connection fails for good.
73 * Besides, if a single request to an address takes a long time,
74 * then the peer is unlikely worthwhile anyway.
76 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
79 * How often do we re-add (cheaper) plugins to our list of plugins
80 * to try for a given connected peer?
82 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
85 * After how long do we expire an address in a HELLO
86 * that we just validated? This value is also used
87 * for our own addresses when we create a HELLO.
89 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
93 * Entry in linked list of network addresses.
98 * This is a linked list.
100 struct AddressList *next;
103 * The address, actually a pointer to the end
104 * of this struct. Do not free!
109 * How long until we auto-expire this address (unless it is
110 * re-confirmed by the transport)?
112 struct GNUNET_TIME_Absolute expires;
123 * Entry in linked list of all of our plugins.
125 struct TransportPlugin
129 * This is a linked list.
131 struct TransportPlugin *next;
134 * API of the transport as returned by the plugin's
135 * initialization function.
137 struct GNUNET_TRANSPORT_PluginFunctions *api;
140 * Short name for the plugin (i.e. "tcp").
145 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
150 * List of our known addresses for this transport.
152 struct AddressList *addresses;
155 * Environment this transport service is using
158 struct GNUNET_TRANSPORT_PluginEnvironment env;
161 * ID of task that is used to clean up expired addresses.
163 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
167 * Set to GNUNET_YES if we need to scrap the existing
168 * list of "addresses" and start fresh when we receive
169 * the next address update from a transport. Set to
170 * GNUNET_NO if we should just add the new address
171 * to the list and wait for the commit call.
179 * For each neighbor we keep a list of messages
180 * that we still want to transmit to the neighbor.
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 * Neighbor this entry belongs to.
205 struct NeighborList *neighbor;
208 * Plugin that we used for the transmission.
209 * NULL until we scheduled a transmission.
211 struct TransportPlugin *plugin;
214 * Internal message of the transport system that should not be
215 * included in the usual SEND-SEND_OK transmission confirmation
216 * traffic management scheme. Typically, "internal_msg" will
217 * be set whenever "client" is NULL (but it is not strictly
223 * How important is the message?
225 unsigned int priority;
231 * For a given Neighbor, which plugins are available
232 * to talk to this peer and what are their costs?
238 * This is a linked list.
240 struct ReadyList *next;
243 * Which of our transport plugins does this entry
246 struct TransportPlugin *plugin;
249 * Neighbor this entry belongs to.
251 struct NeighborList *neighbor;
254 * What was the last latency observed for this plugin
255 * and peer? Invalid if connected is GNUNET_NO.
257 struct GNUNET_TIME_Relative latency;
260 * If we did not successfully transmit a message to the given peer
261 * via this connection during the specified time, we should consider
262 * the connection to be dead. This is used in the case that a TCP
263 * transport simply stalls writing to the stream but does not
264 * formerly get a signal that the other peer died.
266 struct GNUNET_TIME_Absolute timeout;
269 * Is this plugin currently connected? The first time
270 * we transmit or send data to a peer via a particular
271 * plugin, we set this to GNUNET_YES. If we later get
272 * an error (disconnect notification or transmission
273 * failure), we set it back to GNUNET_NO. Each time the
274 * value is set to GNUNET_YES, we increment the
275 * "connect_attempts" counter. If that one reaches a
276 * particular threshold, we consider the plugin to not
277 * be working properly at this time for the given peer
278 * and remove it from the eligible list.
283 * How often have we tried to connect using this plugin?
285 unsigned int connect_attempts;
288 * Is this plugin ready to transmit to the specific target?
289 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
290 * transmission is in progress, "transmit_ready" is set to
299 * Entry in linked list of all of our current neighbors.
305 * This is a linked list.
307 struct NeighborList *next;
310 * Which of our transports is connected to this peer
311 * and what is their status?
313 struct ReadyList *plugins;
316 * List of messages we would like to send to this peer;
317 * must contain at most one message per client.
319 struct MessageQueue *messages;
322 * Identity of this neighbor.
324 struct GNUNET_PeerIdentity id;
327 * Opaque addr of this peer, only known to the plugin
337 * ID of task scheduled to run when this peer is about to
338 * time out (will free resources associated with the peer).
340 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
343 * How long until we should consider this peer dead
344 * (if we don't receive another message in the
347 struct GNUNET_TIME_Absolute peer_timeout;
350 * At what time did we reset last_received last?
352 struct GNUNET_TIME_Absolute last_quota_update;
355 * At what time should we try to again add plugins to
358 struct GNUNET_TIME_Absolute retry_plugins_time;
361 * How many bytes have we received since the "last_quota_update"
364 uint64_t last_received;
367 * Global quota for inbound traffic for the neighbor in bytes/ms.
372 * How often has the other peer (recently) violated the
373 * inbound traffic limit? Incremented by 10 per violation,
374 * decremented by 1 per non-violation (for each
377 unsigned int quota_violation_count;
380 * Have we seen an ACK from this neighbor in the past?
381 * (used to make up a fake ACK for clients connecting after
382 * the neighbor connected to us).
386 /* The latency we have seen for this particular address for
387 * this particular peer. This latency may have been calculated
388 * over multiple transports. This value reflects how long it took
389 * us to receive a response when SENDING via this particular
390 * transport/neighbor/address combination!
392 struct GNUNET_TIME_RelativeNBO latency;
398 * Linked list of messages to be transmitted to
399 * the client. Each entry is followed by the
402 struct ClientMessageQueueEntry
405 * This is a linked list.
407 struct ClientMessageQueueEntry *next;
412 * Client connected to the transport service.
414 struct TransportClient
418 * This is a linked list.
420 struct TransportClient *next;
423 * Handle to the client.
425 struct GNUNET_SERVER_Client *client;
428 * Linked list of messages yet to be transmitted to
431 struct ClientMessageQueueEntry *message_queue_head;
434 * Tail of linked list of messages yet to be transmitted to the
437 struct ClientMessageQueueEntry *message_queue_tail;
440 * Is a call to "transmit_send_continuation" pending? If so, we
441 * must not free this struct (even if the corresponding client
442 * disconnects) and instead only remove it from the linked list and
443 * set the "client" field to NULL.
448 * Length of the list of messages pending for this client.
450 unsigned int message_count;
456 * For each HELLO, we may have to validate multiple addresses;
457 * each address gets its own request entry.
459 struct ValidationAddress
462 * This is a linked list.
464 struct ValidationAddress *next;
467 * Name of the transport.
469 char *transport_name;
472 * When should this validated address expire?
474 struct GNUNET_TIME_Absolute expiration;
477 * Length of the address we are validating.
482 * Challenge number we used.
487 * Set to GNUNET_YES if the challenge was met,
488 * GNUNET_SYSERR if we know it failed, GNUNET_NO
489 * if we are waiting on a response.
496 * Entry in linked list of all HELLOs awaiting validation.
498 struct ValidationList
502 * This is a linked list.
504 struct ValidationList *next;
507 * Linked list with one entry per address from the HELLO
508 * that needs to be validated.
510 struct ValidationAddress *addresses;
513 * The public key of the peer.
515 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
518 * When does this record time-out? (assuming the
519 * challenge goes unanswered)
521 struct GNUNET_TIME_Absolute timeout;
527 * HELLOs awaiting validation.
529 static struct ValidationList *pending_validations;
534 static struct GNUNET_HELLO_Message *our_hello;
537 * "version" of "our_hello". Used to see if a given
538 * neighbor has already been sent the latest version
539 * of our HELLO message.
541 static unsigned int our_hello_version;
546 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
551 static struct GNUNET_PeerIdentity my_identity;
556 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
561 struct GNUNET_SCHEDULER_Handle *sched;
566 const struct GNUNET_CONFIGURATION_Handle *cfg;
569 * Linked list of all clients to this service.
571 static struct TransportClient *clients;
574 * All loaded plugins.
576 static struct TransportPlugin *plugins;
581 static struct GNUNET_SERVER_Handle *server;
584 * All known neighbors and their HELLOs.
586 static struct NeighborList *neighbors;
589 * Number of neighbors we'd like to have.
591 static uint32_t max_connect_per_transport;
595 * Find an entry in the neighbor list for a particular peer.
596 * if sender_address is not specified (NULL) then return the
597 * first matching entry. If sender_address is specified, then
598 * make sure that the address and address_len also matches.
600 * @return NULL if not found.
602 static struct NeighborList *
603 find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
604 size_t sender_address_len)
606 struct NeighborList *head = neighbors;
607 if (sender_address == NULL)
609 while ((head != NULL) &&
610 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
615 while ((head != NULL) &&
616 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
617 (sender_address_len != head->addr_len) &&
618 (0 != memcmp (sender_address, &head->addr, head->addr_len)))
626 * Find an entry in the transport list for a particular transport.
628 * @return NULL if not found.
630 static struct TransportPlugin *
631 find_transport (const char *short_name)
633 struct TransportPlugin *head = plugins;
634 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
641 * Update the quota values for the given neighbor now.
644 update_quota (struct NeighborList *n)
646 struct GNUNET_TIME_Relative delta;
650 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
651 if (delta.value < MIN_QUOTA_REFRESH_TIME)
652 return; /* not enough time passed for doing quota update */
653 allowed = delta.value * n->quota_in;
654 if (n->last_received < allowed)
656 remaining = allowed - n->last_received;
658 remaining /= n->quota_in;
661 if (remaining > MAX_BANDWIDTH_CARRY)
662 remaining = MAX_BANDWIDTH_CARRY;
663 n->last_received = 0;
664 n->last_quota_update = GNUNET_TIME_absolute_get ();
665 n->last_quota_update.value -= remaining;
666 if (n->quota_violation_count > 0)
667 n->quota_violation_count--;
671 n->last_received -= allowed;
672 n->last_quota_update = GNUNET_TIME_absolute_get ();
673 if (n->last_received > allowed)
675 /* more than twice the allowed rate! */
676 n->quota_violation_count += 10;
683 * Function called to notify a client about the socket
684 * being ready to queue more data. "buf" will be
685 * NULL and "size" zero if the socket was closed for
686 * writing in the meantime.
689 * @param size number of bytes available in buf
690 * @param buf where the callee should write the message
691 * @return number of bytes written to buf
694 transmit_to_client_callback (void *cls, size_t size, void *buf)
696 struct TransportClient *client = cls;
697 struct ClientMessageQueueEntry *q;
700 const struct GNUNET_MessageHeader *msg;
701 struct GNUNET_CONNECTION_TransmitHandle *th;
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "Transmission to client failed, closing connection.\n");
708 /* fatal error with client, free message queue! */
709 while (NULL != (q = client->message_queue_head))
711 client->message_queue_head = q->next;
714 client->message_queue_tail = NULL;
715 client->message_count = 0;
720 while (NULL != (q = client->message_queue_head))
722 msg = (const struct GNUNET_MessageHeader *) &q[1];
723 msize = ntohs (msg->size);
724 if (msize + tsize > size)
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
728 "Transmitting message of type %u to client.\n",
731 client->message_queue_head = q->next;
733 client->message_queue_tail = NULL;
734 memcpy (&cbuf[tsize], msg, msize);
737 client->message_count--;
741 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
742 th = GNUNET_SERVER_notify_transmit_ready (client->client,
744 GNUNET_TIME_UNIT_FOREVER_REL,
745 &transmit_to_client_callback,
747 GNUNET_assert (th != NULL);
754 * Send the specified message to the specified client. Since multiple
755 * messages may be pending for the same client at a time, this code
756 * makes sure that no message is lost.
758 * @param client client to transmit the message to
759 * @param msg the message to send
760 * @param may_drop can this message be dropped if the
761 * message queue for this client is getting far too large?
764 transmit_to_client (struct TransportClient *client,
765 const struct GNUNET_MessageHeader *msg, int may_drop)
767 struct ClientMessageQueueEntry *q;
769 struct GNUNET_CONNECTION_TransmitHandle *th;
771 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
773 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
775 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
776 client->message_count, MAX_PENDING);
777 /* TODO: call to statistics... */
780 client->message_count++;
781 msize = ntohs (msg->size);
782 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
783 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
784 memcpy (&q[1], msg, msize);
785 /* append to message queue */
786 if (client->message_queue_tail == NULL)
788 client->message_queue_tail = q;
792 client->message_queue_tail->next = q;
793 client->message_queue_tail = q;
795 if (client->message_queue_head == NULL)
797 client->message_queue_head = q;
798 th = GNUNET_SERVER_notify_transmit_ready (client->client,
800 GNUNET_TIME_UNIT_FOREVER_REL,
801 &transmit_to_client_callback,
803 GNUNET_assert (th != NULL);
809 * Find alternative plugins for communication.
811 * @param neighbor for which neighbor should we try to find
815 try_alternative_plugins (struct NeighborList *neighbor)
817 struct ReadyList *rl;
819 if ((neighbor->plugins != NULL) &&
820 (neighbor->retry_plugins_time.value >
821 GNUNET_TIME_absolute_get ().value))
822 return; /* don't try right now */
823 neighbor->retry_plugins_time
824 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
826 rl = neighbor->plugins;
829 if (rl->connect_attempts > 0)
830 rl->connect_attempts--; /* amnesty */
838 * The peer specified by the given neighbor has timed-out or a plugin
839 * has disconnected. We may either need to do nothing (other plugins
840 * still up), or trigger a full disconnect and clean up. This
841 * function updates our state and do the necessary notifications.
842 * Also notifies our clients that the neighbor is now officially
845 * @param n the neighbor list entry for the peer
846 * @param check should we just check if all plugins
847 * disconnected or must we ask all plugins to
850 static void disconnect_neighbor (struct NeighborList *n, int check);
854 * Check the ready list for the given neighbor and
855 * if a plugin is ready for transmission (and if we
856 * have a message), do so!
858 * @param neighbor target peer for which to check the plugins
860 static void try_transmission_to_peer (struct NeighborList *neighbor);
864 * Function called by the GNUNET_TRANSPORT_TransmitFunction
865 * upon "completion" of a send request. This tells the API
866 * that it is now legal to send another message to the given
869 * @param cls closure, identifies the entry on the
870 * message queue that was transmitted and the
871 * client responsible for queueing the message
872 * @param target the peer receiving the message
873 * @param result GNUNET_OK on success, if the transmission
874 * failed, we should not tell the client to transmit
878 transmit_send_continuation (void *cls,
879 const struct GNUNET_PeerIdentity *target,
882 struct MessageQueue *mq = cls;
883 struct ReadyList *rl;
884 struct SendOkMessage send_ok_msg;
885 struct NeighborList *n;
887 GNUNET_assert (mq != NULL);
889 GNUNET_assert (n != NULL);
891 memcmp (&n->id, target,
892 sizeof (struct GNUNET_PeerIdentity)));
894 while ((rl != NULL) && (rl->plugin != mq->plugin))
896 GNUNET_assert (rl != NULL);
897 if (result == GNUNET_OK)
900 GNUNET_TIME_relative_to_absolute
901 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906 "Transmission to peer `%s' failed, marking connection as down.\n",
907 GNUNET_i2s (target));
908 rl->connected = GNUNET_NO;
910 if (!mq->internal_msg)
911 rl->transmit_ready = GNUNET_YES;
912 if (mq->client != NULL)
914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915 "Notifying client %p about failed transission to peer `%4s'.\n",
916 mq->client, GNUNET_i2s (target));
917 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
918 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
919 send_ok_msg.success = htonl (result);
920 send_ok_msg.peer = n->id;
921 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
923 GNUNET_free (mq->message);
925 /* one plugin just became ready again, try transmitting
926 another message (if available) */
927 if (result == GNUNET_OK)
928 try_transmission_to_peer (n);
930 disconnect_neighbor (n, GNUNET_YES);
935 * Check the ready list for the given neighbor and
936 * if a plugin is ready for transmission (and if we
937 * have a message), do so!
940 try_transmission_to_peer (struct NeighborList *neighbor)
942 struct ReadyList *pos;
943 struct GNUNET_TIME_Relative min_latency;
944 struct ReadyList *rl;
945 struct MessageQueue *mq;
946 struct GNUNET_TIME_Absolute now;
948 if (neighbor->messages == NULL)
949 return; /* nothing to do */
950 try_alternative_plugins (neighbor);
951 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
953 mq = neighbor->messages;
954 now = GNUNET_TIME_absolute_get ();
955 pos = neighbor->plugins;
958 /* set plugins that are inactive for a long time back to disconnected */
959 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963 "Marking long-time inactive connection to `%4s' as down.\n",
964 GNUNET_i2s (&neighbor->id));
966 pos->connected = GNUNET_NO;
968 if (((GNUNET_YES == pos->transmit_ready) ||
969 (mq->internal_msg)) &&
970 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
971 ((rl == NULL) || (min_latency.value > pos->latency.value)))
974 min_latency = pos->latency;
981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
982 "No plugin ready to transmit message\n");
984 return; /* nobody ready */
986 if (GNUNET_NO == rl->connected)
988 rl->connect_attempts++;
989 rl->connected = GNUNET_YES;
991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
992 "Establishing fresh connection with `%4s' via plugin `%s'\n",
993 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
996 neighbor->messages = mq->next;
997 mq->plugin = rl->plugin;
998 if (!mq->internal_msg)
999 rl->transmit_ready = GNUNET_NO;
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1003 ntohs (mq->message->type),
1004 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1007 rl->plugin->api->send (rl->plugin->api->cls,
1011 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1013 rl->neighbor->addr_len,
1015 &transmit_send_continuation, mq);
1020 * Send the specified message to the specified peer.
1022 * @param client source of the transmission request (can be NULL)
1023 * @param priority how important is the message
1024 * @param msg message to send
1025 * @param is_internal is this an internal message
1026 * @param neighbor handle to the neighbor for transmission
1029 transmit_to_peer (struct TransportClient *client,
1030 unsigned int priority,
1031 const struct GNUNET_MessageHeader *msg,
1032 int is_internal, struct NeighborList *neighbor)
1034 struct MessageQueue *mq;
1035 struct MessageQueue *mqe;
1036 struct GNUNET_MessageHeader *m;
1039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1040 _("Sending message of type %u to peer `%4s'\n"),
1041 ntohs (msg->type), GNUNET_i2s (&neighbor->id));
1045 /* check for duplicate submission */
1046 mq = neighbor->messages;
1049 if (mq->client == client)
1051 /* client transmitted to same peer twice
1052 before getting SendOk! */
1059 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1060 mq->client = client;
1061 m = GNUNET_malloc (ntohs (msg->size));
1062 memcpy (m, msg, ntohs (msg->size));
1064 mq->neighbor = neighbor;
1065 mq->internal_msg = is_internal;
1066 mq->priority = priority;
1069 mqe = neighbor->messages;
1071 while (mqe->next != NULL)
1076 neighbor->messages = mq;
1077 try_transmission_to_peer (neighbor);
1090 struct GeneratorContext
1092 struct TransportPlugin *plug_pos;
1093 struct AddressList *addr_pos;
1094 struct GNUNET_TIME_Absolute expiration;
1102 address_generator (void *cls, size_t max, void *buf)
1104 struct GeneratorContext *gc = cls;
1107 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1109 gc->plug_pos = gc->plug_pos->next;
1110 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1112 if (NULL == gc->plug_pos)
1114 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1117 gc->addr_pos->addrlen, buf, max);
1118 gc->addr_pos = gc->addr_pos->next;
1124 * Construct our HELLO message from all of the addresses of
1125 * all of the transports.
1130 struct GNUNET_HELLO_Message *hello;
1131 struct TransportClient *cpos;
1132 struct NeighborList *npos;
1133 struct GeneratorContext gc;
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1137 "Refreshing my `%s'\n", "HELLO");
1139 gc.plug_pos = plugins;
1140 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1141 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1142 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1144 while (cpos != NULL)
1146 transmit_to_client (cpos,
1147 (const struct GNUNET_MessageHeader *) hello,
1152 GNUNET_free_non_null (our_hello);
1154 our_hello_version++;
1155 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1157 while (npos != NULL)
1160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1161 "Transmitting updated `%s' to neighbor `%4s'\n",
1162 "HELLO", GNUNET_i2s (&npos->id));
1164 transmit_to_peer (NULL, 0,
1165 (const struct GNUNET_MessageHeader *) our_hello,
1173 * Task used to clean up expired addresses for a plugin.
1175 * @param cls closure
1179 expire_address_task (void *cls,
1180 const struct GNUNET_SCHEDULER_TaskContext *tc);
1184 * Update the list of addresses for this plugin,
1185 * expiring those that are past their expiration date.
1187 * @param plugin addresses of which plugin should be recomputed?
1188 * @param fresh set to GNUNET_YES if a new address was added
1189 * and we need to regenerate the HELLO even if nobody
1193 update_addresses (struct TransportPlugin *plugin, int fresh)
1195 struct GNUNET_TIME_Relative min_remaining;
1196 struct GNUNET_TIME_Relative remaining;
1197 struct GNUNET_TIME_Absolute now;
1198 struct AddressList *pos;
1199 struct AddressList *prev;
1200 struct AddressList *next;
1203 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1204 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1205 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1206 now = GNUNET_TIME_absolute_get ();
1207 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1208 expired = GNUNET_NO;
1210 pos = plugin->addresses;
1214 if (pos->expires.value < now.value)
1216 expired = GNUNET_YES;
1218 plugin->addresses = pos->next;
1220 prev->next = pos->next;
1225 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1226 if (remaining.value < min_remaining.value)
1227 min_remaining = remaining;
1233 if (expired || fresh)
1235 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1236 plugin->address_update_task
1237 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1239 &expire_address_task, plugin);
1245 * Task used to clean up expired addresses for a plugin.
1247 * @param cls closure
1251 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1253 struct TransportPlugin *plugin = cls;
1254 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1255 update_addresses (plugin, GNUNET_NO);
1260 * Function that must be called by each plugin to notify the
1261 * transport service about the addresses under which the transport
1262 * provided by the plugin can be reached.
1264 * @param cls closure
1265 * @param name name of the transport that generated the address
1266 * @param addr one of the addresses of the host, NULL for the last address
1267 * the specific address format depends on the transport
1268 * @param addrlen length of the address
1269 * @param expires when should this address automatically expire?
1272 plugin_env_notify_address (void *cls,
1276 struct GNUNET_TIME_Relative expires)
1278 struct TransportPlugin *p = cls;
1279 struct AddressList *al;
1280 struct GNUNET_TIME_Absolute abex;
1282 abex = GNUNET_TIME_relative_to_absolute (expires);
1283 GNUNET_assert (p == find_transport (name));
1288 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1290 if (al->expires.value < abex.value)
1297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1298 "Plugin `%s' informs us about a new address `%s'\n", name,
1299 GNUNET_a2s (addr, addrlen));
1301 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1303 al->next = p->addresses;
1306 al->addrlen = addrlen;
1307 memcpy (&al[1], addr, addrlen);
1308 update_addresses (p, GNUNET_YES);
1313 * Notify all of our clients about a peer connecting.
1316 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1317 struct GNUNET_TIME_Relative latency)
1319 struct ConnectInfoMessage cim;
1320 struct TransportClient *cpos;
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "Informing clients about peer `%4s' connecting to us\n",
1327 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1328 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1329 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1330 cim.latency = GNUNET_TIME_relative_hton (latency);
1331 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1333 while (cpos != NULL)
1335 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1342 * Notify all of our clients about a peer disconnecting.
1345 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1347 struct DisconnectInfoMessage dim;
1348 struct TransportClient *cpos;
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1352 "Informing clients about peer `%4s' disconnecting\n",
1355 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1356 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1357 dim.reserved = htonl (0);
1358 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1360 while (cpos != NULL)
1362 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1369 * Copy any validated addresses to buf.
1371 * @return 0 once all addresses have been
1375 list_validated_addresses (void *cls, size_t max, void *buf)
1377 struct ValidationAddress **va = cls;
1380 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1384 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1386 &(*va)[1], (*va)->addr_len, buf, max);
1393 * HELLO validation cleanup task.
1396 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1398 struct ValidationAddress *va;
1399 struct ValidationList *pos;
1400 struct ValidationList *prev;
1401 struct GNUNET_TIME_Absolute now;
1402 struct GNUNET_TIME_Absolute first;
1403 struct GNUNET_HELLO_Message *hello;
1404 struct GNUNET_PeerIdentity pid;
1405 struct NeighborList *n;
1408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1409 "HELLO validation cleanup background task running...\n");
1411 now = GNUNET_TIME_absolute_get ();
1413 pos = pending_validations;
1416 if (pos->timeout.value < now.value)
1419 pending_validations = pos->next;
1421 prev->next = pos->next;
1422 va = pos->addresses;
1423 hello = GNUNET_HELLO_create (&pos->publicKey,
1424 &list_validated_addresses, &va);
1425 GNUNET_CRYPTO_hash (&pos->publicKey,
1427 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1431 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1432 "HELLO", GNUNET_i2s (&pid));
1434 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1435 n = find_neighbor (&pid, NULL, 0);
1437 try_transmission_to_peer (n);
1438 GNUNET_free (hello);
1439 while (NULL != (va = pos->addresses))
1441 pos->addresses = va->next;
1442 GNUNET_free (va->transport_name);
1447 pos = pending_validations;
1456 /* finally, reschedule cleanup if needed; list is
1457 ordered by timeout, so we need the last element... */
1458 if (NULL != pending_validations)
1460 first = pending_validations->timeout;
1461 pos = pending_validations;
1464 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1467 GNUNET_SCHEDULER_add_delayed (sched,
1468 GNUNET_TIME_absolute_get_remaining
1469 (first), &cleanup_validation, NULL);
1477 * Function that will be called if we receive a validation
1478 * of an address challenge that we transmitted to another
1479 * peer. Note that the validation should only be considered
1480 * acceptable if the challenge matches AND if the sender
1481 * address is at least a plausible address for this peer
1482 * (otherwise we may be seeing a MiM attack).
1484 * @param cls closure
1485 * @param name name of the transport that generated the address
1486 * @param peer who responded to our challenge
1487 * @param challenge the challenge number we presumably used
1488 * @param sender_addr string describing our sender address (as observed
1489 * by the other peer in human-readable format)
1492 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1493 const struct GNUNET_PeerIdentity *peer,
1494 const char *sender_address,
1495 size_t sender_address_len)
1497 unsigned int not_done;
1499 struct ValidationList *pos;
1500 struct ValidationAddress *va;
1501 struct GNUNET_PeerIdentity id;
1503 int challenge = 1; /* FIXME: Pull this number out of the PONG message */
1504 pos = pending_validations;
1507 GNUNET_CRYPTO_hash (&pos->publicKey,
1509 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1511 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1517 /* TODO: call statistics (unmatched PONG) */
1518 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1520 ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
1525 matched = GNUNET_NO;
1526 va = pos->addresses;
1529 if (va->challenge == challenge)
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1533 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1535 GNUNET_a2s ((const struct sockaddr *) &va[1],
1538 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1540 ("Another peer saw us using the address `%s' via `FIXME'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1542 va->ok = GNUNET_YES;
1544 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1545 matched = GNUNET_YES;
1547 if (va->ok != GNUNET_YES)
1551 if (GNUNET_NO == matched)
1553 /* TODO: call statistics (unmatched PONG) */
1554 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1556 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563 "All addresses validated, will now construct `%s' for `%4s'.\n",
1564 "HELLO", GNUNET_i2s (peer));
1566 pos->timeout.value = 0;
1567 GNUNET_SCHEDULER_add_with_priority (sched,
1568 GNUNET_SCHEDULER_PRIORITY_IDLE,
1569 &cleanup_validation, NULL);
1574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1576 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1582 struct CheckHelloValidatedContext
1585 * Plugin for which we are validating.
1587 struct TransportPlugin *plugin;
1590 * Hello that we are validating.
1592 struct GNUNET_HELLO_Message *hello;
1595 * Validation list being build.
1597 struct ValidationList *e;
1600 * Context for peerinfo iteration.
1601 * NULL after we are done processing peerinfo's information.
1603 struct GNUNET_PEERINFO_IteratorContext *piter;
1609 * Append the given address to the list of entries
1610 * that need to be validated.
1613 run_validation (void *cls,
1615 struct GNUNET_TIME_Absolute expiration,
1616 const void *addr, size_t addrlen)
1618 struct ValidationList *e = cls;
1619 struct TransportPlugin *tp;
1620 struct ValidationAddress *va;
1621 struct GNUNET_PeerIdentity id;
1623 tp = find_transport (tname);
1626 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1627 GNUNET_ERROR_TYPE_BULK,
1629 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1633 GNUNET_CRYPTO_hash (&e->publicKey,
1635 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1638 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1639 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1641 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1642 va->next = e->addresses;
1644 va->transport_name = GNUNET_strdup (tname);
1645 va->addr_len = addrlen;
1646 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1648 memcpy (&va[1], addr, addrlen);
1653 * @param cls handle to the plugin (for sending)
1654 * @param target the peer identity of the peer we are sending to
1655 * @param challenge the challenge number
1656 * @param timeout how long to await validation?
1657 * @param addr the address to validate
1658 * @param addrlen the length of the address
1660 * Perform address validation, which means sending a PING PONG to
1661 * the address via the transport plugin. If not validated, then
1662 * do not count this as a good peer/address...
1666 validate_address (void *cls, struct ValidationAddress *va,
1667 const struct GNUNET_PeerIdentity *target,
1668 struct GNUNET_TIME_Relative timeout,
1669 const void *addr, size_t addrlen)
1671 /* struct Plugin *plugin = cls;
1672 int challenge = va->challenge; */
1680 * Check if addresses in validated hello "h" overlap with
1681 * those in "chvc->hello" and update "chvc->hello" accordingly,
1682 * removing those addresses that have already been validated.
1685 check_hello_validated (void *cls,
1686 const struct GNUNET_PeerIdentity *peer,
1687 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1689 struct CheckHelloValidatedContext *chvc = cls;
1690 struct ValidationAddress *va;
1691 struct TransportPlugin *tp;
1693 struct GNUNET_PeerIdentity apeer;
1695 first_call = GNUNET_NO;
1696 if (chvc->e == NULL)
1699 first_call = GNUNET_YES;
1700 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1701 GNUNET_assert (GNUNET_OK ==
1702 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1703 &chvc->e->publicKey));
1705 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1706 chvc->e->next = pending_validations;
1707 pending_validations = chvc->e;
1711 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1713 GNUNET_TIME_absolute_get (),
1714 &run_validation, chvc->e);
1716 else if (GNUNET_YES == first_call)
1718 /* no existing HELLO, all addresses are new */
1719 GNUNET_HELLO_iterate_addresses (chvc->hello,
1720 GNUNET_NO, &run_validation, chvc->e);
1723 return; /* wait for next call */
1724 /* finally, transmit validation attempts */
1725 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1728 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1729 "HELLO", GNUNET_i2s (&apeer));
1731 va = chvc->e->addresses;
1735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1736 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1739 GNUNET_a2s ((const struct sockaddr *) &va[1],
1740 va->addr_len), GNUNET_i2s (&apeer));
1742 tp = find_transport (va->transport_name);
1743 GNUNET_assert (tp != NULL);
1744 /* This validation should happen inside the transport, not from the plugin! */
1745 validate_address (tp->api->cls, va, &apeer,
1746 HELLO_VERIFICATION_TIMEOUT,
1747 &va[1], va->addr_len);
1748 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1751 GNUNET_SCHEDULER_add_delayed (sched,
1752 GNUNET_TIME_absolute_get_remaining (chvc->
1754 &cleanup_validation, NULL);
1760 * Process HELLO-message.
1762 * @param plugin transport involved, may be NULL
1763 * @param message the actual message
1764 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1767 process_hello (struct TransportPlugin *plugin,
1768 const struct GNUNET_MessageHeader *message)
1770 struct ValidationList *e;
1772 struct GNUNET_PeerIdentity target;
1773 const struct GNUNET_HELLO_Message *hello;
1774 struct CheckHelloValidatedContext *chvc;
1775 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1777 hsize = ntohs (message->size);
1778 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1779 (hsize < sizeof (struct GNUNET_MessageHeader)))
1782 return GNUNET_SYSERR;
1784 /* first, check if load is too high */
1785 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1787 /* TODO: call to stats? */
1790 hello = (const struct GNUNET_HELLO_Message *) message;
1791 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1793 GNUNET_break_op (0);
1794 return GNUNET_SYSERR;
1796 GNUNET_CRYPTO_hash (&publicKey,
1797 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1798 &target.hashPubKey);
1800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1801 "Processing `%s' message for `%4s'\n",
1802 "HELLO", GNUNET_i2s (&target));
1804 /* check if a HELLO for this peer is already on the validation list */
1805 e = pending_validations;
1808 if (0 == memcmp (&e->publicKey,
1811 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1813 /* TODO: call to stats? */
1815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1816 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1817 "HELLO", GNUNET_i2s (&target));
1823 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1824 chvc->plugin = plugin;
1825 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1826 memcpy (chvc->hello, hello, hsize);
1827 /* finally, check if HELLO was previously validated
1828 (continuation will then schedule actual validation) */
1829 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1833 HELLO_VERIFICATION_TIMEOUT,
1834 &check_hello_validated, chvc);
1840 * The peer specified by the given neighbor has timed-out or a plugin
1841 * has disconnected. We may either need to do nothing (other plugins
1842 * still up), or trigger a full disconnect and clean up. This
1843 * function updates our state and do the necessary notifications.
1844 * Also notifies our clients that the neighbor is now officially
1847 * @param n the neighbor list entry for the peer
1848 * @param check should we just check if all plugins
1849 * disconnected or must we ask all plugins to
1853 disconnect_neighbor (struct NeighborList *n, int check)
1855 struct ReadyList *rpos;
1856 struct NeighborList *npos;
1857 struct NeighborList *nprev;
1858 struct MessageQueue *mq;
1860 if (GNUNET_YES == check)
1863 while (NULL != rpos)
1865 if (GNUNET_YES == rpos->connected)
1866 return; /* still connected */
1872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1873 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
1875 /* remove n from neighbors list */
1878 while ((npos != NULL) && (npos != n))
1883 GNUNET_assert (npos != NULL);
1885 neighbors = n->next;
1887 nprev->next = n->next;
1889 /* notify all clients about disconnect */
1890 notify_clients_disconnect (&n->id);
1892 /* clean up all plugins, cancel connections and pending transmissions */
1893 while (NULL != (rpos = n->plugins))
1895 n->plugins = rpos->next;
1896 GNUNET_assert (rpos->neighbor == n);
1897 if (GNUNET_YES == rpos->connected)
1898 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
1902 /* free all messages on the queue */
1903 while (NULL != (mq = n->messages))
1905 n->messages = mq->next;
1906 GNUNET_assert (mq->neighbor == n);
1909 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1910 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
1911 /* finally, free n itself */
1917 * Add an entry for each of our transport plugins
1918 * (that are able to send) to the list of plugins
1919 * for this neighbor.
1921 * @param neighbor to initialize
1924 add_plugins (struct NeighborList *neighbor)
1926 struct TransportPlugin *tp;
1927 struct ReadyList *rl;
1929 neighbor->retry_plugins_time
1930 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1934 if (tp->api->send != NULL)
1936 rl = GNUNET_malloc (sizeof (struct ReadyList));
1937 rl->next = neighbor->plugins;
1938 neighbor->plugins = rl;
1940 rl->neighbor = neighbor;
1941 rl->transmit_ready = GNUNET_YES;
1949 neighbor_timeout_task (void *cls,
1950 const struct GNUNET_SCHEDULER_TaskContext *tc)
1952 struct NeighborList *n = cls;
1955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1956 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1958 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1959 disconnect_neighbor (n, GNUNET_NO);
1964 * Create a fresh entry in our neighbor list for the given peer.
1965 * Will try to transmit our current HELLO to the new neighbor. Also
1966 * notifies our clients about the new "connection".
1968 * @param peer the peer for which we create the entry
1969 * @return the new neighbor list entry
1971 static struct NeighborList *
1972 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
1974 struct NeighborList *n;
1977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1978 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
1981 GNUNET_assert (our_hello != NULL);
1982 n = GNUNET_malloc (sizeof (struct NeighborList));
1983 n->next = neighbors;
1986 n->last_quota_update = GNUNET_TIME_absolute_get ();
1988 GNUNET_TIME_relative_to_absolute
1989 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1990 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1992 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1993 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1994 &neighbor_timeout_task, n);
1995 transmit_to_peer (NULL, 0,
1996 (const struct GNUNET_MessageHeader *) our_hello,
1998 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2003 * We have received a PING message from someone. Need to send a PONG message
2004 * in response to the peer by any means necessary. Of course, with something
2005 * like TCP where a connection exists, we may want to send it that way. But
2006 * we may not be able to make that distinction...
2008 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2009 const struct GNUNET_PeerIdentity *peer,
2010 const char *sender_address,
2011 size_t sender_address_len)
2018 * Function called by the plugin for each received message.
2019 * Update data volumes, possibly notify plugins about
2020 * reducing the rate at which they read from the socket
2021 * and generally forward to our receive callback.
2023 * @param cls the "struct TransportPlugin *" we gave to the plugin
2024 * @param message the message, NULL if peer was disconnected
2025 * @param distance the transport cost to this peer (not latency!)
2026 * @param sender_address the address that the sender reported
2027 * (opaque to transport service)
2028 * @param sender_address_len the length of the sender address
2029 * @param peer (claimed) identity of the other peer
2030 * @return the new service_context that the plugin should use
2031 * for future receive calls for messages from this
2036 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2037 const struct GNUNET_MessageHeader *message,
2038 unsigned int distance, const char *sender_address,
2039 size_t sender_address_len)
2041 const struct GNUNET_MessageHeader ack = {
2042 htons (sizeof (struct GNUNET_MessageHeader)),
2043 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2045 struct ReadyList *service_context;
2046 struct TransportPlugin *plugin = cls;
2047 struct TransportClient *cpos;
2048 struct InboundMessage *im;
2050 struct NeighborList *n;
2052 n = find_neighbor (peer, sender_address, sender_address_len);
2055 if (message == NULL)
2056 return; /* disconnect of peer already marked down */
2057 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2059 service_context = n->plugins;
2060 while ((service_context != NULL) && (plugin != service_context->plugin))
2061 service_context = service_context->next;
2062 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2063 if (message == NULL)
2066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2067 "Receive failed from `%4s', triggering disconnect\n",
2068 GNUNET_i2s (&n->id));
2070 /* TODO: call stats */
2071 if (service_context != NULL)
2072 service_context->connected = GNUNET_NO;
2073 disconnect_neighbor (n, GNUNET_YES);
2077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2078 "Processing message of type `%u' received by plugin...\n",
2079 ntohs (message->type));
2081 if (service_context != NULL)
2083 if (service_context->connected == GNUNET_NO)
2085 service_context->connected = GNUNET_YES;
2086 service_context->transmit_ready = GNUNET_YES;
2087 service_context->connect_attempts++;
2089 service_context->timeout
2091 GNUNET_TIME_relative_to_absolute
2092 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2093 /* service_context->latency = latency; */ /* This value should be set by us! */
2095 /* update traffic received amount ... */
2096 msize = ntohs (message->size);
2097 n->last_received += msize;
2098 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2100 GNUNET_TIME_relative_to_absolute
2101 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2103 GNUNET_SCHEDULER_add_delayed (sched,
2104 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2105 &neighbor_timeout_task, n);
2107 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2109 /* dropping message due to frequent inbound volume violations! */
2110 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2111 GNUNET_ERROR_TYPE_BULK,
2113 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2114 /* TODO: call stats */
2115 GNUNET_assert ((service_context == NULL) ||
2116 (NULL != service_context->neighbor));
2119 switch (ntohs (message->type))
2121 case GNUNET_MESSAGE_TYPE_HELLO:
2123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2124 "Receiving `%s' message from `%4s'.\n", "HELLO",
2127 process_hello (plugin, message);
2129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2130 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2133 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2135 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2136 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2137 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2138 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2139 //plugin_env_notify_validation();
2140 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2141 n->saw_ack = GNUNET_YES;
2142 /* intentional fall-through! */
2145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2146 "Received message of type %u from `%4s', sending to all clients.\n",
2147 ntohs (message->type), GNUNET_i2s (peer));
2149 /* transmit message to all clients */
2150 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2151 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2152 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2153 im->latency = n->latency;
2155 memcpy (&im[1], message, msize);
2158 while (cpos != NULL)
2160 transmit_to_client (cpos, &im->header, GNUNET_YES);
2165 GNUNET_assert ((service_context == NULL) ||
2166 (NULL != service_context->neighbor));
2171 * Handle START-message. This is the first message sent to us
2172 * by any client which causes us to add it to our list.
2174 * @param cls closure (always NULL)
2175 * @param client identification of the client
2176 * @param message the actual message
2179 handle_start (void *cls,
2180 struct GNUNET_SERVER_Client *client,
2181 const struct GNUNET_MessageHeader *message)
2183 struct TransportClient *c;
2184 struct ConnectInfoMessage cim;
2185 struct NeighborList *n;
2186 struct InboundMessage *im;
2187 struct GNUNET_MessageHeader *ack;
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191 "Received `%s' request from client\n", "START");
2196 if (c->client == client)
2198 /* client already on our list! */
2200 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2205 c = GNUNET_malloc (sizeof (struct TransportClient));
2209 if (our_hello != NULL)
2212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2213 "Sending our own `%s' to new client\n", "HELLO");
2215 transmit_to_client (c,
2216 (const struct GNUNET_MessageHeader *) our_hello,
2218 /* tell new client about all existing connections */
2219 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2220 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2222 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2223 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2224 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2225 sizeof (struct GNUNET_MessageHeader));
2226 im->header.size = htons (sizeof (struct InboundMessage) +
2227 sizeof (struct GNUNET_MessageHeader));
2228 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2229 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2230 ack = (struct GNUNET_MessageHeader *) &im[1];
2231 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2232 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2233 for (n = neighbors; n != NULL; n = n->next)
2236 transmit_to_client (c, &cim.header, GNUNET_NO);
2240 transmit_to_client (c, &im->header, GNUNET_NO);
2245 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2250 * Handle HELLO-message.
2252 * @param cls closure (always NULL)
2253 * @param client identification of the client
2254 * @param message the actual message
2257 handle_hello (void *cls,
2258 struct GNUNET_SERVER_Client *client,
2259 const struct GNUNET_MessageHeader *message)
2264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2265 "Received `%s' request from client\n", "HELLO");
2267 ret = process_hello (NULL, message);
2268 GNUNET_SERVER_receive_done (client, ret);
2273 * Handle SEND-message.
2275 * @param cls closure (always NULL)
2276 * @param client identification of the client
2277 * @param message the actual message
2280 handle_send (void *cls,
2281 struct GNUNET_SERVER_Client *client,
2282 const struct GNUNET_MessageHeader *message)
2284 struct TransportClient *tc;
2285 struct NeighborList *n;
2286 const struct OutboundMessage *obm;
2287 const struct GNUNET_MessageHeader *obmm;
2291 size = ntohs (message->size);
2293 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2296 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2299 obm = (const struct OutboundMessage *) message;
2301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2302 "Received `%s' request from client with target `%4s'\n",
2303 "SEND", GNUNET_i2s (&obm->peer));
2305 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2306 msize = ntohs (obmm->size);
2307 if (size != msize + sizeof (struct OutboundMessage))
2310 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2313 n = find_neighbor (&obm->peer, NULL, 0);
2315 n = setup_new_neighbor (&obm->peer, NULL, 0);
2317 while ((tc != NULL) && (tc->client != client))
2321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2322 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2324 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2326 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2327 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2332 * Handle SET_QUOTA-message.
2334 * @param cls closure (always NULL)
2335 * @param client identification of the client
2336 * @param message the actual message
2339 handle_set_quota (void *cls,
2340 struct GNUNET_SERVER_Client *client,
2341 const struct GNUNET_MessageHeader *message)
2343 const struct QuotaSetMessage *qsm =
2344 (const struct QuotaSetMessage *) message;
2345 struct NeighborList *n;
2346 struct TransportPlugin *p;
2347 struct ReadyList *rl;
2350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2351 "Received `%s' request from client for peer `%4s'\n",
2352 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2354 n = find_neighbor (&qsm->peer, NULL, 0);
2357 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2361 if (n->quota_in < ntohl (qsm->quota_in))
2362 n->last_quota_update = GNUNET_TIME_absolute_get ();
2363 n->quota_in = ntohl (qsm->quota_in);
2368 p->api->set_receive_quota (p->api->cls,
2369 &qsm->peer, ntohl (qsm->quota_in));
2372 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2377 * Handle TRY_CONNECT-message.
2379 * @param cls closure (always NULL)
2380 * @param client identification of the client
2381 * @param message the actual message
2384 handle_try_connect (void *cls,
2385 struct GNUNET_SERVER_Client *client,
2386 const struct GNUNET_MessageHeader *message)
2388 const struct TryConnectMessage *tcm;
2390 tcm = (const struct TryConnectMessage *) message;
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393 "Received `%s' request from client %p asking to connect to `%4s'\n",
2394 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2396 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2397 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2398 knowing its address? Should we ask the plugin
2399 for more information about this peer? I don't
2400 think we can... Or set up new peer should only
2401 happen when transport notifies us of an address,
2402 and this setup should check for an address in
2403 the existing list only */
2406 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2407 "Client asked to connect to `%4s', but connection already exists\n",
2408 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2410 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2414 transmit_address_to_client (void *cls, const char *address)
2416 struct GNUNET_SERVER_TransmitContext *tc = cls;
2419 if (NULL == address)
2422 slen = strlen (address) + 1;
2423 GNUNET_SERVER_transmit_context_append (tc, address, slen,
2424 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2425 if (NULL == address)
2426 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2430 * Handle AddressLookup-message.
2432 * @param cls closure (always NULL)
2433 * @param client identification of the client
2434 * @param message the actual message
2437 handle_address_lookup (void *cls,
2438 struct GNUNET_SERVER_Client *client,
2439 const struct GNUNET_MessageHeader *message)
2441 const struct AddressLookupMessage *alum;
2442 struct TransportPlugin *lsPlugin;
2443 const char *nameTransport;
2444 const char *address;
2446 struct GNUNET_SERVER_TransmitContext *tc;
2448 size = ntohs (message->size);
2449 if (size < sizeof (struct AddressLookupMessage))
2451 GNUNET_break_op (0);
2452 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2455 alum = (const struct AddressLookupMessage *) message;
2456 uint32_t addressLen = ntohl (alum->addrlen);
2457 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2459 GNUNET_break_op (0);
2460 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2463 address = (const char *) &alum[1];
2464 nameTransport = (const char *) &address[addressLen];
2466 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2468 GNUNET_break_op (0);
2469 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2472 struct GNUNET_TIME_Absolute timeout =
2473 GNUNET_TIME_absolute_ntoh (alum->timeout);
2474 struct GNUNET_TIME_Relative rtimeout =
2475 GNUNET_TIME_absolute_get_remaining (timeout);
2476 lsPlugin = find_transport (nameTransport);
2477 if (NULL == lsPlugin)
2479 tc = GNUNET_SERVER_transmit_context_create (client);
2480 GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
2481 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2482 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2485 tc = GNUNET_SERVER_transmit_context_create (client);
2486 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2487 address, addressLen, GNUNET_YES,
2489 &transmit_address_to_client, tc);
2493 * List of handlers for the messages understood by this
2496 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2497 {&handle_start, NULL,
2498 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2499 {&handle_hello, NULL,
2500 GNUNET_MESSAGE_TYPE_HELLO, 0},
2501 {&handle_send, NULL,
2502 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2503 {&handle_set_quota, NULL,
2504 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2505 {&handle_try_connect, NULL,
2506 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2507 sizeof (struct TryConnectMessage)},
2508 {&handle_address_lookup, NULL,
2509 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2516 * Setup the environment for this plugin.
2519 create_environment (struct TransportPlugin *plug)
2521 plug->env.cfg = cfg;
2522 plug->env.sched = sched;
2523 plug->env.my_identity = &my_identity;
2524 plug->env.cls = plug;
2525 plug->env.receive = &plugin_env_receive;
2526 plug->env.notify_address = &plugin_env_notify_address;
2527 plug->env.default_quota_in =
2528 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2529 plug->env.max_connections = max_connect_per_transport;
2534 * Start the specified transport (load the plugin).
2537 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2539 struct TransportPlugin *plug;
2542 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2543 _("Loading `%s' transport plugin\n"), name);
2544 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2545 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2546 create_environment (plug);
2547 plug->short_name = GNUNET_strdup (name);
2548 plug->lib_name = libname;
2549 plug->next = plugins;
2551 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2552 if (plug->api == NULL)
2554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2555 _("Failed to load transport plugin for `%s'\n"), name);
2556 GNUNET_free (plug->short_name);
2557 plugins = plug->next;
2558 GNUNET_free (libname);
2565 * Called whenever a client is disconnected. Frees our
2566 * resources associated with that client.
2568 * @param cls closure
2569 * @param client identification of the client
2572 client_disconnect_notification (void *cls,
2573 struct GNUNET_SERVER_Client *client)
2575 struct TransportClient *pos;
2576 struct TransportClient *prev;
2577 struct ClientMessageQueueEntry *mqe;
2580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2581 "Client disconnected, cleaning up.\n");
2585 while ((pos != NULL) && (pos->client != client))
2592 while (NULL != (mqe = pos->message_queue_head))
2594 pos->message_queue_head = mqe->next;
2597 pos->message_queue_head = NULL;
2599 clients = pos->next;
2601 prev->next = pos->next;
2602 if (GNUNET_YES == pos->tcs_pending)
2612 * Function called when the service shuts down. Unloads our plugins.
2614 * @param cls closure, unused
2615 * @param tc task context (unused)
2618 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2620 struct TransportPlugin *plug;
2621 struct AddressList *al;
2624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2625 "Transport service is unloading plugins...\n");
2627 while (NULL != (plug = plugins))
2629 plugins = plug->next;
2630 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2631 GNUNET_free (plug->lib_name);
2632 GNUNET_free (plug->short_name);
2633 while (NULL != (al = plug->addresses))
2635 plug->addresses = al->next;
2640 if (my_private_key != NULL)
2641 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2642 GNUNET_free_non_null (our_hello);
2647 * Initiate transport service.
2649 * @param cls closure
2650 * @param s scheduler to use
2651 * @param serv the initialized server
2652 * @param c configuration to use
2656 struct GNUNET_SCHEDULER_Handle *s,
2657 struct GNUNET_SERVER_Handle *serv,
2658 const struct GNUNET_CONFIGURATION_Handle *c)
2663 unsigned long long tneigh;
2668 /* parse configuration */
2670 GNUNET_CONFIGURATION_get_value_number (c,
2675 GNUNET_CONFIGURATION_get_value_filename (c,
2677 "HOSTKEY", &keyfile)))
2679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2681 ("Transport service is lacking key configuration settings. Exiting.\n"));
2682 GNUNET_SCHEDULER_shutdown (s);
2685 max_connect_per_transport = (uint32_t) tneigh;
2686 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2687 GNUNET_free (keyfile);
2688 if (my_private_key == NULL)
2690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2692 ("Transport service could not access hostkey. Exiting.\n"));
2693 GNUNET_SCHEDULER_shutdown (s);
2696 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2697 GNUNET_CRYPTO_hash (&my_public_key,
2698 sizeof (my_public_key), &my_identity.hashPubKey);
2699 /* setup notification */
2701 GNUNET_SERVER_disconnect_notify (server,
2702 &client_disconnect_notification, NULL);
2703 /* load plugins... */
2706 GNUNET_CONFIGURATION_get_value_string (c,
2707 "TRANSPORT", "PLUGINS", &plugs))
2709 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2710 _("Starting transport plugins `%s'\n"), plugs);
2711 pos = strtok (plugs, " ");
2714 start_transport (server, pos);
2716 pos = strtok (NULL, " ");
2718 GNUNET_free (plugs);
2720 GNUNET_SCHEDULER_add_delayed (sched,
2721 GNUNET_TIME_UNIT_FOREVER_REL,
2722 &unload_plugins, NULL);
2726 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2728 /* process client requests */
2729 GNUNET_SERVER_add_handlers (server, handlers);
2734 * The main function for the transport service.
2736 * @param argc number of arguments from the command line
2737 * @param argv command line arguments
2738 * @return 0 ok, 1 on error
2741 main (int argc, char *const *argv)
2743 return (GNUNET_OK ==
2744 GNUNET_SERVICE_run (argc,
2747 GNUNET_SERVICE_OPTION_NONE,
2748 &run, NULL)) ? 0 : 1;
2751 /* end of gnunet-service-transport.c */