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 long will we allow sending of a ping to be delayed?
81 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
83 #define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */
86 * How often do we re-add (cheaper) plugins to our list of plugins
87 * to try for a given connected peer?
89 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
92 * After how long do we expire an address in a HELLO
93 * that we just validated? This value is also used
94 * for our own addresses when we create a HELLO.
96 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
100 * Entry in linked list of network addresses.
105 * This is a linked list.
107 struct AddressList *next;
110 * The address, actually a pointer to the end
111 * of this struct. Do not free!
116 * How long until we auto-expire this address (unless it is
117 * re-confirmed by the transport)?
119 struct GNUNET_TIME_Absolute expires;
130 * Entry in linked list of all of our plugins.
132 struct TransportPlugin
136 * This is a linked list.
138 struct TransportPlugin *next;
141 * API of the transport as returned by the plugin's
142 * initialization function.
144 struct GNUNET_TRANSPORT_PluginFunctions *api;
147 * Short name for the plugin (i.e. "tcp").
152 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
157 * List of our known addresses for this transport.
159 struct AddressList *addresses;
162 * Environment this transport service is using
165 struct GNUNET_TRANSPORT_PluginEnvironment env;
168 * ID of task that is used to clean up expired addresses.
170 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
174 * Set to GNUNET_YES if we need to scrap the existing
175 * list of "addresses" and start fresh when we receive
176 * the next address update from a transport. Set to
177 * GNUNET_NO if we should just add the new address
178 * to the list and wait for the commit call.
186 * For each neighbor we keep a list of messages
187 * that we still want to transmit to the neighbor.
193 * This is a linked list.
195 struct MessageQueue *next;
198 * The message we want to transmit.
200 struct GNUNET_MessageHeader *message;
203 * Client responsible for queueing the message;
204 * used to check that a client has not two messages
205 * pending for the same target. Can be NULL.
207 struct TransportClient *client;
210 * Neighbor this entry belongs to.
212 struct NeighborList *neighbor;
215 * Plugin that we used for the transmission.
216 * NULL until we scheduled a transmission.
218 struct TransportPlugin *plugin;
221 * Internal message of the transport system that should not be
222 * included in the usual SEND-SEND_OK transmission confirmation
223 * traffic management scheme. Typically, "internal_msg" will
224 * be set whenever "client" is NULL (but it is not strictly
230 * How important is the message?
232 unsigned int priority;
238 * For a given Neighbor, which plugins are available
239 * to talk to this peer and what are their costs?
245 * This is a linked list.
247 struct ReadyList *next;
250 * Which of our transport plugins does this entry
253 struct TransportPlugin *plugin;
256 * Neighbor this entry belongs to.
258 struct NeighborList *neighbor;
261 * What was the last latency observed for this plugin
262 * and peer? Invalid if connected is GNUNET_NO.
264 struct GNUNET_TIME_Relative latency;
267 * If we did not successfully transmit a message to the given peer
268 * via this connection during the specified time, we should consider
269 * the connection to be dead. This is used in the case that a TCP
270 * transport simply stalls writing to the stream but does not
271 * formerly get a signal that the other peer died.
273 struct GNUNET_TIME_Absolute timeout;
276 * Is this plugin currently connected? The first time
277 * we transmit or send data to a peer via a particular
278 * plugin, we set this to GNUNET_YES. If we later get
279 * an error (disconnect notification or transmission
280 * failure), we set it back to GNUNET_NO. Each time the
281 * value is set to GNUNET_YES, we increment the
282 * "connect_attempts" counter. If that one reaches a
283 * particular threshold, we consider the plugin to not
284 * be working properly at this time for the given peer
285 * and remove it from the eligible list.
290 * How often have we tried to connect using this plugin?
292 unsigned int connect_attempts;
295 * Is this plugin ready to transmit to the specific target?
296 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
297 * transmission is in progress, "transmit_ready" is set to
306 * Entry in linked list of all of our current neighbors.
312 * This is a linked list.
314 struct NeighborList *next;
317 * Which of our transports is connected to this peer
318 * and what is their status?
320 struct ReadyList *plugins;
323 * List of messages we would like to send to this peer;
324 * must contain at most one message per client.
326 struct MessageQueue *messages;
329 * Identity of this neighbor.
331 struct GNUNET_PeerIdentity id;
334 * Opaque addr of this peer, only known to the plugin
344 * ID of task scheduled to run when this peer is about to
345 * time out (will free resources associated with the peer).
347 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
350 * How long until we should consider this peer dead
351 * (if we don't receive another message in the
354 struct GNUNET_TIME_Absolute peer_timeout;
357 * At what time did we reset last_received last?
359 struct GNUNET_TIME_Absolute last_quota_update;
362 * At what time should we try to again add plugins to
365 struct GNUNET_TIME_Absolute retry_plugins_time;
368 * How many bytes have we received since the "last_quota_update"
371 uint64_t last_received;
374 * Global quota for inbound traffic for the neighbor in bytes/ms.
379 * How often has the other peer (recently) violated the
380 * inbound traffic limit? Incremented by 10 per violation,
381 * decremented by 1 per non-violation (for each
384 unsigned int quota_violation_count;
387 * Have we seen an ACK from this neighbor in the past?
388 * (used to make up a fake ACK for clients connecting after
389 * the neighbor connected to us).
393 /* The latency we have seen for this particular address for
394 * this particular peer. This latency may have been calculated
395 * over multiple transports. This value reflects how long it took
396 * us to receive a response when SENDING via this particular
397 * transport/neighbor/address combination!
399 struct GNUNET_TIME_RelativeNBO latency;
404 * Message used to ask a peer to validate receipt (to check an address
405 * from a HELLO). Followed by the address used. Note that the
406 * recipients response does not affirm that he has this address,
407 * only that he got the challenge message.
409 struct TransportPingMessage
413 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
415 struct GNUNET_MessageHeader header;
418 * Random challenge number (in network byte order).
420 uint32_t challenge GNUNET_PACKED;
423 * Who is the intended recipient?
425 struct GNUNET_PeerIdentity target;
431 * Message used to validate a HELLO. The challenge is included in the
432 * confirmation to make matching of replies to requests possible. The
433 * signature signs the original challenge number, our public key, the
434 * sender's address (so that the sender can check that the address we
435 * saw is plausible for him and possibly detect a MiM attack) and a
436 * timestamp (to limit replay).<p>
438 * This message is followed by the address of the
439 * client that we are observing (which is part of what
442 struct TransportPongMessage
446 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
448 struct GNUNET_MessageHeader header;
451 * For padding, always zero.
453 uint32_t reserved GNUNET_PACKED;
458 struct GNUNET_CRYPTO_RsaSignature signature;
461 * What are we signing and why?
463 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
466 * Random challenge number (in network byte order).
468 uint32_t challenge GNUNET_PACKED;
471 * Who signed this message?
473 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
478 * Linked list of messages to be transmitted to
479 * the client. Each entry is followed by the
482 struct ClientMessageQueueEntry
485 * This is a linked list.
487 struct ClientMessageQueueEntry *next;
492 * Client connected to the transport service.
494 struct TransportClient
498 * This is a linked list.
500 struct TransportClient *next;
503 * Handle to the client.
505 struct GNUNET_SERVER_Client *client;
508 * Linked list of messages yet to be transmitted to
511 struct ClientMessageQueueEntry *message_queue_head;
514 * Tail of linked list of messages yet to be transmitted to the
517 struct ClientMessageQueueEntry *message_queue_tail;
520 * Is a call to "transmit_send_continuation" pending? If so, we
521 * must not free this struct (even if the corresponding client
522 * disconnects) and instead only remove it from the linked list and
523 * set the "client" field to NULL.
528 * Length of the list of messages pending for this client.
530 unsigned int message_count;
536 * For each HELLO, we may have to validate multiple addresses;
537 * each address gets its own request entry.
539 struct ValidationAddress
542 * This is a linked list.
544 struct ValidationAddress *next;
547 * Name of the transport.
549 char *transport_name;
552 * When should this validated address expire?
554 struct GNUNET_TIME_Absolute expiration;
557 * Length of the address we are validating.
562 * Challenge number we used.
567 * Set to GNUNET_YES if the challenge was met,
568 * GNUNET_SYSERR if we know it failed, GNUNET_NO
569 * if we are waiting on a response.
576 * Entry in linked list of all HELLOs awaiting validation.
578 struct ValidationList
582 * This is a linked list.
584 struct ValidationList *next;
587 * Linked list with one entry per address from the HELLO
588 * that needs to be validated.
590 struct ValidationAddress *addresses;
593 * The public key of the peer.
595 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
598 * When does this record time-out? (assuming the
599 * challenge goes unanswered)
601 struct GNUNET_TIME_Absolute timeout;
607 * HELLOs awaiting validation.
609 static struct ValidationList *pending_validations;
614 static struct GNUNET_HELLO_Message *our_hello;
617 * "version" of "our_hello". Used to see if a given
618 * neighbor has already been sent the latest version
619 * of our HELLO message.
621 static unsigned int our_hello_version;
626 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
631 static struct GNUNET_PeerIdentity my_identity;
636 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
641 struct GNUNET_SCHEDULER_Handle *sched;
646 const struct GNUNET_CONFIGURATION_Handle *cfg;
649 * Linked list of all clients to this service.
651 static struct TransportClient *clients;
654 * All loaded plugins.
656 static struct TransportPlugin *plugins;
661 static struct GNUNET_SERVER_Handle *server;
664 * All known neighbors and their HELLOs.
666 static struct NeighborList *neighbors;
669 * Number of neighbors we'd like to have.
671 static uint32_t max_connect_per_transport;
675 * Find an entry in the neighbor list for a particular peer.
676 * if sender_address is not specified (NULL) then return the
677 * first matching entry. If sender_address is specified, then
678 * make sure that the address and address_len also matches.
680 * @return NULL if not found.
682 static struct NeighborList *
683 find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
684 size_t sender_address_len)
686 struct NeighborList *head = neighbors;
687 if (sender_address == NULL)
689 while ((head != NULL) &&
690 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
695 while ((head != NULL) &&
696 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
697 (sender_address_len != head->addr_len) &&
698 (0 != memcmp (sender_address, &head->addr, head->addr_len)))
706 * Find an entry in the transport list for a particular transport.
708 * @return NULL if not found.
710 static struct TransportPlugin *
711 find_transport (const char *short_name)
713 struct TransportPlugin *head = plugins;
714 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
721 * Update the quota values for the given neighbor now.
724 update_quota (struct NeighborList *n)
726 struct GNUNET_TIME_Relative delta;
730 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
731 if (delta.value < MIN_QUOTA_REFRESH_TIME)
732 return; /* not enough time passed for doing quota update */
733 allowed = delta.value * n->quota_in;
734 if (n->last_received < allowed)
736 remaining = allowed - n->last_received;
738 remaining /= n->quota_in;
741 if (remaining > MAX_BANDWIDTH_CARRY)
742 remaining = MAX_BANDWIDTH_CARRY;
743 n->last_received = 0;
744 n->last_quota_update = GNUNET_TIME_absolute_get ();
745 n->last_quota_update.value -= remaining;
746 if (n->quota_violation_count > 0)
747 n->quota_violation_count--;
751 n->last_received -= allowed;
752 n->last_quota_update = GNUNET_TIME_absolute_get ();
753 if (n->last_received > allowed)
755 /* more than twice the allowed rate! */
756 n->quota_violation_count += 10;
763 * Function called to notify a client about the socket
764 * being ready to queue more data. "buf" will be
765 * NULL and "size" zero if the socket was closed for
766 * writing in the meantime.
769 * @param size number of bytes available in buf
770 * @param buf where the callee should write the message
771 * @return number of bytes written to buf
774 transmit_to_client_callback (void *cls, size_t size, void *buf)
776 struct TransportClient *client = cls;
777 struct ClientMessageQueueEntry *q;
780 const struct GNUNET_MessageHeader *msg;
781 struct GNUNET_CONNECTION_TransmitHandle *th;
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787 "Transmission to client failed, closing connection.\n");
788 /* fatal error with client, free message queue! */
789 while (NULL != (q = client->message_queue_head))
791 client->message_queue_head = q->next;
794 client->message_queue_tail = NULL;
795 client->message_count = 0;
800 while (NULL != (q = client->message_queue_head))
802 msg = (const struct GNUNET_MessageHeader *) &q[1];
803 msize = ntohs (msg->size);
804 if (msize + tsize > size)
807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
808 "Transmitting message of type %u to client.\n",
811 client->message_queue_head = q->next;
813 client->message_queue_tail = NULL;
814 memcpy (&cbuf[tsize], msg, msize);
817 client->message_count--;
821 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
822 th = GNUNET_SERVER_notify_transmit_ready (client->client,
824 GNUNET_TIME_UNIT_FOREVER_REL,
825 &transmit_to_client_callback,
827 GNUNET_assert (th != NULL);
834 * Send the specified message to the specified client. Since multiple
835 * messages may be pending for the same client at a time, this code
836 * makes sure that no message is lost.
838 * @param client client to transmit the message to
839 * @param msg the message to send
840 * @param may_drop can this message be dropped if the
841 * message queue for this client is getting far too large?
844 transmit_to_client (struct TransportClient *client,
845 const struct GNUNET_MessageHeader *msg, int may_drop)
847 struct ClientMessageQueueEntry *q;
849 struct GNUNET_CONNECTION_TransmitHandle *th;
851 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
853 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
855 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
856 client->message_count, MAX_PENDING);
857 /* TODO: call to statistics... */
860 client->message_count++;
861 msize = ntohs (msg->size);
862 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
863 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
864 memcpy (&q[1], msg, msize);
865 /* append to message queue */
866 if (client->message_queue_tail == NULL)
868 client->message_queue_tail = q;
872 client->message_queue_tail->next = q;
873 client->message_queue_tail = q;
875 if (client->message_queue_head == NULL)
877 client->message_queue_head = q;
878 th = GNUNET_SERVER_notify_transmit_ready (client->client,
880 GNUNET_TIME_UNIT_FOREVER_REL,
881 &transmit_to_client_callback,
883 GNUNET_assert (th != NULL);
889 * Find alternative plugins for communication.
891 * @param neighbor for which neighbor should we try to find
895 try_alternative_plugins (struct NeighborList *neighbor)
897 struct ReadyList *rl;
899 if ((neighbor->plugins != NULL) &&
900 (neighbor->retry_plugins_time.value >
901 GNUNET_TIME_absolute_get ().value))
902 return; /* don't try right now */
903 neighbor->retry_plugins_time
904 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
906 rl = neighbor->plugins;
909 if (rl->connect_attempts > 0)
910 rl->connect_attempts--; /* amnesty */
918 * The peer specified by the given neighbor has timed-out or a plugin
919 * has disconnected. We may either need to do nothing (other plugins
920 * still up), or trigger a full disconnect and clean up. This
921 * function updates our state and do the necessary notifications.
922 * Also notifies our clients that the neighbor is now officially
925 * @param n the neighbor list entry for the peer
926 * @param check should we just check if all plugins
927 * disconnected or must we ask all plugins to
930 static void disconnect_neighbor (struct NeighborList *n, int check);
934 * Check the ready list for the given neighbor and
935 * if a plugin is ready for transmission (and if we
936 * have a message), do so!
938 * @param neighbor target peer for which to check the plugins
940 static void try_transmission_to_peer (struct NeighborList *neighbor);
944 * Function called by the GNUNET_TRANSPORT_TransmitFunction
945 * upon "completion" of a send request. This tells the API
946 * that it is now legal to send another message to the given
949 * @param cls closure, identifies the entry on the
950 * message queue that was transmitted and the
951 * client responsible for queueing the message
952 * @param target the peer receiving the message
953 * @param result GNUNET_OK on success, if the transmission
954 * failed, we should not tell the client to transmit
958 transmit_send_continuation (void *cls,
959 const struct GNUNET_PeerIdentity *target,
962 struct MessageQueue *mq = cls;
963 struct ReadyList *rl;
964 struct SendOkMessage send_ok_msg;
965 struct NeighborList *n;
967 GNUNET_assert (mq != NULL);
969 GNUNET_assert (n != NULL);
971 memcmp (&n->id, target,
972 sizeof (struct GNUNET_PeerIdentity)));
974 while ((rl != NULL) && (rl->plugin != mq->plugin))
976 GNUNET_assert (rl != NULL);
977 if (result == GNUNET_OK)
980 GNUNET_TIME_relative_to_absolute
981 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
986 "Transmission to peer `%s' failed, marking connection as down.\n",
987 GNUNET_i2s (target));
988 rl->connected = GNUNET_NO;
990 if (!mq->internal_msg)
991 rl->transmit_ready = GNUNET_YES;
992 if (mq->client != NULL)
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 "Notifying client %p about failed transission to peer `%4s'.\n",
996 mq->client, GNUNET_i2s (target));
997 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
998 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
999 send_ok_msg.success = htonl (result);
1000 send_ok_msg.peer = n->id;
1001 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1003 GNUNET_free (mq->message);
1005 /* one plugin just became ready again, try transmitting
1006 another message (if available) */
1007 if (result == GNUNET_OK)
1008 try_transmission_to_peer (n);
1010 disconnect_neighbor (n, GNUNET_YES);
1015 * Check the ready list for the given neighbor and
1016 * if a plugin is ready for transmission (and if we
1017 * have a message), do so!
1020 try_transmission_to_peer (struct NeighborList *neighbor)
1022 struct ReadyList *pos;
1023 struct GNUNET_TIME_Relative min_latency;
1024 struct ReadyList *rl;
1025 struct MessageQueue *mq;
1026 struct GNUNET_TIME_Absolute now;
1028 if (neighbor->messages == NULL)
1029 return; /* nothing to do */
1030 try_alternative_plugins (neighbor);
1031 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1033 mq = neighbor->messages;
1034 now = GNUNET_TIME_absolute_get ();
1035 pos = neighbor->plugins;
1038 /* set plugins that are inactive for a long time back to disconnected */
1039 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043 "Marking long-time inactive connection to `%4s' as down.\n",
1044 GNUNET_i2s (&neighbor->id));
1046 pos->connected = GNUNET_NO;
1048 if (((GNUNET_YES == pos->transmit_ready) ||
1049 (mq->internal_msg)) &&
1050 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1051 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1054 min_latency = pos->latency;
1061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1062 "No plugin ready to transmit message\n");
1064 return; /* nobody ready */
1066 if (GNUNET_NO == rl->connected)
1068 rl->connect_attempts++;
1069 rl->connected = GNUNET_YES;
1071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072 "Establishing fresh connection with `%4s' via plugin `%s'\n",
1073 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1076 neighbor->messages = mq->next;
1077 mq->plugin = rl->plugin;
1078 if (!mq->internal_msg)
1079 rl->transmit_ready = GNUNET_NO;
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1083 ntohs (mq->message->type),
1084 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1087 rl->plugin->api->send (rl->plugin->api->cls,
1091 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1093 rl->neighbor->addr_len,
1095 &transmit_send_continuation, mq);
1100 * Send the specified message to the specified peer.
1102 * @param client source of the transmission request (can be NULL)
1103 * @param priority how important is the message
1104 * @param msg message to send
1105 * @param is_internal is this an internal message
1106 * @param neighbor handle to the neighbor for transmission
1109 transmit_to_peer (struct TransportClient *client,
1110 unsigned int priority,
1111 const struct GNUNET_MessageHeader *msg,
1112 int is_internal, struct NeighborList *neighbor)
1114 struct MessageQueue *mq;
1115 struct MessageQueue *mqe;
1116 struct GNUNET_MessageHeader *m;
1119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1120 _("Sending message of type %u to peer `%4s'\n"),
1121 ntohs (msg->type), GNUNET_i2s (&neighbor->id));
1125 /* check for duplicate submission */
1126 mq = neighbor->messages;
1129 if (mq->client == client)
1131 /* client transmitted to same peer twice
1132 before getting SendOk! */
1139 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1140 mq->client = client;
1141 m = GNUNET_malloc (ntohs (msg->size));
1142 memcpy (m, msg, ntohs (msg->size));
1144 mq->neighbor = neighbor;
1145 mq->internal_msg = is_internal;
1146 mq->priority = priority;
1149 mqe = neighbor->messages;
1151 while (mqe->next != NULL)
1156 neighbor->messages = mq;
1157 try_transmission_to_peer (neighbor);
1170 struct GeneratorContext
1172 struct TransportPlugin *plug_pos;
1173 struct AddressList *addr_pos;
1174 struct GNUNET_TIME_Absolute expiration;
1182 address_generator (void *cls, size_t max, void *buf)
1184 struct GeneratorContext *gc = cls;
1187 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1189 gc->plug_pos = gc->plug_pos->next;
1190 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1192 if (NULL == gc->plug_pos)
1194 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1197 gc->addr_pos->addrlen, buf, max);
1198 gc->addr_pos = gc->addr_pos->next;
1204 * Construct our HELLO message from all of the addresses of
1205 * all of the transports.
1210 struct GNUNET_HELLO_Message *hello;
1211 struct TransportClient *cpos;
1212 struct NeighborList *npos;
1213 struct GeneratorContext gc;
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1217 "Refreshing my `%s'\n", "HELLO");
1219 gc.plug_pos = plugins;
1220 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1221 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1222 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1224 while (cpos != NULL)
1226 transmit_to_client (cpos,
1227 (const struct GNUNET_MessageHeader *) hello,
1232 GNUNET_free_non_null (our_hello);
1234 our_hello_version++;
1235 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1237 while (npos != NULL)
1240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1241 "Transmitting updated `%s' to neighbor `%4s'\n",
1242 "HELLO", GNUNET_i2s (&npos->id));
1244 transmit_to_peer (NULL, 0,
1245 (const struct GNUNET_MessageHeader *) our_hello,
1253 * Task used to clean up expired addresses for a plugin.
1255 * @param cls closure
1259 expire_address_task (void *cls,
1260 const struct GNUNET_SCHEDULER_TaskContext *tc);
1264 * Update the list of addresses for this plugin,
1265 * expiring those that are past their expiration date.
1267 * @param plugin addresses of which plugin should be recomputed?
1268 * @param fresh set to GNUNET_YES if a new address was added
1269 * and we need to regenerate the HELLO even if nobody
1273 update_addresses (struct TransportPlugin *plugin, int fresh)
1275 struct GNUNET_TIME_Relative min_remaining;
1276 struct GNUNET_TIME_Relative remaining;
1277 struct GNUNET_TIME_Absolute now;
1278 struct AddressList *pos;
1279 struct AddressList *prev;
1280 struct AddressList *next;
1283 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1284 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1285 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1286 now = GNUNET_TIME_absolute_get ();
1287 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1288 expired = GNUNET_NO;
1290 pos = plugin->addresses;
1294 if (pos->expires.value < now.value)
1296 expired = GNUNET_YES;
1298 plugin->addresses = pos->next;
1300 prev->next = pos->next;
1305 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1306 if (remaining.value < min_remaining.value)
1307 min_remaining = remaining;
1313 if (expired || fresh)
1315 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1316 plugin->address_update_task
1317 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1319 &expire_address_task, plugin);
1325 * Task used to clean up expired addresses for a plugin.
1327 * @param cls closure
1331 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1333 struct TransportPlugin *plugin = cls;
1334 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1335 update_addresses (plugin, GNUNET_NO);
1340 * Function that must be called by each plugin to notify the
1341 * transport service about the addresses under which the transport
1342 * provided by the plugin can be reached.
1344 * @param cls closure
1345 * @param name name of the transport that generated the address
1346 * @param addr one of the addresses of the host, NULL for the last address
1347 * the specific address format depends on the transport
1348 * @param addrlen length of the address
1349 * @param expires when should this address automatically expire?
1352 plugin_env_notify_address (void *cls,
1356 struct GNUNET_TIME_Relative expires)
1358 struct TransportPlugin *p = cls;
1359 struct AddressList *al;
1360 struct GNUNET_TIME_Absolute abex;
1362 abex = GNUNET_TIME_relative_to_absolute (expires);
1363 GNUNET_assert (p == find_transport (name));
1368 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1370 if (al->expires.value < abex.value)
1377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1378 "Plugin `%s' informs us about a new address `%s'\n", name,
1379 GNUNET_a2s (addr, addrlen));
1381 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1383 al->next = p->addresses;
1386 al->addrlen = addrlen;
1387 memcpy (&al[1], addr, addrlen);
1388 update_addresses (p, GNUNET_YES);
1393 * Notify all of our clients about a peer connecting.
1396 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1397 struct GNUNET_TIME_Relative latency)
1399 struct ConnectInfoMessage cim;
1400 struct TransportClient *cpos;
1403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1404 "Informing clients about peer `%4s' connecting to us\n",
1407 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1408 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1409 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1410 cim.latency = GNUNET_TIME_relative_hton (latency);
1411 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1413 while (cpos != NULL)
1415 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1422 * Notify all of our clients about a peer disconnecting.
1425 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1427 struct DisconnectInfoMessage dim;
1428 struct TransportClient *cpos;
1431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432 "Informing clients about peer `%4s' disconnecting\n",
1435 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1436 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1437 dim.reserved = htonl (0);
1438 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1440 while (cpos != NULL)
1442 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1449 * Copy any validated addresses to buf.
1451 * @return 0 once all addresses have been
1455 list_validated_addresses (void *cls, size_t max, void *buf)
1457 struct ValidationAddress **va = cls;
1460 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1464 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1466 &(*va)[1], (*va)->addr_len, buf, max);
1473 * HELLO validation cleanup task.
1476 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1478 struct ValidationAddress *va;
1479 struct ValidationList *pos;
1480 struct ValidationList *prev;
1481 struct GNUNET_TIME_Absolute now;
1482 struct GNUNET_TIME_Absolute first;
1483 struct GNUNET_HELLO_Message *hello;
1484 struct GNUNET_PeerIdentity pid;
1485 struct NeighborList *n;
1488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1489 "HELLO validation cleanup background task running...\n");
1491 now = GNUNET_TIME_absolute_get ();
1493 pos = pending_validations;
1496 if (pos->timeout.value < now.value)
1499 pending_validations = pos->next;
1501 prev->next = pos->next;
1502 va = pos->addresses;
1503 hello = GNUNET_HELLO_create (&pos->publicKey,
1504 &list_validated_addresses, &va);
1505 GNUNET_CRYPTO_hash (&pos->publicKey,
1507 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1511 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1512 "HELLO", GNUNET_i2s (&pid));
1514 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1515 n = find_neighbor (&pid, NULL, 0);
1517 try_transmission_to_peer (n);
1518 GNUNET_free (hello);
1519 while (NULL != (va = pos->addresses))
1521 pos->addresses = va->next;
1522 GNUNET_free (va->transport_name);
1527 pos = pending_validations;
1536 /* finally, reschedule cleanup if needed; list is
1537 ordered by timeout, so we need the last element... */
1538 if (NULL != pending_validations)
1540 first = pending_validations->timeout;
1541 pos = pending_validations;
1544 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1547 GNUNET_SCHEDULER_add_delayed (sched,
1548 GNUNET_TIME_absolute_get_remaining
1549 (first), &cleanup_validation, NULL);
1554 static struct GNUNET_MessageHeader *
1555 createPingMessage (struct GNUNET_PeerIdentity * target, struct ValidationAddress *va)
1558 struct TransportPingMessage *ping;
1559 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
1561 ping->challenge = htonl(va->challenge);
1562 ping->header.size = sizeof(struct TransportPingMessage);
1563 ping->header.type = GNUNET_MESSAGE_TYPE_TRANSPORT_PING;
1564 memcpy(&ping->target, target, sizeof(struct GNUNET_PeerIdentity));
1566 return &ping->header;
1570 * Function that will be called if we receive a validation
1571 * of an address challenge that we transmitted to another
1572 * peer. Note that the validation should only be considered
1573 * acceptable if the challenge matches AND if the sender
1574 * address is at least a plausible address for this peer
1575 * (otherwise we may be seeing a MiM attack).
1577 * @param cls closure
1578 * @param name name of the transport that generated the address
1579 * @param peer who responded to our challenge
1580 * @param challenge the challenge number we presumably used
1581 * @param sender_addr string describing our sender address (as observed
1582 * by the other peer in human-readable format)
1585 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1586 const struct GNUNET_PeerIdentity *peer,
1587 const char *sender_address,
1588 size_t sender_address_len)
1590 unsigned int not_done;
1592 struct ValidationList *pos;
1593 struct ValidationAddress *va;
1594 struct GNUNET_PeerIdentity id;
1595 struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
1597 unsigned int challenge = ntohl(pong->challenge);
1598 pos = pending_validations;
1601 GNUNET_CRYPTO_hash (&pos->publicKey,
1603 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1605 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1611 /* TODO: call statistics (unmatched PONG) */
1612 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1614 ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
1619 matched = GNUNET_NO;
1620 va = pos->addresses;
1623 if (va->challenge == challenge)
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1629 GNUNET_a2s ((const struct sockaddr *) &va[1],
1632 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1634 ("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"),
1636 va->ok = GNUNET_YES;
1638 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1639 matched = GNUNET_YES;
1641 if (va->ok != GNUNET_YES)
1645 if (GNUNET_NO == matched)
1647 /* TODO: call statistics (unmatched PONG) */
1648 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1650 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657 "All addresses validated, will now construct `%s' for `%4s'.\n",
1658 "HELLO", GNUNET_i2s (peer));
1660 pos->timeout.value = 0;
1661 GNUNET_SCHEDULER_add_with_priority (sched,
1662 GNUNET_SCHEDULER_PRIORITY_IDLE,
1663 &cleanup_validation, NULL);
1668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1669 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1670 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1676 struct CheckHelloValidatedContext
1679 * Plugin for which we are validating.
1681 struct TransportPlugin *plugin;
1684 * Hello that we are validating.
1686 struct GNUNET_HELLO_Message *hello;
1689 * Validation list being build.
1691 struct ValidationList *e;
1694 * Context for peerinfo iteration.
1695 * NULL after we are done processing peerinfo's information.
1697 struct GNUNET_PEERINFO_IteratorContext *piter;
1703 * Append the given address to the list of entries
1704 * that need to be validated.
1707 run_validation (void *cls,
1709 struct GNUNET_TIME_Absolute expiration,
1710 const void *addr, size_t addrlen)
1712 struct ValidationList *e = cls;
1713 struct TransportPlugin *tp;
1714 struct ValidationAddress *va;
1715 struct GNUNET_PeerIdentity id;
1716 struct GNUNET_MessageHeader *pingMessage;
1717 tp = find_transport (tname);
1720 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1721 GNUNET_ERROR_TYPE_BULK,
1723 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1727 GNUNET_CRYPTO_hash (&e->publicKey,
1729 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1733 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1735 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1736 va->next = e->addresses;
1738 va->transport_name = GNUNET_strdup (tname);
1739 va->addr_len = addrlen;
1740 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1742 memcpy (&va[1], addr, addrlen);
1744 pingMessage = createPingMessage(&id, va);
1746 tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1747 TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
1749 GNUNET_free(pingMessage);
1755 * @param cls handle to the plugin (for sending)
1756 * @param target the peer identity of the peer we are sending to
1757 * @param challenge the challenge number
1758 * @param timeout how long to await validation?
1759 * @param addr the address to validate
1760 * @param addrlen the length of the address
1762 * Perform address validation, which means sending a PING PONG to
1763 * the address via the transport plugin. If not validated, then
1764 * do not count this as a good peer/address...
1768 validate_address (void *cls, struct ValidationAddress *va,
1769 const struct GNUNET_PeerIdentity *target,
1770 struct GNUNET_TIME_Relative timeout,
1771 const void *addr, size_t addrlen)
1773 /* struct Plugin *plugin = cls;
1774 int challenge = va->challenge; */
1782 * Check if addresses in validated hello "h" overlap with
1783 * those in "chvc->hello" and update "chvc->hello" accordingly,
1784 * removing those addresses that have already been validated.
1787 check_hello_validated (void *cls,
1788 const struct GNUNET_PeerIdentity *peer,
1789 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1791 struct CheckHelloValidatedContext *chvc = cls;
1792 struct ValidationAddress *va;
1793 struct TransportPlugin *tp;
1795 struct GNUNET_PeerIdentity apeer;
1797 first_call = GNUNET_NO;
1798 if (chvc->e == NULL)
1801 first_call = GNUNET_YES;
1802 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1803 GNUNET_assert (GNUNET_OK ==
1804 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1805 &chvc->e->publicKey));
1807 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1808 chvc->e->next = pending_validations;
1809 pending_validations = chvc->e;
1813 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1815 GNUNET_TIME_absolute_get (),
1816 &run_validation, chvc->e);
1818 else if (GNUNET_YES == first_call)
1820 /* no existing HELLO, all addresses are new */
1821 GNUNET_HELLO_iterate_addresses (chvc->hello,
1822 GNUNET_NO, &run_validation, chvc->e);
1825 return; /* wait for next call */
1826 /* finally, transmit validation attempts */
1827 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1831 "HELLO", GNUNET_i2s (&apeer));
1833 va = chvc->e->addresses;
1837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1841 GNUNET_a2s ((const struct sockaddr *) &va[1],
1842 va->addr_len), GNUNET_i2s (&apeer));
1844 tp = find_transport (va->transport_name);
1845 GNUNET_assert (tp != NULL);
1846 /* This validation should happen inside the transport, not from the plugin! */
1847 validate_address (tp->api->cls, va, &apeer,
1848 HELLO_VERIFICATION_TIMEOUT,
1849 &va[1], va->addr_len);
1850 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1853 GNUNET_SCHEDULER_add_delayed (sched,
1854 GNUNET_TIME_absolute_get_remaining (chvc->
1856 &cleanup_validation, NULL);
1862 * Process HELLO-message.
1864 * @param plugin transport involved, may be NULL
1865 * @param message the actual message
1866 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1869 process_hello (struct TransportPlugin *plugin,
1870 const struct GNUNET_MessageHeader *message)
1872 struct ValidationList *e;
1874 struct GNUNET_PeerIdentity target;
1875 const struct GNUNET_HELLO_Message *hello;
1876 struct CheckHelloValidatedContext *chvc;
1877 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1879 hsize = ntohs (message->size);
1880 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1881 (hsize < sizeof (struct GNUNET_MessageHeader)))
1884 return GNUNET_SYSERR;
1886 /* first, check if load is too high */
1887 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1889 /* TODO: call to stats? */
1892 hello = (const struct GNUNET_HELLO_Message *) message;
1893 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1895 GNUNET_break_op (0);
1896 return GNUNET_SYSERR;
1898 GNUNET_CRYPTO_hash (&publicKey,
1899 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1900 &target.hashPubKey);
1902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1903 "Processing `%s' message for `%4s'\n",
1904 "HELLO", GNUNET_i2s (&target));
1906 /* check if a HELLO for this peer is already on the validation list */
1907 e = pending_validations;
1910 if (0 == memcmp (&e->publicKey,
1913 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1915 /* TODO: call to stats? */
1917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1918 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1919 "HELLO", GNUNET_i2s (&target));
1925 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1926 chvc->plugin = plugin;
1927 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1928 memcpy (chvc->hello, hello, hsize);
1929 /* finally, check if HELLO was previously validated
1930 (continuation will then schedule actual validation) */
1931 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1935 HELLO_VERIFICATION_TIMEOUT,
1936 &check_hello_validated, chvc);
1942 * The peer specified by the given neighbor has timed-out or a plugin
1943 * has disconnected. We may either need to do nothing (other plugins
1944 * still up), or trigger a full disconnect and clean up. This
1945 * function updates our state and do the necessary notifications.
1946 * Also notifies our clients that the neighbor is now officially
1949 * @param n the neighbor list entry for the peer
1950 * @param check should we just check if all plugins
1951 * disconnected or must we ask all plugins to
1955 disconnect_neighbor (struct NeighborList *n, int check)
1957 struct ReadyList *rpos;
1958 struct NeighborList *npos;
1959 struct NeighborList *nprev;
1960 struct MessageQueue *mq;
1962 if (GNUNET_YES == check)
1965 while (NULL != rpos)
1967 if (GNUNET_YES == rpos->connected)
1968 return; /* still connected */
1974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1975 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
1977 /* remove n from neighbors list */
1980 while ((npos != NULL) && (npos != n))
1985 GNUNET_assert (npos != NULL);
1987 neighbors = n->next;
1989 nprev->next = n->next;
1991 /* notify all clients about disconnect */
1992 notify_clients_disconnect (&n->id);
1994 /* clean up all plugins, cancel connections and pending transmissions */
1995 while (NULL != (rpos = n->plugins))
1997 n->plugins = rpos->next;
1998 GNUNET_assert (rpos->neighbor == n);
1999 if (GNUNET_YES == rpos->connected)
2000 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2004 /* free all messages on the queue */
2005 while (NULL != (mq = n->messages))
2007 n->messages = mq->next;
2008 GNUNET_assert (mq->neighbor == n);
2011 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2012 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2013 /* finally, free n itself */
2019 * Add an entry for each of our transport plugins
2020 * (that are able to send) to the list of plugins
2021 * for this neighbor.
2023 * @param neighbor to initialize
2026 add_plugins (struct NeighborList *neighbor)
2028 struct TransportPlugin *tp;
2029 struct ReadyList *rl;
2031 neighbor->retry_plugins_time
2032 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2036 if (tp->api->send != NULL)
2038 rl = GNUNET_malloc (sizeof (struct ReadyList));
2039 rl->next = neighbor->plugins;
2040 neighbor->plugins = rl;
2042 rl->neighbor = neighbor;
2043 rl->transmit_ready = GNUNET_YES;
2051 neighbor_timeout_task (void *cls,
2052 const struct GNUNET_SCHEDULER_TaskContext *tc)
2054 struct NeighborList *n = cls;
2057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2058 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2060 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2061 disconnect_neighbor (n, GNUNET_NO);
2066 * Create a fresh entry in our neighbor list for the given peer.
2067 * Will try to transmit our current HELLO to the new neighbor. Also
2068 * notifies our clients about the new "connection".
2070 * @param peer the peer for which we create the entry
2071 * @return the new neighbor list entry
2073 static struct NeighborList *
2074 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
2076 struct NeighborList *n;
2079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2080 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
2083 GNUNET_assert (our_hello != NULL);
2084 n = GNUNET_malloc (sizeof (struct NeighborList));
2085 n->next = neighbors;
2088 n->last_quota_update = GNUNET_TIME_absolute_get ();
2090 GNUNET_TIME_relative_to_absolute
2091 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2092 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2094 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2095 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2096 &neighbor_timeout_task, n);
2097 transmit_to_peer (NULL, 0,
2098 (const struct GNUNET_MessageHeader *) our_hello,
2100 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2105 * We have received a PING message from someone. Need to send a PONG message
2106 * in response to the peer by any means necessary. Of course, with something
2107 * like TCP where a connection exists, we may want to send it that way. But
2108 * we may not be able to make that distinction...
2110 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2111 const struct GNUNET_PeerIdentity *peer,
2112 const char *sender_address,
2113 size_t sender_address_len)
2115 struct TransportPlugin *plugin = cls;
2116 struct TransportPingMessage *ping;
2117 struct TransportPongMessage *pong;
2120 pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2124 "Processing `%s' from `%s'\n",
2125 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2128 msize = ntohs (message->size);
2129 if (msize < sizeof (struct TransportPingMessage))
2131 GNUNET_break_op (0);
2132 return GNUNET_SYSERR;
2134 ping = (struct TransportPingMessage *) message;
2135 if (0 != memcmp (&ping->target,
2136 plugin->env.my_identity,
2137 sizeof (struct GNUNET_PeerIdentity)))
2139 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2140 _("Received `%s' message not destined for me!\n"), "PING");
2141 return GNUNET_SYSERR;
2144 msize -= sizeof (struct TransportPingMessage);
2146 * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
2148 GNUNET_break_op (0);
2149 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2153 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
2156 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2160 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2161 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2162 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2163 pong->purpose.size =
2164 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2166 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2167 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2168 pong->challenge = ping->challenge;
2170 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2171 memcpy (&pong[1], sender_address, sender_address_len);
2172 GNUNET_assert (GNUNET_OK ==
2173 GNUNET_CRYPTO_rsa_sign (my_private_key,
2174 &pong->purpose, &pong->signature));
2176 transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, find_neighbor(peer, NULL, 0));
2177 /* plugin->api->send(); */ /* We can't directly send back along received address, because
2178 the port we saw for the peer (for TCP especially) will not
2179 likely be the open port on the other side! */
2185 * Function called by the plugin for each received message.
2186 * Update data volumes, possibly notify plugins about
2187 * reducing the rate at which they read from the socket
2188 * and generally forward to our receive callback.
2190 * @param cls the "struct TransportPlugin *" we gave to the plugin
2191 * @param message the message, NULL if peer was disconnected
2192 * @param distance the transport cost to this peer (not latency!)
2193 * @param sender_address the address that the sender reported
2194 * (opaque to transport service)
2195 * @param sender_address_len the length of the sender address
2196 * @param peer (claimed) identity of the other peer
2197 * @return the new service_context that the plugin should use
2198 * for future receive calls for messages from this
2203 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2204 const struct GNUNET_MessageHeader *message,
2205 unsigned int distance, const char *sender_address,
2206 size_t sender_address_len)
2208 const struct GNUNET_MessageHeader ack = {
2209 htons (sizeof (struct GNUNET_MessageHeader)),
2210 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2212 struct ReadyList *service_context;
2213 struct TransportPlugin *plugin = cls;
2214 struct TransportClient *cpos;
2215 struct InboundMessage *im;
2217 struct NeighborList *n;
2219 n = find_neighbor (peer, sender_address, sender_address_len);
2222 if (message == NULL)
2223 return; /* disconnect of peer already marked down */
2224 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2226 service_context = n->plugins;
2227 while ((service_context != NULL) && (plugin != service_context->plugin))
2228 service_context = service_context->next;
2229 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2230 if (message == NULL)
2233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2234 "Receive failed from `%4s', triggering disconnect\n",
2235 GNUNET_i2s (&n->id));
2237 /* TODO: call stats */
2238 if (service_context != NULL)
2239 service_context->connected = GNUNET_NO;
2240 disconnect_neighbor (n, GNUNET_YES);
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2245 "Processing message of type `%u' received by plugin...\n",
2246 ntohs (message->type));
2248 if (service_context != NULL)
2250 if (service_context->connected == GNUNET_NO)
2252 service_context->connected = GNUNET_YES;
2253 service_context->transmit_ready = GNUNET_YES;
2254 service_context->connect_attempts++;
2256 service_context->timeout
2258 GNUNET_TIME_relative_to_absolute
2259 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2260 /* service_context->latency = latency; */ /* This value should be set by us! */
2262 /* update traffic received amount ... */
2263 msize = ntohs (message->size);
2264 n->last_received += msize;
2265 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2267 GNUNET_TIME_relative_to_absolute
2268 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2270 GNUNET_SCHEDULER_add_delayed (sched,
2271 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2272 &neighbor_timeout_task, n);
2274 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2276 /* dropping message due to frequent inbound volume violations! */
2277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2278 GNUNET_ERROR_TYPE_BULK,
2280 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2281 /* TODO: call stats */
2282 GNUNET_assert ((service_context == NULL) ||
2283 (NULL != service_context->neighbor));
2286 switch (ntohs (message->type))
2288 case GNUNET_MESSAGE_TYPE_HELLO:
2290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2291 "Receiving `%s' message from `%4s'.\n", "HELLO",
2294 process_hello (plugin, message);
2296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2297 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2300 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2302 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2303 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2304 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2305 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2306 //plugin_env_notify_validation();
2307 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2308 n->saw_ack = GNUNET_YES;
2309 /* intentional fall-through! */
2312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2313 "Received message of type %u from `%4s', sending to all clients.\n",
2314 ntohs (message->type), GNUNET_i2s (peer));
2316 /* transmit message to all clients */
2317 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2318 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2319 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2320 im->latency = n->latency;
2322 memcpy (&im[1], message, msize);
2325 while (cpos != NULL)
2327 transmit_to_client (cpos, &im->header, GNUNET_YES);
2332 GNUNET_assert ((service_context == NULL) ||
2333 (NULL != service_context->neighbor));
2338 * Handle START-message. This is the first message sent to us
2339 * by any client which causes us to add it to our list.
2341 * @param cls closure (always NULL)
2342 * @param client identification of the client
2343 * @param message the actual message
2346 handle_start (void *cls,
2347 struct GNUNET_SERVER_Client *client,
2348 const struct GNUNET_MessageHeader *message)
2350 struct TransportClient *c;
2351 struct ConnectInfoMessage cim;
2352 struct NeighborList *n;
2353 struct InboundMessage *im;
2354 struct GNUNET_MessageHeader *ack;
2357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2358 "Received `%s' request from client\n", "START");
2363 if (c->client == client)
2365 /* client already on our list! */
2367 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2372 c = GNUNET_malloc (sizeof (struct TransportClient));
2376 if (our_hello != NULL)
2379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2380 "Sending our own `%s' to new client\n", "HELLO");
2382 transmit_to_client (c,
2383 (const struct GNUNET_MessageHeader *) our_hello,
2385 /* tell new client about all existing connections */
2386 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2387 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2389 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2390 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2391 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2392 sizeof (struct GNUNET_MessageHeader));
2393 im->header.size = htons (sizeof (struct InboundMessage) +
2394 sizeof (struct GNUNET_MessageHeader));
2395 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2396 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2397 ack = (struct GNUNET_MessageHeader *) &im[1];
2398 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2399 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2400 for (n = neighbors; n != NULL; n = n->next)
2403 transmit_to_client (c, &cim.header, GNUNET_NO);
2407 transmit_to_client (c, &im->header, GNUNET_NO);
2412 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2417 * Handle HELLO-message.
2419 * @param cls closure (always NULL)
2420 * @param client identification of the client
2421 * @param message the actual message
2424 handle_hello (void *cls,
2425 struct GNUNET_SERVER_Client *client,
2426 const struct GNUNET_MessageHeader *message)
2431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2432 "Received `%s' request from client\n", "HELLO");
2434 ret = process_hello (NULL, message);
2435 GNUNET_SERVER_receive_done (client, ret);
2440 * Handle SEND-message.
2442 * @param cls closure (always NULL)
2443 * @param client identification of the client
2444 * @param message the actual message
2447 handle_send (void *cls,
2448 struct GNUNET_SERVER_Client *client,
2449 const struct GNUNET_MessageHeader *message)
2451 struct TransportClient *tc;
2452 struct NeighborList *n;
2453 const struct OutboundMessage *obm;
2454 const struct GNUNET_MessageHeader *obmm;
2458 size = ntohs (message->size);
2460 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2463 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2466 obm = (const struct OutboundMessage *) message;
2468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469 "Received `%s' request from client with target `%4s'\n",
2470 "SEND", GNUNET_i2s (&obm->peer));
2472 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2473 msize = ntohs (obmm->size);
2474 if (size != msize + sizeof (struct OutboundMessage))
2477 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2480 n = find_neighbor (&obm->peer, NULL, 0);
2482 n = setup_new_neighbor (&obm->peer, NULL, 0);
2484 while ((tc != NULL) && (tc->client != client))
2488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2489 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2491 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2493 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2494 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2499 * Handle SET_QUOTA-message.
2501 * @param cls closure (always NULL)
2502 * @param client identification of the client
2503 * @param message the actual message
2506 handle_set_quota (void *cls,
2507 struct GNUNET_SERVER_Client *client,
2508 const struct GNUNET_MessageHeader *message)
2510 const struct QuotaSetMessage *qsm =
2511 (const struct QuotaSetMessage *) message;
2512 struct NeighborList *n;
2513 struct TransportPlugin *p;
2514 struct ReadyList *rl;
2517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2518 "Received `%s' request from client for peer `%4s'\n",
2519 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2521 n = find_neighbor (&qsm->peer, NULL, 0);
2524 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2528 if (n->quota_in < ntohl (qsm->quota_in))
2529 n->last_quota_update = GNUNET_TIME_absolute_get ();
2530 n->quota_in = ntohl (qsm->quota_in);
2535 p->api->set_receive_quota (p->api->cls,
2536 &qsm->peer, ntohl (qsm->quota_in));
2539 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2544 * Handle TRY_CONNECT-message.
2546 * @param cls closure (always NULL)
2547 * @param client identification of the client
2548 * @param message the actual message
2551 handle_try_connect (void *cls,
2552 struct GNUNET_SERVER_Client *client,
2553 const struct GNUNET_MessageHeader *message)
2555 const struct TryConnectMessage *tcm;
2557 tcm = (const struct TryConnectMessage *) message;
2559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2560 "Received `%s' request from client %p asking to connect to `%4s'\n",
2561 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2563 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2564 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2565 knowing its address? Should we ask the plugin
2566 for more information about this peer? I don't
2567 think we can... Or set up new peer should only
2568 happen when transport notifies us of an address,
2569 and this setup should check for an address in
2570 the existing list only */
2573 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2574 "Client asked to connect to `%4s', but connection already exists\n",
2575 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2577 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2581 transmit_address_to_client (void *cls, const char *address)
2583 struct GNUNET_SERVER_TransmitContext *tc = cls;
2586 if (NULL == address)
2589 slen = strlen (address) + 1;
2590 GNUNET_SERVER_transmit_context_append (tc, address, slen,
2591 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2592 if (NULL == address)
2593 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2597 * Handle AddressLookup-message.
2599 * @param cls closure (always NULL)
2600 * @param client identification of the client
2601 * @param message the actual message
2604 handle_address_lookup (void *cls,
2605 struct GNUNET_SERVER_Client *client,
2606 const struct GNUNET_MessageHeader *message)
2608 const struct AddressLookupMessage *alum;
2609 struct TransportPlugin *lsPlugin;
2610 const char *nameTransport;
2611 const char *address;
2613 struct GNUNET_SERVER_TransmitContext *tc;
2615 size = ntohs (message->size);
2616 if (size < sizeof (struct AddressLookupMessage))
2618 GNUNET_break_op (0);
2619 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2622 alum = (const struct AddressLookupMessage *) message;
2623 uint32_t addressLen = ntohl (alum->addrlen);
2624 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2626 GNUNET_break_op (0);
2627 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2630 address = (const char *) &alum[1];
2631 nameTransport = (const char *) &address[addressLen];
2633 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2635 GNUNET_break_op (0);
2636 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2639 struct GNUNET_TIME_Absolute timeout =
2640 GNUNET_TIME_absolute_ntoh (alum->timeout);
2641 struct GNUNET_TIME_Relative rtimeout =
2642 GNUNET_TIME_absolute_get_remaining (timeout);
2643 lsPlugin = find_transport (nameTransport);
2644 if (NULL == lsPlugin)
2646 tc = GNUNET_SERVER_transmit_context_create (client);
2647 GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
2648 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2649 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2652 tc = GNUNET_SERVER_transmit_context_create (client);
2653 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2654 address, addressLen, GNUNET_YES,
2656 &transmit_address_to_client, tc);
2660 * List of handlers for the messages understood by this
2663 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2664 {&handle_start, NULL,
2665 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2666 {&handle_hello, NULL,
2667 GNUNET_MESSAGE_TYPE_HELLO, 0},
2668 {&handle_send, NULL,
2669 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2670 {&handle_set_quota, NULL,
2671 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2672 {&handle_try_connect, NULL,
2673 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2674 sizeof (struct TryConnectMessage)},
2675 {&handle_address_lookup, NULL,
2676 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2683 * Setup the environment for this plugin.
2686 create_environment (struct TransportPlugin *plug)
2688 plug->env.cfg = cfg;
2689 plug->env.sched = sched;
2690 plug->env.my_identity = &my_identity;
2691 plug->env.cls = plug;
2692 plug->env.receive = &plugin_env_receive;
2693 plug->env.notify_address = &plugin_env_notify_address;
2694 plug->env.default_quota_in =
2695 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2696 plug->env.max_connections = max_connect_per_transport;
2701 * Start the specified transport (load the plugin).
2704 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2706 struct TransportPlugin *plug;
2709 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2710 _("Loading `%s' transport plugin\n"), name);
2711 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2712 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2713 create_environment (plug);
2714 plug->short_name = GNUNET_strdup (name);
2715 plug->lib_name = libname;
2716 plug->next = plugins;
2718 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2719 if (plug->api == NULL)
2721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2722 _("Failed to load transport plugin for `%s'\n"), name);
2723 GNUNET_free (plug->short_name);
2724 plugins = plug->next;
2725 GNUNET_free (libname);
2732 * Called whenever a client is disconnected. Frees our
2733 * resources associated with that client.
2735 * @param cls closure
2736 * @param client identification of the client
2739 client_disconnect_notification (void *cls,
2740 struct GNUNET_SERVER_Client *client)
2742 struct TransportClient *pos;
2743 struct TransportClient *prev;
2744 struct ClientMessageQueueEntry *mqe;
2749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2750 "Client disconnected, cleaning up.\n");
2754 while ((pos != NULL) && (pos->client != client))
2761 while (NULL != (mqe = pos->message_queue_head))
2763 pos->message_queue_head = mqe->next;
2766 pos->message_queue_head = NULL;
2768 clients = pos->next;
2770 prev->next = pos->next;
2771 if (GNUNET_YES == pos->tcs_pending)
2781 * Function called when the service shuts down. Unloads our plugins.
2783 * @param cls closure, unused
2784 * @param tc task context (unused)
2787 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2789 struct TransportPlugin *plug;
2790 struct AddressList *al;
2793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2794 "Transport service is unloading plugins...\n");
2796 while (NULL != (plug = plugins))
2798 plugins = plug->next;
2799 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2800 GNUNET_free (plug->lib_name);
2801 GNUNET_free (plug->short_name);
2802 while (NULL != (al = plug->addresses))
2804 plug->addresses = al->next;
2809 if (my_private_key != NULL)
2810 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2811 GNUNET_free_non_null (our_hello);
2816 * Initiate transport service.
2818 * @param cls closure
2819 * @param s scheduler to use
2820 * @param serv the initialized server
2821 * @param c configuration to use
2825 struct GNUNET_SCHEDULER_Handle *s,
2826 struct GNUNET_SERVER_Handle *serv,
2827 const struct GNUNET_CONFIGURATION_Handle *c)
2832 unsigned long long tneigh;
2837 /* parse configuration */
2839 GNUNET_CONFIGURATION_get_value_number (c,
2844 GNUNET_CONFIGURATION_get_value_filename (c,
2846 "HOSTKEY", &keyfile)))
2848 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2850 ("Transport service is lacking key configuration settings. Exiting.\n"));
2851 GNUNET_SCHEDULER_shutdown (s);
2854 max_connect_per_transport = (uint32_t) tneigh;
2855 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2856 GNUNET_free (keyfile);
2857 if (my_private_key == NULL)
2859 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2861 ("Transport service could not access hostkey. Exiting.\n"));
2862 GNUNET_SCHEDULER_shutdown (s);
2865 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2866 GNUNET_CRYPTO_hash (&my_public_key,
2867 sizeof (my_public_key), &my_identity.hashPubKey);
2868 /* setup notification */
2870 GNUNET_SERVER_disconnect_notify (server,
2871 &client_disconnect_notification, NULL);
2872 /* load plugins... */
2875 GNUNET_CONFIGURATION_get_value_string (c,
2876 "TRANSPORT", "PLUGINS", &plugs))
2878 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2879 _("Starting transport plugins `%s'\n"), plugs);
2880 pos = strtok (plugs, " ");
2883 start_transport (server, pos);
2885 pos = strtok (NULL, " ");
2887 GNUNET_free (plugs);
2889 GNUNET_SCHEDULER_add_delayed (sched,
2890 GNUNET_TIME_UNIT_FOREVER_REL,
2891 &unload_plugins, NULL);
2895 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2897 /* process client requests */
2898 GNUNET_SERVER_add_handlers (server, handlers);
2903 * The main function for the transport service.
2905 * @param argc number of arguments from the command line
2906 * @param argv command line arguments
2907 * @return 0 ok, 1 on error
2910 main (int argc, char *const *argv)
2912 return (GNUNET_OK ==
2913 GNUNET_SERVICE_run (argc,
2916 GNUNET_SERVICE_OPTION_NONE,
2917 &run, NULL)) ? 0 : 1;
2920 /* end of gnunet-service-transport.c */