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;
397 * Message used to ask a peer to validate receipt (to check an address
398 * from a HELLO). Followed by the address used. Note that the
399 * recipients response does not affirm that he has this address,
400 * only that he got the challenge message.
402 struct TransportPingMessage
406 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
408 struct GNUNET_MessageHeader header;
411 * Random challenge number (in network byte order).
413 uint32_t challenge GNUNET_PACKED;
416 * Who is the intended recipient?
418 struct GNUNET_PeerIdentity target;
424 * Message used to validate a HELLO. The challenge is included in the
425 * confirmation to make matching of replies to requests possible. The
426 * signature signs the original challenge number, our public key, the
427 * sender's address (so that the sender can check that the address we
428 * saw is plausible for him and possibly detect a MiM attack) and a
429 * timestamp (to limit replay).<p>
431 * This message is followed by the address of the
432 * client that we are observing (which is part of what
435 struct TransportPongMessage
439 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
441 struct GNUNET_MessageHeader header;
444 * For padding, always zero.
446 uint32_t reserved GNUNET_PACKED;
451 struct GNUNET_CRYPTO_RsaSignature signature;
454 * What are we signing and why?
456 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
459 * Random challenge number (in network byte order).
461 uint32_t challenge GNUNET_PACKED;
464 * Who signed this message?
466 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
471 * Linked list of messages to be transmitted to
472 * the client. Each entry is followed by the
475 struct ClientMessageQueueEntry
478 * This is a linked list.
480 struct ClientMessageQueueEntry *next;
485 * Client connected to the transport service.
487 struct TransportClient
491 * This is a linked list.
493 struct TransportClient *next;
496 * Handle to the client.
498 struct GNUNET_SERVER_Client *client;
501 * Linked list of messages yet to be transmitted to
504 struct ClientMessageQueueEntry *message_queue_head;
507 * Tail of linked list of messages yet to be transmitted to the
510 struct ClientMessageQueueEntry *message_queue_tail;
513 * Is a call to "transmit_send_continuation" pending? If so, we
514 * must not free this struct (even if the corresponding client
515 * disconnects) and instead only remove it from the linked list and
516 * set the "client" field to NULL.
521 * Length of the list of messages pending for this client.
523 unsigned int message_count;
529 * For each HELLO, we may have to validate multiple addresses;
530 * each address gets its own request entry.
532 struct ValidationAddress
535 * This is a linked list.
537 struct ValidationAddress *next;
540 * Name of the transport.
542 char *transport_name;
545 * When should this validated address expire?
547 struct GNUNET_TIME_Absolute expiration;
550 * Length of the address we are validating.
555 * Challenge number we used.
560 * Set to GNUNET_YES if the challenge was met,
561 * GNUNET_SYSERR if we know it failed, GNUNET_NO
562 * if we are waiting on a response.
569 * Entry in linked list of all HELLOs awaiting validation.
571 struct ValidationList
575 * This is a linked list.
577 struct ValidationList *next;
580 * Linked list with one entry per address from the HELLO
581 * that needs to be validated.
583 struct ValidationAddress *addresses;
586 * The public key of the peer.
588 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
591 * When does this record time-out? (assuming the
592 * challenge goes unanswered)
594 struct GNUNET_TIME_Absolute timeout;
600 * HELLOs awaiting validation.
602 static struct ValidationList *pending_validations;
607 static struct GNUNET_HELLO_Message *our_hello;
610 * "version" of "our_hello". Used to see if a given
611 * neighbor has already been sent the latest version
612 * of our HELLO message.
614 static unsigned int our_hello_version;
619 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
624 static struct GNUNET_PeerIdentity my_identity;
629 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
634 struct GNUNET_SCHEDULER_Handle *sched;
639 const struct GNUNET_CONFIGURATION_Handle *cfg;
642 * Linked list of all clients to this service.
644 static struct TransportClient *clients;
647 * All loaded plugins.
649 static struct TransportPlugin *plugins;
654 static struct GNUNET_SERVER_Handle *server;
657 * All known neighbors and their HELLOs.
659 static struct NeighborList *neighbors;
662 * Number of neighbors we'd like to have.
664 static uint32_t max_connect_per_transport;
668 * Find an entry in the neighbor list for a particular peer.
669 * if sender_address is not specified (NULL) then return the
670 * first matching entry. If sender_address is specified, then
671 * make sure that the address and address_len also matches.
673 * @return NULL if not found.
675 static struct NeighborList *
676 find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
677 size_t sender_address_len)
679 struct NeighborList *head = neighbors;
680 if (sender_address == NULL)
682 while ((head != NULL) &&
683 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
688 while ((head != NULL) &&
689 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
690 (sender_address_len != head->addr_len) &&
691 (0 != memcmp (sender_address, &head->addr, head->addr_len)))
699 * Find an entry in the transport list for a particular transport.
701 * @return NULL if not found.
703 static struct TransportPlugin *
704 find_transport (const char *short_name)
706 struct TransportPlugin *head = plugins;
707 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
714 * Update the quota values for the given neighbor now.
717 update_quota (struct NeighborList *n)
719 struct GNUNET_TIME_Relative delta;
723 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
724 if (delta.value < MIN_QUOTA_REFRESH_TIME)
725 return; /* not enough time passed for doing quota update */
726 allowed = delta.value * n->quota_in;
727 if (n->last_received < allowed)
729 remaining = allowed - n->last_received;
731 remaining /= n->quota_in;
734 if (remaining > MAX_BANDWIDTH_CARRY)
735 remaining = MAX_BANDWIDTH_CARRY;
736 n->last_received = 0;
737 n->last_quota_update = GNUNET_TIME_absolute_get ();
738 n->last_quota_update.value -= remaining;
739 if (n->quota_violation_count > 0)
740 n->quota_violation_count--;
744 n->last_received -= allowed;
745 n->last_quota_update = GNUNET_TIME_absolute_get ();
746 if (n->last_received > allowed)
748 /* more than twice the allowed rate! */
749 n->quota_violation_count += 10;
756 * Function called to notify a client about the socket
757 * being ready to queue more data. "buf" will be
758 * NULL and "size" zero if the socket was closed for
759 * writing in the meantime.
762 * @param size number of bytes available in buf
763 * @param buf where the callee should write the message
764 * @return number of bytes written to buf
767 transmit_to_client_callback (void *cls, size_t size, void *buf)
769 struct TransportClient *client = cls;
770 struct ClientMessageQueueEntry *q;
773 const struct GNUNET_MessageHeader *msg;
774 struct GNUNET_CONNECTION_TransmitHandle *th;
779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
780 "Transmission to client failed, closing connection.\n");
781 /* fatal error with client, free message queue! */
782 while (NULL != (q = client->message_queue_head))
784 client->message_queue_head = q->next;
787 client->message_queue_tail = NULL;
788 client->message_count = 0;
793 while (NULL != (q = client->message_queue_head))
795 msg = (const struct GNUNET_MessageHeader *) &q[1];
796 msize = ntohs (msg->size);
797 if (msize + tsize > size)
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Transmitting message of type %u to client.\n",
804 client->message_queue_head = q->next;
806 client->message_queue_tail = NULL;
807 memcpy (&cbuf[tsize], msg, msize);
810 client->message_count--;
814 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
815 th = GNUNET_SERVER_notify_transmit_ready (client->client,
817 GNUNET_TIME_UNIT_FOREVER_REL,
818 &transmit_to_client_callback,
820 GNUNET_assert (th != NULL);
827 * Send the specified message to the specified client. Since multiple
828 * messages may be pending for the same client at a time, this code
829 * makes sure that no message is lost.
831 * @param client client to transmit the message to
832 * @param msg the message to send
833 * @param may_drop can this message be dropped if the
834 * message queue for this client is getting far too large?
837 transmit_to_client (struct TransportClient *client,
838 const struct GNUNET_MessageHeader *msg, int may_drop)
840 struct ClientMessageQueueEntry *q;
842 struct GNUNET_CONNECTION_TransmitHandle *th;
844 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
846 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
848 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
849 client->message_count, MAX_PENDING);
850 /* TODO: call to statistics... */
853 client->message_count++;
854 msize = ntohs (msg->size);
855 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
856 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
857 memcpy (&q[1], msg, msize);
858 /* append to message queue */
859 if (client->message_queue_tail == NULL)
861 client->message_queue_tail = q;
865 client->message_queue_tail->next = q;
866 client->message_queue_tail = q;
868 if (client->message_queue_head == NULL)
870 client->message_queue_head = q;
871 th = GNUNET_SERVER_notify_transmit_ready (client->client,
873 GNUNET_TIME_UNIT_FOREVER_REL,
874 &transmit_to_client_callback,
876 GNUNET_assert (th != NULL);
882 * Find alternative plugins for communication.
884 * @param neighbor for which neighbor should we try to find
888 try_alternative_plugins (struct NeighborList *neighbor)
890 struct ReadyList *rl;
892 if ((neighbor->plugins != NULL) &&
893 (neighbor->retry_plugins_time.value >
894 GNUNET_TIME_absolute_get ().value))
895 return; /* don't try right now */
896 neighbor->retry_plugins_time
897 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
899 rl = neighbor->plugins;
902 if (rl->connect_attempts > 0)
903 rl->connect_attempts--; /* amnesty */
911 * The peer specified by the given neighbor has timed-out or a plugin
912 * has disconnected. We may either need to do nothing (other plugins
913 * still up), or trigger a full disconnect and clean up. This
914 * function updates our state and do the necessary notifications.
915 * Also notifies our clients that the neighbor is now officially
918 * @param n the neighbor list entry for the peer
919 * @param check should we just check if all plugins
920 * disconnected or must we ask all plugins to
923 static void disconnect_neighbor (struct NeighborList *n, int check);
927 * Check the ready list for the given neighbor and
928 * if a plugin is ready for transmission (and if we
929 * have a message), do so!
931 * @param neighbor target peer for which to check the plugins
933 static void try_transmission_to_peer (struct NeighborList *neighbor);
937 * Function called by the GNUNET_TRANSPORT_TransmitFunction
938 * upon "completion" of a send request. This tells the API
939 * that it is now legal to send another message to the given
942 * @param cls closure, identifies the entry on the
943 * message queue that was transmitted and the
944 * client responsible for queueing the message
945 * @param target the peer receiving the message
946 * @param result GNUNET_OK on success, if the transmission
947 * failed, we should not tell the client to transmit
951 transmit_send_continuation (void *cls,
952 const struct GNUNET_PeerIdentity *target,
955 struct MessageQueue *mq = cls;
956 struct ReadyList *rl;
957 struct SendOkMessage send_ok_msg;
958 struct NeighborList *n;
960 GNUNET_assert (mq != NULL);
962 GNUNET_assert (n != NULL);
964 memcmp (&n->id, target,
965 sizeof (struct GNUNET_PeerIdentity)));
967 while ((rl != NULL) && (rl->plugin != mq->plugin))
969 GNUNET_assert (rl != NULL);
970 if (result == GNUNET_OK)
973 GNUNET_TIME_relative_to_absolute
974 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "Transmission to peer `%s' failed, marking connection as down.\n",
980 GNUNET_i2s (target));
981 rl->connected = GNUNET_NO;
983 if (!mq->internal_msg)
984 rl->transmit_ready = GNUNET_YES;
985 if (mq->client != NULL)
987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988 "Notifying client %p about failed transission to peer `%4s'.\n",
989 mq->client, GNUNET_i2s (target));
990 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
991 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
992 send_ok_msg.success = htonl (result);
993 send_ok_msg.peer = n->id;
994 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
996 GNUNET_free (mq->message);
998 /* one plugin just became ready again, try transmitting
999 another message (if available) */
1000 if (result == GNUNET_OK)
1001 try_transmission_to_peer (n);
1003 disconnect_neighbor (n, GNUNET_YES);
1008 * Check the ready list for the given neighbor and
1009 * if a plugin is ready for transmission (and if we
1010 * have a message), do so!
1013 try_transmission_to_peer (struct NeighborList *neighbor)
1015 struct ReadyList *pos;
1016 struct GNUNET_TIME_Relative min_latency;
1017 struct ReadyList *rl;
1018 struct MessageQueue *mq;
1019 struct GNUNET_TIME_Absolute now;
1021 if (neighbor->messages == NULL)
1022 return; /* nothing to do */
1023 try_alternative_plugins (neighbor);
1024 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1026 mq = neighbor->messages;
1027 now = GNUNET_TIME_absolute_get ();
1028 pos = neighbor->plugins;
1031 /* set plugins that are inactive for a long time back to disconnected */
1032 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036 "Marking long-time inactive connection to `%4s' as down.\n",
1037 GNUNET_i2s (&neighbor->id));
1039 pos->connected = GNUNET_NO;
1041 if (((GNUNET_YES == pos->transmit_ready) ||
1042 (mq->internal_msg)) &&
1043 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1044 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1047 min_latency = pos->latency;
1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 "No plugin ready to transmit message\n");
1057 return; /* nobody ready */
1059 if (GNUNET_NO == rl->connected)
1061 rl->connect_attempts++;
1062 rl->connected = GNUNET_YES;
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "Establishing fresh connection with `%4s' via plugin `%s'\n",
1066 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1069 neighbor->messages = mq->next;
1070 mq->plugin = rl->plugin;
1071 if (!mq->internal_msg)
1072 rl->transmit_ready = GNUNET_NO;
1074 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1076 ntohs (mq->message->type),
1077 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1080 rl->plugin->api->send (rl->plugin->api->cls,
1084 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1086 rl->neighbor->addr_len,
1088 &transmit_send_continuation, mq);
1093 * Send the specified message to the specified peer.
1095 * @param client source of the transmission request (can be NULL)
1096 * @param priority how important is the message
1097 * @param msg message to send
1098 * @param is_internal is this an internal message
1099 * @param neighbor handle to the neighbor for transmission
1102 transmit_to_peer (struct TransportClient *client,
1103 unsigned int priority,
1104 const struct GNUNET_MessageHeader *msg,
1105 int is_internal, struct NeighborList *neighbor)
1107 struct MessageQueue *mq;
1108 struct MessageQueue *mqe;
1109 struct GNUNET_MessageHeader *m;
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113 _("Sending message of type %u to peer `%4s'\n"),
1114 ntohs (msg->type), GNUNET_i2s (&neighbor->id));
1118 /* check for duplicate submission */
1119 mq = neighbor->messages;
1122 if (mq->client == client)
1124 /* client transmitted to same peer twice
1125 before getting SendOk! */
1132 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1133 mq->client = client;
1134 m = GNUNET_malloc (ntohs (msg->size));
1135 memcpy (m, msg, ntohs (msg->size));
1137 mq->neighbor = neighbor;
1138 mq->internal_msg = is_internal;
1139 mq->priority = priority;
1142 mqe = neighbor->messages;
1144 while (mqe->next != NULL)
1149 neighbor->messages = mq;
1150 try_transmission_to_peer (neighbor);
1163 struct GeneratorContext
1165 struct TransportPlugin *plug_pos;
1166 struct AddressList *addr_pos;
1167 struct GNUNET_TIME_Absolute expiration;
1175 address_generator (void *cls, size_t max, void *buf)
1177 struct GeneratorContext *gc = cls;
1180 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1182 gc->plug_pos = gc->plug_pos->next;
1183 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1185 if (NULL == gc->plug_pos)
1187 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1190 gc->addr_pos->addrlen, buf, max);
1191 gc->addr_pos = gc->addr_pos->next;
1197 * Construct our HELLO message from all of the addresses of
1198 * all of the transports.
1203 struct GNUNET_HELLO_Message *hello;
1204 struct TransportClient *cpos;
1205 struct NeighborList *npos;
1206 struct GeneratorContext gc;
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1210 "Refreshing my `%s'\n", "HELLO");
1212 gc.plug_pos = plugins;
1213 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1214 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1215 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1217 while (cpos != NULL)
1219 transmit_to_client (cpos,
1220 (const struct GNUNET_MessageHeader *) hello,
1225 GNUNET_free_non_null (our_hello);
1227 our_hello_version++;
1228 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1230 while (npos != NULL)
1233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1234 "Transmitting updated `%s' to neighbor `%4s'\n",
1235 "HELLO", GNUNET_i2s (&npos->id));
1237 transmit_to_peer (NULL, 0,
1238 (const struct GNUNET_MessageHeader *) our_hello,
1246 * Task used to clean up expired addresses for a plugin.
1248 * @param cls closure
1252 expire_address_task (void *cls,
1253 const struct GNUNET_SCHEDULER_TaskContext *tc);
1257 * Update the list of addresses for this plugin,
1258 * expiring those that are past their expiration date.
1260 * @param plugin addresses of which plugin should be recomputed?
1261 * @param fresh set to GNUNET_YES if a new address was added
1262 * and we need to regenerate the HELLO even if nobody
1266 update_addresses (struct TransportPlugin *plugin, int fresh)
1268 struct GNUNET_TIME_Relative min_remaining;
1269 struct GNUNET_TIME_Relative remaining;
1270 struct GNUNET_TIME_Absolute now;
1271 struct AddressList *pos;
1272 struct AddressList *prev;
1273 struct AddressList *next;
1276 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1277 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1278 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1279 now = GNUNET_TIME_absolute_get ();
1280 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1281 expired = GNUNET_NO;
1283 pos = plugin->addresses;
1287 if (pos->expires.value < now.value)
1289 expired = GNUNET_YES;
1291 plugin->addresses = pos->next;
1293 prev->next = pos->next;
1298 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1299 if (remaining.value < min_remaining.value)
1300 min_remaining = remaining;
1306 if (expired || fresh)
1308 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1309 plugin->address_update_task
1310 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1312 &expire_address_task, plugin);
1318 * Task used to clean up expired addresses for a plugin.
1320 * @param cls closure
1324 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1326 struct TransportPlugin *plugin = cls;
1327 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1328 update_addresses (plugin, GNUNET_NO);
1333 * Function that must be called by each plugin to notify the
1334 * transport service about the addresses under which the transport
1335 * provided by the plugin can be reached.
1337 * @param cls closure
1338 * @param name name of the transport that generated the address
1339 * @param addr one of the addresses of the host, NULL for the last address
1340 * the specific address format depends on the transport
1341 * @param addrlen length of the address
1342 * @param expires when should this address automatically expire?
1345 plugin_env_notify_address (void *cls,
1349 struct GNUNET_TIME_Relative expires)
1351 struct TransportPlugin *p = cls;
1352 struct AddressList *al;
1353 struct GNUNET_TIME_Absolute abex;
1355 abex = GNUNET_TIME_relative_to_absolute (expires);
1356 GNUNET_assert (p == find_transport (name));
1361 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1363 if (al->expires.value < abex.value)
1370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371 "Plugin `%s' informs us about a new address `%s'\n", name,
1372 GNUNET_a2s (addr, addrlen));
1374 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1376 al->next = p->addresses;
1379 al->addrlen = addrlen;
1380 memcpy (&al[1], addr, addrlen);
1381 update_addresses (p, GNUNET_YES);
1386 * Notify all of our clients about a peer connecting.
1389 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1390 struct GNUNET_TIME_Relative latency)
1392 struct ConnectInfoMessage cim;
1393 struct TransportClient *cpos;
1396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1397 "Informing clients about peer `%4s' connecting to us\n",
1400 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1401 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1402 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1403 cim.latency = GNUNET_TIME_relative_hton (latency);
1404 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1406 while (cpos != NULL)
1408 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1415 * Notify all of our clients about a peer disconnecting.
1418 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1420 struct DisconnectInfoMessage dim;
1421 struct TransportClient *cpos;
1424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1425 "Informing clients about peer `%4s' disconnecting\n",
1428 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1429 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1430 dim.reserved = htonl (0);
1431 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1433 while (cpos != NULL)
1435 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1442 * Copy any validated addresses to buf.
1444 * @return 0 once all addresses have been
1448 list_validated_addresses (void *cls, size_t max, void *buf)
1450 struct ValidationAddress **va = cls;
1453 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1457 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1459 &(*va)[1], (*va)->addr_len, buf, max);
1466 * HELLO validation cleanup task.
1469 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1471 struct ValidationAddress *va;
1472 struct ValidationList *pos;
1473 struct ValidationList *prev;
1474 struct GNUNET_TIME_Absolute now;
1475 struct GNUNET_TIME_Absolute first;
1476 struct GNUNET_HELLO_Message *hello;
1477 struct GNUNET_PeerIdentity pid;
1478 struct NeighborList *n;
1481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1482 "HELLO validation cleanup background task running...\n");
1484 now = GNUNET_TIME_absolute_get ();
1486 pos = pending_validations;
1489 if (pos->timeout.value < now.value)
1492 pending_validations = pos->next;
1494 prev->next = pos->next;
1495 va = pos->addresses;
1496 hello = GNUNET_HELLO_create (&pos->publicKey,
1497 &list_validated_addresses, &va);
1498 GNUNET_CRYPTO_hash (&pos->publicKey,
1500 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1504 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1505 "HELLO", GNUNET_i2s (&pid));
1507 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1508 n = find_neighbor (&pid, NULL, 0);
1510 try_transmission_to_peer (n);
1511 GNUNET_free (hello);
1512 while (NULL != (va = pos->addresses))
1514 pos->addresses = va->next;
1515 GNUNET_free (va->transport_name);
1520 pos = pending_validations;
1529 /* finally, reschedule cleanup if needed; list is
1530 ordered by timeout, so we need the last element... */
1531 if (NULL != pending_validations)
1533 first = pending_validations->timeout;
1534 pos = pending_validations;
1537 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1540 GNUNET_SCHEDULER_add_delayed (sched,
1541 GNUNET_TIME_absolute_get_remaining
1542 (first), &cleanup_validation, NULL);
1550 * Function that will be called if we receive a validation
1551 * of an address challenge that we transmitted to another
1552 * peer. Note that the validation should only be considered
1553 * acceptable if the challenge matches AND if the sender
1554 * address is at least a plausible address for this peer
1555 * (otherwise we may be seeing a MiM attack).
1557 * @param cls closure
1558 * @param name name of the transport that generated the address
1559 * @param peer who responded to our challenge
1560 * @param challenge the challenge number we presumably used
1561 * @param sender_addr string describing our sender address (as observed
1562 * by the other peer in human-readable format)
1565 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1566 const struct GNUNET_PeerIdentity *peer,
1567 const char *sender_address,
1568 size_t sender_address_len)
1570 unsigned int not_done;
1572 struct ValidationList *pos;
1573 struct ValidationAddress *va;
1574 struct GNUNET_PeerIdentity id;
1576 int challenge = 1; /* FIXME: Pull this number out of the PONG message */
1577 pos = pending_validations;
1580 GNUNET_CRYPTO_hash (&pos->publicKey,
1582 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1584 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1590 /* TODO: call statistics (unmatched PONG) */
1591 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1593 ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
1598 matched = GNUNET_NO;
1599 va = pos->addresses;
1602 if (va->challenge == challenge)
1605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1606 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1608 GNUNET_a2s ((const struct sockaddr *) &va[1],
1611 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1613 ("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"),
1615 va->ok = GNUNET_YES;
1617 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1618 matched = GNUNET_YES;
1620 if (va->ok != GNUNET_YES)
1624 if (GNUNET_NO == matched)
1626 /* TODO: call statistics (unmatched PONG) */
1627 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1629 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636 "All addresses validated, will now construct `%s' for `%4s'.\n",
1637 "HELLO", GNUNET_i2s (peer));
1639 pos->timeout.value = 0;
1640 GNUNET_SCHEDULER_add_with_priority (sched,
1641 GNUNET_SCHEDULER_PRIORITY_IDLE,
1642 &cleanup_validation, NULL);
1647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1648 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1649 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1655 struct CheckHelloValidatedContext
1658 * Plugin for which we are validating.
1660 struct TransportPlugin *plugin;
1663 * Hello that we are validating.
1665 struct GNUNET_HELLO_Message *hello;
1668 * Validation list being build.
1670 struct ValidationList *e;
1673 * Context for peerinfo iteration.
1674 * NULL after we are done processing peerinfo's information.
1676 struct GNUNET_PEERINFO_IteratorContext *piter;
1682 * Append the given address to the list of entries
1683 * that need to be validated.
1686 run_validation (void *cls,
1688 struct GNUNET_TIME_Absolute expiration,
1689 const void *addr, size_t addrlen)
1691 struct ValidationList *e = cls;
1692 struct TransportPlugin *tp;
1693 struct ValidationAddress *va;
1694 struct GNUNET_PeerIdentity id;
1696 tp = find_transport (tname);
1699 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1700 GNUNET_ERROR_TYPE_BULK,
1702 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1706 GNUNET_CRYPTO_hash (&e->publicKey,
1708 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1712 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1714 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1715 va->next = e->addresses;
1717 va->transport_name = GNUNET_strdup (tname);
1718 va->addr_len = addrlen;
1719 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1721 memcpy (&va[1], addr, addrlen);
1726 * @param cls handle to the plugin (for sending)
1727 * @param target the peer identity of the peer we are sending to
1728 * @param challenge the challenge number
1729 * @param timeout how long to await validation?
1730 * @param addr the address to validate
1731 * @param addrlen the length of the address
1733 * Perform address validation, which means sending a PING PONG to
1734 * the address via the transport plugin. If not validated, then
1735 * do not count this as a good peer/address...
1739 validate_address (void *cls, struct ValidationAddress *va,
1740 const struct GNUNET_PeerIdentity *target,
1741 struct GNUNET_TIME_Relative timeout,
1742 const void *addr, size_t addrlen)
1744 /* struct Plugin *plugin = cls;
1745 int challenge = va->challenge; */
1753 * Check if addresses in validated hello "h" overlap with
1754 * those in "chvc->hello" and update "chvc->hello" accordingly,
1755 * removing those addresses that have already been validated.
1758 check_hello_validated (void *cls,
1759 const struct GNUNET_PeerIdentity *peer,
1760 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1762 struct CheckHelloValidatedContext *chvc = cls;
1763 struct ValidationAddress *va;
1764 struct TransportPlugin *tp;
1766 struct GNUNET_PeerIdentity apeer;
1768 first_call = GNUNET_NO;
1769 if (chvc->e == NULL)
1772 first_call = GNUNET_YES;
1773 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1774 GNUNET_assert (GNUNET_OK ==
1775 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1776 &chvc->e->publicKey));
1778 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1779 chvc->e->next = pending_validations;
1780 pending_validations = chvc->e;
1784 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1786 GNUNET_TIME_absolute_get (),
1787 &run_validation, chvc->e);
1789 else if (GNUNET_YES == first_call)
1791 /* no existing HELLO, all addresses are new */
1792 GNUNET_HELLO_iterate_addresses (chvc->hello,
1793 GNUNET_NO, &run_validation, chvc->e);
1796 return; /* wait for next call */
1797 /* finally, transmit validation attempts */
1798 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1801 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1802 "HELLO", GNUNET_i2s (&apeer));
1804 va = chvc->e->addresses;
1808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1809 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1812 GNUNET_a2s ((const struct sockaddr *) &va[1],
1813 va->addr_len), GNUNET_i2s (&apeer));
1815 tp = find_transport (va->transport_name);
1816 GNUNET_assert (tp != NULL);
1817 /* This validation should happen inside the transport, not from the plugin! */
1818 validate_address (tp->api->cls, va, &apeer,
1819 HELLO_VERIFICATION_TIMEOUT,
1820 &va[1], va->addr_len);
1821 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1824 GNUNET_SCHEDULER_add_delayed (sched,
1825 GNUNET_TIME_absolute_get_remaining (chvc->
1827 &cleanup_validation, NULL);
1833 * Process HELLO-message.
1835 * @param plugin transport involved, may be NULL
1836 * @param message the actual message
1837 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1840 process_hello (struct TransportPlugin *plugin,
1841 const struct GNUNET_MessageHeader *message)
1843 struct ValidationList *e;
1845 struct GNUNET_PeerIdentity target;
1846 const struct GNUNET_HELLO_Message *hello;
1847 struct CheckHelloValidatedContext *chvc;
1848 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1850 hsize = ntohs (message->size);
1851 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1852 (hsize < sizeof (struct GNUNET_MessageHeader)))
1855 return GNUNET_SYSERR;
1857 /* first, check if load is too high */
1858 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1860 /* TODO: call to stats? */
1863 hello = (const struct GNUNET_HELLO_Message *) message;
1864 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1866 GNUNET_break_op (0);
1867 return GNUNET_SYSERR;
1869 GNUNET_CRYPTO_hash (&publicKey,
1870 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1871 &target.hashPubKey);
1873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1874 "Processing `%s' message for `%4s'\n",
1875 "HELLO", GNUNET_i2s (&target));
1877 /* check if a HELLO for this peer is already on the validation list */
1878 e = pending_validations;
1881 if (0 == memcmp (&e->publicKey,
1884 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1886 /* TODO: call to stats? */
1888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1889 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1890 "HELLO", GNUNET_i2s (&target));
1896 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1897 chvc->plugin = plugin;
1898 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1899 memcpy (chvc->hello, hello, hsize);
1900 /* finally, check if HELLO was previously validated
1901 (continuation will then schedule actual validation) */
1902 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1906 HELLO_VERIFICATION_TIMEOUT,
1907 &check_hello_validated, chvc);
1913 * The peer specified by the given neighbor has timed-out or a plugin
1914 * has disconnected. We may either need to do nothing (other plugins
1915 * still up), or trigger a full disconnect and clean up. This
1916 * function updates our state and do the necessary notifications.
1917 * Also notifies our clients that the neighbor is now officially
1920 * @param n the neighbor list entry for the peer
1921 * @param check should we just check if all plugins
1922 * disconnected or must we ask all plugins to
1926 disconnect_neighbor (struct NeighborList *n, int check)
1928 struct ReadyList *rpos;
1929 struct NeighborList *npos;
1930 struct NeighborList *nprev;
1931 struct MessageQueue *mq;
1933 if (GNUNET_YES == check)
1936 while (NULL != rpos)
1938 if (GNUNET_YES == rpos->connected)
1939 return; /* still connected */
1945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1946 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
1948 /* remove n from neighbors list */
1951 while ((npos != NULL) && (npos != n))
1956 GNUNET_assert (npos != NULL);
1958 neighbors = n->next;
1960 nprev->next = n->next;
1962 /* notify all clients about disconnect */
1963 notify_clients_disconnect (&n->id);
1965 /* clean up all plugins, cancel connections and pending transmissions */
1966 while (NULL != (rpos = n->plugins))
1968 n->plugins = rpos->next;
1969 GNUNET_assert (rpos->neighbor == n);
1970 if (GNUNET_YES == rpos->connected)
1971 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
1975 /* free all messages on the queue */
1976 while (NULL != (mq = n->messages))
1978 n->messages = mq->next;
1979 GNUNET_assert (mq->neighbor == n);
1982 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1983 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
1984 /* finally, free n itself */
1990 * Add an entry for each of our transport plugins
1991 * (that are able to send) to the list of plugins
1992 * for this neighbor.
1994 * @param neighbor to initialize
1997 add_plugins (struct NeighborList *neighbor)
1999 struct TransportPlugin *tp;
2000 struct ReadyList *rl;
2002 neighbor->retry_plugins_time
2003 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2007 if (tp->api->send != NULL)
2009 rl = GNUNET_malloc (sizeof (struct ReadyList));
2010 rl->next = neighbor->plugins;
2011 neighbor->plugins = rl;
2013 rl->neighbor = neighbor;
2014 rl->transmit_ready = GNUNET_YES;
2022 neighbor_timeout_task (void *cls,
2023 const struct GNUNET_SCHEDULER_TaskContext *tc)
2025 struct NeighborList *n = cls;
2028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2029 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2031 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2032 disconnect_neighbor (n, GNUNET_NO);
2037 * Create a fresh entry in our neighbor list for the given peer.
2038 * Will try to transmit our current HELLO to the new neighbor. Also
2039 * notifies our clients about the new "connection".
2041 * @param peer the peer for which we create the entry
2042 * @return the new neighbor list entry
2044 static struct NeighborList *
2045 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
2047 struct NeighborList *n;
2050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2051 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
2054 GNUNET_assert (our_hello != NULL);
2055 n = GNUNET_malloc (sizeof (struct NeighborList));
2056 n->next = neighbors;
2059 n->last_quota_update = GNUNET_TIME_absolute_get ();
2061 GNUNET_TIME_relative_to_absolute
2062 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2063 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2065 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2066 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2067 &neighbor_timeout_task, n);
2068 transmit_to_peer (NULL, 0,
2069 (const struct GNUNET_MessageHeader *) our_hello,
2071 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2076 * We have received a PING message from someone. Need to send a PONG message
2077 * in response to the peer by any means necessary. Of course, with something
2078 * like TCP where a connection exists, we may want to send it that way. But
2079 * we may not be able to make that distinction...
2081 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2082 const struct GNUNET_PeerIdentity *peer,
2083 const char *sender_address,
2084 size_t sender_address_len)
2091 * Function called by the plugin for each received message.
2092 * Update data volumes, possibly notify plugins about
2093 * reducing the rate at which they read from the socket
2094 * and generally forward to our receive callback.
2096 * @param cls the "struct TransportPlugin *" we gave to the plugin
2097 * @param message the message, NULL if peer was disconnected
2098 * @param distance the transport cost to this peer (not latency!)
2099 * @param sender_address the address that the sender reported
2100 * (opaque to transport service)
2101 * @param sender_address_len the length of the sender address
2102 * @param peer (claimed) identity of the other peer
2103 * @return the new service_context that the plugin should use
2104 * for future receive calls for messages from this
2109 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2110 const struct GNUNET_MessageHeader *message,
2111 unsigned int distance, const char *sender_address,
2112 size_t sender_address_len)
2114 const struct GNUNET_MessageHeader ack = {
2115 htons (sizeof (struct GNUNET_MessageHeader)),
2116 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2118 struct ReadyList *service_context;
2119 struct TransportPlugin *plugin = cls;
2120 struct TransportClient *cpos;
2121 struct InboundMessage *im;
2123 struct NeighborList *n;
2125 n = find_neighbor (peer, sender_address, sender_address_len);
2128 if (message == NULL)
2129 return; /* disconnect of peer already marked down */
2130 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2132 service_context = n->plugins;
2133 while ((service_context != NULL) && (plugin != service_context->plugin))
2134 service_context = service_context->next;
2135 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2136 if (message == NULL)
2139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2140 "Receive failed from `%4s', triggering disconnect\n",
2141 GNUNET_i2s (&n->id));
2143 /* TODO: call stats */
2144 if (service_context != NULL)
2145 service_context->connected = GNUNET_NO;
2146 disconnect_neighbor (n, GNUNET_YES);
2150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2151 "Processing message of type `%u' received by plugin...\n",
2152 ntohs (message->type));
2154 if (service_context != NULL)
2156 if (service_context->connected == GNUNET_NO)
2158 service_context->connected = GNUNET_YES;
2159 service_context->transmit_ready = GNUNET_YES;
2160 service_context->connect_attempts++;
2162 service_context->timeout
2164 GNUNET_TIME_relative_to_absolute
2165 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2166 /* service_context->latency = latency; */ /* This value should be set by us! */
2168 /* update traffic received amount ... */
2169 msize = ntohs (message->size);
2170 n->last_received += msize;
2171 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2173 GNUNET_TIME_relative_to_absolute
2174 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2176 GNUNET_SCHEDULER_add_delayed (sched,
2177 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2178 &neighbor_timeout_task, n);
2180 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2182 /* dropping message due to frequent inbound volume violations! */
2183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2184 GNUNET_ERROR_TYPE_BULK,
2186 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2187 /* TODO: call stats */
2188 GNUNET_assert ((service_context == NULL) ||
2189 (NULL != service_context->neighbor));
2192 switch (ntohs (message->type))
2194 case GNUNET_MESSAGE_TYPE_HELLO:
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2197 "Receiving `%s' message from `%4s'.\n", "HELLO",
2200 process_hello (plugin, message);
2202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2203 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2206 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2208 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2209 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2210 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2211 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2212 //plugin_env_notify_validation();
2213 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2214 n->saw_ack = GNUNET_YES;
2215 /* intentional fall-through! */
2218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2219 "Received message of type %u from `%4s', sending to all clients.\n",
2220 ntohs (message->type), GNUNET_i2s (peer));
2222 /* transmit message to all clients */
2223 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2224 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2225 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2226 im->latency = n->latency;
2228 memcpy (&im[1], message, msize);
2231 while (cpos != NULL)
2233 transmit_to_client (cpos, &im->header, GNUNET_YES);
2238 GNUNET_assert ((service_context == NULL) ||
2239 (NULL != service_context->neighbor));
2244 * Handle START-message. This is the first message sent to us
2245 * by any client which causes us to add it to our list.
2247 * @param cls closure (always NULL)
2248 * @param client identification of the client
2249 * @param message the actual message
2252 handle_start (void *cls,
2253 struct GNUNET_SERVER_Client *client,
2254 const struct GNUNET_MessageHeader *message)
2256 struct TransportClient *c;
2257 struct ConnectInfoMessage cim;
2258 struct NeighborList *n;
2259 struct InboundMessage *im;
2260 struct GNUNET_MessageHeader *ack;
2263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2264 "Received `%s' request from client\n", "START");
2269 if (c->client == client)
2271 /* client already on our list! */
2273 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2278 c = GNUNET_malloc (sizeof (struct TransportClient));
2282 if (our_hello != NULL)
2285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2286 "Sending our own `%s' to new client\n", "HELLO");
2288 transmit_to_client (c,
2289 (const struct GNUNET_MessageHeader *) our_hello,
2291 /* tell new client about all existing connections */
2292 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2293 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2295 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2296 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2297 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2298 sizeof (struct GNUNET_MessageHeader));
2299 im->header.size = htons (sizeof (struct InboundMessage) +
2300 sizeof (struct GNUNET_MessageHeader));
2301 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2302 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2303 ack = (struct GNUNET_MessageHeader *) &im[1];
2304 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2305 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2306 for (n = neighbors; n != NULL; n = n->next)
2309 transmit_to_client (c, &cim.header, GNUNET_NO);
2313 transmit_to_client (c, &im->header, GNUNET_NO);
2318 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2323 * Handle HELLO-message.
2325 * @param cls closure (always NULL)
2326 * @param client identification of the client
2327 * @param message the actual message
2330 handle_hello (void *cls,
2331 struct GNUNET_SERVER_Client *client,
2332 const struct GNUNET_MessageHeader *message)
2337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2338 "Received `%s' request from client\n", "HELLO");
2340 ret = process_hello (NULL, message);
2341 GNUNET_SERVER_receive_done (client, ret);
2346 * Handle SEND-message.
2348 * @param cls closure (always NULL)
2349 * @param client identification of the client
2350 * @param message the actual message
2353 handle_send (void *cls,
2354 struct GNUNET_SERVER_Client *client,
2355 const struct GNUNET_MessageHeader *message)
2357 struct TransportClient *tc;
2358 struct NeighborList *n;
2359 const struct OutboundMessage *obm;
2360 const struct GNUNET_MessageHeader *obmm;
2364 size = ntohs (message->size);
2366 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2369 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2372 obm = (const struct OutboundMessage *) message;
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "Received `%s' request from client with target `%4s'\n",
2376 "SEND", GNUNET_i2s (&obm->peer));
2378 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2379 msize = ntohs (obmm->size);
2380 if (size != msize + sizeof (struct OutboundMessage))
2383 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2386 n = find_neighbor (&obm->peer, NULL, 0);
2388 n = setup_new_neighbor (&obm->peer, NULL, 0);
2390 while ((tc != NULL) && (tc->client != client))
2394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2397 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2399 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2400 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2405 * Handle SET_QUOTA-message.
2407 * @param cls closure (always NULL)
2408 * @param client identification of the client
2409 * @param message the actual message
2412 handle_set_quota (void *cls,
2413 struct GNUNET_SERVER_Client *client,
2414 const struct GNUNET_MessageHeader *message)
2416 const struct QuotaSetMessage *qsm =
2417 (const struct QuotaSetMessage *) message;
2418 struct NeighborList *n;
2419 struct TransportPlugin *p;
2420 struct ReadyList *rl;
2423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2424 "Received `%s' request from client for peer `%4s'\n",
2425 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2427 n = find_neighbor (&qsm->peer, NULL, 0);
2430 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2434 if (n->quota_in < ntohl (qsm->quota_in))
2435 n->last_quota_update = GNUNET_TIME_absolute_get ();
2436 n->quota_in = ntohl (qsm->quota_in);
2441 p->api->set_receive_quota (p->api->cls,
2442 &qsm->peer, ntohl (qsm->quota_in));
2445 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2450 * Handle TRY_CONNECT-message.
2452 * @param cls closure (always NULL)
2453 * @param client identification of the client
2454 * @param message the actual message
2457 handle_try_connect (void *cls,
2458 struct GNUNET_SERVER_Client *client,
2459 const struct GNUNET_MessageHeader *message)
2461 const struct TryConnectMessage *tcm;
2463 tcm = (const struct TryConnectMessage *) message;
2465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2466 "Received `%s' request from client %p asking to connect to `%4s'\n",
2467 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2469 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2470 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2471 knowing its address? Should we ask the plugin
2472 for more information about this peer? I don't
2473 think we can... Or set up new peer should only
2474 happen when transport notifies us of an address,
2475 and this setup should check for an address in
2476 the existing list only */
2479 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2480 "Client asked to connect to `%4s', but connection already exists\n",
2481 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2483 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2487 transmit_address_to_client (void *cls, const char *address)
2489 struct GNUNET_SERVER_TransmitContext *tc = cls;
2492 if (NULL == address)
2495 slen = strlen (address) + 1;
2496 GNUNET_SERVER_transmit_context_append (tc, address, slen,
2497 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2498 if (NULL == address)
2499 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2503 * Handle AddressLookup-message.
2505 * @param cls closure (always NULL)
2506 * @param client identification of the client
2507 * @param message the actual message
2510 handle_address_lookup (void *cls,
2511 struct GNUNET_SERVER_Client *client,
2512 const struct GNUNET_MessageHeader *message)
2514 const struct AddressLookupMessage *alum;
2515 struct TransportPlugin *lsPlugin;
2516 const char *nameTransport;
2517 const char *address;
2519 struct GNUNET_SERVER_TransmitContext *tc;
2521 size = ntohs (message->size);
2522 if (size < sizeof (struct AddressLookupMessage))
2524 GNUNET_break_op (0);
2525 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2528 alum = (const struct AddressLookupMessage *) message;
2529 uint32_t addressLen = ntohl (alum->addrlen);
2530 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2532 GNUNET_break_op (0);
2533 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2536 address = (const char *) &alum[1];
2537 nameTransport = (const char *) &address[addressLen];
2539 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2541 GNUNET_break_op (0);
2542 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2545 struct GNUNET_TIME_Absolute timeout =
2546 GNUNET_TIME_absolute_ntoh (alum->timeout);
2547 struct GNUNET_TIME_Relative rtimeout =
2548 GNUNET_TIME_absolute_get_remaining (timeout);
2549 lsPlugin = find_transport (nameTransport);
2550 if (NULL == lsPlugin)
2552 tc = GNUNET_SERVER_transmit_context_create (client);
2553 GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
2554 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2555 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2558 tc = GNUNET_SERVER_transmit_context_create (client);
2559 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2560 address, addressLen, GNUNET_YES,
2562 &transmit_address_to_client, tc);
2566 * List of handlers for the messages understood by this
2569 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2570 {&handle_start, NULL,
2571 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2572 {&handle_hello, NULL,
2573 GNUNET_MESSAGE_TYPE_HELLO, 0},
2574 {&handle_send, NULL,
2575 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2576 {&handle_set_quota, NULL,
2577 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2578 {&handle_try_connect, NULL,
2579 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2580 sizeof (struct TryConnectMessage)},
2581 {&handle_address_lookup, NULL,
2582 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2589 * Setup the environment for this plugin.
2592 create_environment (struct TransportPlugin *plug)
2594 plug->env.cfg = cfg;
2595 plug->env.sched = sched;
2596 plug->env.my_identity = &my_identity;
2597 plug->env.cls = plug;
2598 plug->env.receive = &plugin_env_receive;
2599 plug->env.notify_address = &plugin_env_notify_address;
2600 plug->env.default_quota_in =
2601 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2602 plug->env.max_connections = max_connect_per_transport;
2607 * Start the specified transport (load the plugin).
2610 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2612 struct TransportPlugin *plug;
2615 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2616 _("Loading `%s' transport plugin\n"), name);
2617 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2618 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2619 create_environment (plug);
2620 plug->short_name = GNUNET_strdup (name);
2621 plug->lib_name = libname;
2622 plug->next = plugins;
2624 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2625 if (plug->api == NULL)
2627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2628 _("Failed to load transport plugin for `%s'\n"), name);
2629 GNUNET_free (plug->short_name);
2630 plugins = plug->next;
2631 GNUNET_free (libname);
2638 * Called whenever a client is disconnected. Frees our
2639 * resources associated with that client.
2641 * @param cls closure
2642 * @param client identification of the client
2645 client_disconnect_notification (void *cls,
2646 struct GNUNET_SERVER_Client *client)
2648 struct TransportClient *pos;
2649 struct TransportClient *prev;
2650 struct ClientMessageQueueEntry *mqe;
2653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2654 "Client disconnected, cleaning up.\n");
2658 while ((pos != NULL) && (pos->client != client))
2665 while (NULL != (mqe = pos->message_queue_head))
2667 pos->message_queue_head = mqe->next;
2670 pos->message_queue_head = NULL;
2672 clients = pos->next;
2674 prev->next = pos->next;
2675 if (GNUNET_YES == pos->tcs_pending)
2685 * Function called when the service shuts down. Unloads our plugins.
2687 * @param cls closure, unused
2688 * @param tc task context (unused)
2691 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2693 struct TransportPlugin *plug;
2694 struct AddressList *al;
2697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2698 "Transport service is unloading plugins...\n");
2700 while (NULL != (plug = plugins))
2702 plugins = plug->next;
2703 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2704 GNUNET_free (plug->lib_name);
2705 GNUNET_free (plug->short_name);
2706 while (NULL != (al = plug->addresses))
2708 plug->addresses = al->next;
2713 if (my_private_key != NULL)
2714 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2715 GNUNET_free_non_null (our_hello);
2720 * Initiate transport service.
2722 * @param cls closure
2723 * @param s scheduler to use
2724 * @param serv the initialized server
2725 * @param c configuration to use
2729 struct GNUNET_SCHEDULER_Handle *s,
2730 struct GNUNET_SERVER_Handle *serv,
2731 const struct GNUNET_CONFIGURATION_Handle *c)
2736 unsigned long long tneigh;
2741 /* parse configuration */
2743 GNUNET_CONFIGURATION_get_value_number (c,
2748 GNUNET_CONFIGURATION_get_value_filename (c,
2750 "HOSTKEY", &keyfile)))
2752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2754 ("Transport service is lacking key configuration settings. Exiting.\n"));
2755 GNUNET_SCHEDULER_shutdown (s);
2758 max_connect_per_transport = (uint32_t) tneigh;
2759 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2760 GNUNET_free (keyfile);
2761 if (my_private_key == NULL)
2763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2765 ("Transport service could not access hostkey. Exiting.\n"));
2766 GNUNET_SCHEDULER_shutdown (s);
2769 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2770 GNUNET_CRYPTO_hash (&my_public_key,
2771 sizeof (my_public_key), &my_identity.hashPubKey);
2772 /* setup notification */
2774 GNUNET_SERVER_disconnect_notify (server,
2775 &client_disconnect_notification, NULL);
2776 /* load plugins... */
2779 GNUNET_CONFIGURATION_get_value_string (c,
2780 "TRANSPORT", "PLUGINS", &plugs))
2782 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2783 _("Starting transport plugins `%s'\n"), plugs);
2784 pos = strtok (plugs, " ");
2787 start_transport (server, pos);
2789 pos = strtok (NULL, " ");
2791 GNUNET_free (plugs);
2793 GNUNET_SCHEDULER_add_delayed (sched,
2794 GNUNET_TIME_UNIT_FOREVER_REL,
2795 &unload_plugins, NULL);
2799 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2801 /* process client requests */
2802 GNUNET_SERVER_add_handlers (server, handlers);
2807 * The main function for the transport service.
2809 * @param argc number of arguments from the command line
2810 * @param argv command line arguments
2811 * @return 0 ok, 1 on error
2814 main (int argc, char *const *argv)
2816 return (GNUNET_OK ==
2817 GNUNET_SERVICE_run (argc,
2820 GNUNET_SERVICE_OPTION_NONE,
2821 &run, NULL)) ? 0 : 1;
2824 /* end of gnunet-service-transport.c */