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, 30)
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;
1163 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 = htons(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)))
1612 /* TODO: call statistics (unmatched PONG) */
1613 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1615 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1616 GNUNET_i2s (peer), count);
1620 matched = GNUNET_NO;
1621 va = pos->addresses;
1624 if (va->challenge == challenge)
1627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1628 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1630 GNUNET_a2s ((const struct sockaddr *) sender_address,
1631 sender_address_len));
1633 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1635 ("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 GNUNET_a2s ((const struct sockaddr *) &va[1],
1638 va->ok = GNUNET_YES;
1640 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1641 matched = GNUNET_YES;
1643 if (va->ok != GNUNET_YES)
1647 if (GNUNET_NO == matched)
1649 /* TODO: call statistics (unmatched PONG) */
1650 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1652 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1659 "All addresses validated, will now construct `%s' for `%4s'.\n",
1660 "HELLO", GNUNET_i2s (peer));
1662 pos->timeout.value = 0;
1663 GNUNET_SCHEDULER_add_with_priority (sched,
1664 GNUNET_SCHEDULER_PRIORITY_IDLE,
1665 &cleanup_validation, NULL);
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1672 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1678 struct CheckHelloValidatedContext
1681 * Plugin for which we are validating.
1683 struct TransportPlugin *plugin;
1686 * Hello that we are validating.
1688 struct GNUNET_HELLO_Message *hello;
1691 * Validation list being build.
1693 struct ValidationList *e;
1696 * Context for peerinfo iteration.
1697 * NULL after we are done processing peerinfo's information.
1699 struct GNUNET_PEERINFO_IteratorContext *piter;
1705 * Append the given address to the list of entries
1706 * that need to be validated.
1709 run_validation (void *cls,
1711 struct GNUNET_TIME_Absolute expiration,
1712 const void *addr, size_t addrlen)
1714 struct ValidationList *e = cls;
1715 struct TransportPlugin *tp;
1716 struct ValidationAddress *va;
1717 struct GNUNET_PeerIdentity id;
1718 struct GNUNET_MessageHeader *pingMessage;
1720 tp = find_transport (tname);
1723 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1724 GNUNET_ERROR_TYPE_BULK,
1726 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1730 GNUNET_CRYPTO_hash (&e->publicKey,
1732 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1735 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1736 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1738 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1739 va->next = e->addresses;
1741 va->transport_name = GNUNET_strdup (tname);
1742 va->addr_len = addrlen;
1743 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1745 memcpy (&va[1], addr, addrlen);
1747 pingMessage = createPingMessage(&id, va);
1749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message to address `%s' via `%s' for `%4s'\n",
1750 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1753 sent = tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1754 TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
1756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
1758 GNUNET_free(pingMessage);
1764 * @param cls handle to the plugin (for sending)
1765 * @param target the peer identity of the peer we are sending to
1766 * @param challenge the challenge number
1767 * @param timeout how long to await validation?
1768 * @param addr the address to validate
1769 * @param addrlen the length of the address
1771 * Perform address validation, which means sending a PING PONG to
1772 * the address via the transport plugin. If not validated, then
1773 * do not count this as a good peer/address...
1777 validate_address (void *cls, struct ValidationAddress *va,
1778 const struct GNUNET_PeerIdentity *target,
1779 struct GNUNET_TIME_Relative timeout,
1780 const void *addr, size_t addrlen)
1782 /* struct Plugin *plugin = cls;
1783 int challenge = va->challenge; */
1791 * Check if addresses in validated hello "h" overlap with
1792 * those in "chvc->hello" and update "chvc->hello" accordingly,
1793 * removing those addresses that have already been validated.
1796 check_hello_validated (void *cls,
1797 const struct GNUNET_PeerIdentity *peer,
1798 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1800 struct CheckHelloValidatedContext *chvc = cls;
1801 struct ValidationAddress *va;
1802 struct TransportPlugin *tp;
1804 struct GNUNET_PeerIdentity apeer;
1806 first_call = GNUNET_NO;
1807 if (chvc->e == NULL)
1810 first_call = GNUNET_YES;
1811 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1812 GNUNET_assert (GNUNET_OK ==
1813 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1814 &chvc->e->publicKey));
1816 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1817 chvc->e->next = pending_validations;
1818 pending_validations = chvc->e;
1822 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1824 GNUNET_TIME_absolute_get (),
1825 &run_validation, chvc->e);
1827 else if (GNUNET_YES == first_call)
1829 /* no existing HELLO, all addresses are new */
1830 GNUNET_HELLO_iterate_addresses (chvc->hello,
1831 GNUNET_NO, &run_validation, chvc->e);
1834 return; /* wait for next call */
1835 /* finally, transmit validation attempts */
1836 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1839 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1840 "HELLO", GNUNET_i2s (&apeer));
1842 va = chvc->e->addresses;
1846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1847 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1850 GNUNET_a2s ((const struct sockaddr *) &va[1],
1851 va->addr_len), GNUNET_i2s (&apeer));
1853 tp = find_transport (va->transport_name);
1854 GNUNET_assert (tp != NULL);
1855 /* This validation should happen inside the transport, not from the plugin! */
1856 validate_address (tp->api->cls, va, &apeer,
1857 HELLO_VERIFICATION_TIMEOUT,
1858 &va[1], va->addr_len);
1859 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1862 GNUNET_SCHEDULER_add_delayed (sched,
1863 GNUNET_TIME_absolute_get_remaining (chvc->
1865 &cleanup_validation, NULL);
1871 * Process HELLO-message.
1873 * @param plugin transport involved, may be NULL
1874 * @param message the actual message
1875 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1878 process_hello (struct TransportPlugin *plugin,
1879 const struct GNUNET_MessageHeader *message)
1881 struct ValidationList *e;
1883 struct GNUNET_PeerIdentity target;
1884 const struct GNUNET_HELLO_Message *hello;
1885 struct CheckHelloValidatedContext *chvc;
1886 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1888 hsize = ntohs (message->size);
1889 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1890 (hsize < sizeof (struct GNUNET_MessageHeader)))
1893 return GNUNET_SYSERR;
1895 /* first, check if load is too high */
1896 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1898 /* TODO: call to stats? */
1901 hello = (const struct GNUNET_HELLO_Message *) message;
1902 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1904 GNUNET_break_op (0);
1905 return GNUNET_SYSERR;
1907 GNUNET_CRYPTO_hash (&publicKey,
1908 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1909 &target.hashPubKey);
1911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1912 "Processing `%s' message for `%4s'\n",
1913 "HELLO", GNUNET_i2s (&target));
1915 /* check if a HELLO for this peer is already on the validation list */
1916 e = pending_validations;
1919 if (0 == memcmp (&e->publicKey,
1922 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1924 /* TODO: call to stats? */
1926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1927 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1928 "HELLO", GNUNET_i2s (&target));
1934 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1935 chvc->plugin = plugin;
1936 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1937 memcpy (chvc->hello, hello, hsize);
1938 /* finally, check if HELLO was previously validated
1939 (continuation will then schedule actual validation) */
1940 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1944 HELLO_VERIFICATION_TIMEOUT,
1945 &check_hello_validated, chvc);
1951 * The peer specified by the given neighbor has timed-out or a plugin
1952 * has disconnected. We may either need to do nothing (other plugins
1953 * still up), or trigger a full disconnect and clean up. This
1954 * function updates our state and do the necessary notifications.
1955 * Also notifies our clients that the neighbor is now officially
1958 * @param n the neighbor list entry for the peer
1959 * @param check should we just check if all plugins
1960 * disconnected or must we ask all plugins to
1964 disconnect_neighbor (struct NeighborList *n, int check)
1966 struct ReadyList *rpos;
1967 struct NeighborList *npos;
1968 struct NeighborList *nprev;
1969 struct MessageQueue *mq;
1971 if (GNUNET_YES == check)
1974 while (NULL != rpos)
1976 if (GNUNET_YES == rpos->connected)
1977 return; /* still connected */
1983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1984 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
1986 /* remove n from neighbors list */
1989 while ((npos != NULL) && (npos != n))
1994 GNUNET_assert (npos != NULL);
1996 neighbors = n->next;
1998 nprev->next = n->next;
2000 /* notify all clients about disconnect */
2001 notify_clients_disconnect (&n->id);
2003 /* clean up all plugins, cancel connections and pending transmissions */
2004 while (NULL != (rpos = n->plugins))
2006 n->plugins = rpos->next;
2007 GNUNET_assert (rpos->neighbor == n);
2008 if (GNUNET_YES == rpos->connected)
2009 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2013 /* free all messages on the queue */
2014 while (NULL != (mq = n->messages))
2016 n->messages = mq->next;
2017 GNUNET_assert (mq->neighbor == n);
2020 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2021 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2022 /* finally, free n itself */
2028 * Add an entry for each of our transport plugins
2029 * (that are able to send) to the list of plugins
2030 * for this neighbor.
2032 * @param neighbor to initialize
2035 add_plugins (struct NeighborList *neighbor)
2037 struct TransportPlugin *tp;
2038 struct ReadyList *rl;
2040 neighbor->retry_plugins_time
2041 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2045 if (tp->api->send != NULL)
2047 rl = GNUNET_malloc (sizeof (struct ReadyList));
2048 rl->next = neighbor->plugins;
2049 neighbor->plugins = rl;
2051 rl->neighbor = neighbor;
2052 rl->transmit_ready = GNUNET_YES;
2060 neighbor_timeout_task (void *cls,
2061 const struct GNUNET_SCHEDULER_TaskContext *tc)
2063 struct NeighborList *n = cls;
2066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2067 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2069 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2070 disconnect_neighbor (n, GNUNET_NO);
2075 * Create a fresh entry in our neighbor list for the given peer.
2076 * Will try to transmit our current HELLO to the new neighbor. Also
2077 * notifies our clients about the new "connection".
2079 * @param peer the peer for which we create the entry
2080 * @return the new neighbor list entry
2082 static struct NeighborList *
2083 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
2085 struct NeighborList *n;
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2089 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
2092 GNUNET_assert (our_hello != NULL);
2093 n = GNUNET_malloc (sizeof (struct NeighborList));
2094 n->next = neighbors;
2097 n->last_quota_update = GNUNET_TIME_absolute_get ();
2099 GNUNET_TIME_relative_to_absolute
2100 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2101 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2103 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2104 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2105 &neighbor_timeout_task, n);
2106 transmit_to_peer (NULL, 0,
2107 (const struct GNUNET_MessageHeader *) our_hello,
2109 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2114 * We have received a PING message from someone. Need to send a PONG message
2115 * in response to the peer by any means necessary. Of course, with something
2116 * like TCP where a connection exists, we may want to send it that way. But
2117 * we may not be able to make that distinction...
2119 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2120 const struct GNUNET_PeerIdentity *peer,
2121 const char *sender_address,
2122 size_t sender_address_len)
2124 struct TransportPlugin *plugin = cls;
2125 struct TransportPingMessage *ping;
2126 struct TransportPongMessage *pong;
2129 pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2133 "Processing `%s' from `%s'\n",
2134 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2137 msize = ntohs (message->size);
2138 if (msize < sizeof (struct TransportPingMessage))
2140 GNUNET_break_op (0);
2141 return GNUNET_SYSERR;
2143 ping = (struct TransportPingMessage *) message;
2144 if (0 != memcmp (&ping->target,
2145 plugin->env.my_identity,
2146 sizeof (struct GNUNET_PeerIdentity)))
2148 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2149 _("Received `%s' message not destined for me!\n"), "PING");
2150 return GNUNET_SYSERR;
2153 msize -= sizeof (struct TransportPingMessage);
2155 * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
2157 GNUNET_break_op (0);
2158 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2162 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
2165 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2169 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2170 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2171 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2172 pong->purpose.size =
2173 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2175 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2176 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2177 pong->challenge = ping->challenge;
2179 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2180 memcpy (&pong[1], sender_address, sender_address_len);
2181 GNUNET_assert (GNUNET_OK ==
2182 GNUNET_CRYPTO_rsa_sign (my_private_key,
2183 &pong->purpose, &pong->signature));
2185 transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, find_neighbor(peer, NULL, 0));
2186 /* plugin->api->send(); */ /* We can't directly send back along received address, because
2187 the port we saw for the peer (for TCP especially) will not
2188 likely be the open port on the other side! */
2194 * Function called by the plugin for each received message.
2195 * Update data volumes, possibly notify plugins about
2196 * reducing the rate at which they read from the socket
2197 * and generally forward to our receive callback.
2199 * @param cls the "struct TransportPlugin *" we gave to the plugin
2200 * @param message the message, NULL if peer was disconnected
2201 * @param distance the transport cost to this peer (not latency!)
2202 * @param sender_address the address that the sender reported
2203 * (opaque to transport service)
2204 * @param sender_address_len the length of the sender address
2205 * @param peer (claimed) identity of the other peer
2206 * @return the new service_context that the plugin should use
2207 * for future receive calls for messages from this
2212 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2213 const struct GNUNET_MessageHeader *message,
2214 unsigned int distance, const char *sender_address,
2215 size_t sender_address_len)
2217 const struct GNUNET_MessageHeader ack = {
2218 htons (sizeof (struct GNUNET_MessageHeader)),
2219 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2221 struct ReadyList *service_context;
2222 struct TransportPlugin *plugin = cls;
2223 struct TransportClient *cpos;
2224 struct InboundMessage *im;
2226 struct NeighborList *n;
2228 n = find_neighbor (peer, sender_address, sender_address_len);
2231 if (message == NULL)
2232 return; /* disconnect of peer already marked down */
2233 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2235 service_context = n->plugins;
2236 while ((service_context != NULL) && (plugin != service_context->plugin))
2237 service_context = service_context->next;
2238 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2239 if (message == NULL)
2242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2243 "Receive failed from `%4s', triggering disconnect\n",
2244 GNUNET_i2s (&n->id));
2246 /* TODO: call stats */
2247 if (service_context != NULL)
2248 service_context->connected = GNUNET_NO;
2249 disconnect_neighbor (n, GNUNET_YES);
2253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2254 "Processing message of type `%u' received by plugin...\n",
2255 ntohs (message->type));
2257 if (service_context != NULL)
2259 if (service_context->connected == GNUNET_NO)
2261 service_context->connected = GNUNET_YES;
2262 service_context->transmit_ready = GNUNET_YES;
2263 service_context->connect_attempts++;
2265 service_context->timeout
2267 GNUNET_TIME_relative_to_absolute
2268 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2269 /* service_context->latency = latency; */ /* This value should be set by us! */
2271 /* update traffic received amount ... */
2272 msize = ntohs (message->size);
2273 n->last_received += msize;
2274 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2276 GNUNET_TIME_relative_to_absolute
2277 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2279 GNUNET_SCHEDULER_add_delayed (sched,
2280 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2281 &neighbor_timeout_task, n);
2283 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2285 /* dropping message due to frequent inbound volume violations! */
2286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2287 GNUNET_ERROR_TYPE_BULK,
2289 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2290 /* TODO: call stats */
2291 GNUNET_assert ((service_context == NULL) ||
2292 (NULL != service_context->neighbor));
2295 switch (ntohs (message->type))
2297 case GNUNET_MESSAGE_TYPE_HELLO:
2299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2300 "Receiving `%s' message from `%4s'.\n", "HELLO",
2303 process_hello (plugin, message);
2305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2306 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2309 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2311 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2312 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2314 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2315 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2317 //plugin_env_notify_validation();
2318 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2319 n->saw_ack = GNUNET_YES;
2320 /* intentional fall-through! */
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324 "Received message of type %u from `%4s', sending to all clients.\n",
2325 ntohs (message->type), GNUNET_i2s (peer));
2327 /* transmit message to all clients */
2328 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2329 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2330 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2331 im->latency = n->latency;
2333 memcpy (&im[1], message, msize);
2336 while (cpos != NULL)
2338 transmit_to_client (cpos, &im->header, GNUNET_YES);
2343 GNUNET_assert ((service_context == NULL) ||
2344 (NULL != service_context->neighbor));
2349 * Handle START-message. This is the first message sent to us
2350 * by any client which causes us to add it to our list.
2352 * @param cls closure (always NULL)
2353 * @param client identification of the client
2354 * @param message the actual message
2357 handle_start (void *cls,
2358 struct GNUNET_SERVER_Client *client,
2359 const struct GNUNET_MessageHeader *message)
2361 struct TransportClient *c;
2362 struct ConnectInfoMessage cim;
2363 struct NeighborList *n;
2364 struct InboundMessage *im;
2365 struct GNUNET_MessageHeader *ack;
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Received `%s' request from client\n", "START");
2374 if (c->client == client)
2376 /* client already on our list! */
2378 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2383 c = GNUNET_malloc (sizeof (struct TransportClient));
2387 if (our_hello != NULL)
2390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2391 "Sending our own `%s' to new client\n", "HELLO");
2393 transmit_to_client (c,
2394 (const struct GNUNET_MessageHeader *) our_hello,
2396 /* tell new client about all existing connections */
2397 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2398 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2400 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2401 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2402 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2403 sizeof (struct GNUNET_MessageHeader));
2404 im->header.size = htons (sizeof (struct InboundMessage) +
2405 sizeof (struct GNUNET_MessageHeader));
2406 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2407 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2408 ack = (struct GNUNET_MessageHeader *) &im[1];
2409 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2410 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2411 for (n = neighbors; n != NULL; n = n->next)
2414 transmit_to_client (c, &cim.header, GNUNET_NO);
2418 transmit_to_client (c, &im->header, GNUNET_NO);
2425 fprintf(stderr, "Our hello is NULL!\n");
2427 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2432 * Handle HELLO-message.
2434 * @param cls closure (always NULL)
2435 * @param client identification of the client
2436 * @param message the actual message
2439 handle_hello (void *cls,
2440 struct GNUNET_SERVER_Client *client,
2441 const struct GNUNET_MessageHeader *message)
2446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2447 "Received `%s' request from client\n", "HELLO");
2449 ret = process_hello (NULL, message);
2450 GNUNET_SERVER_receive_done (client, ret);
2455 * Handle SEND-message.
2457 * @param cls closure (always NULL)
2458 * @param client identification of the client
2459 * @param message the actual message
2462 handle_send (void *cls,
2463 struct GNUNET_SERVER_Client *client,
2464 const struct GNUNET_MessageHeader *message)
2466 struct TransportClient *tc;
2467 struct NeighborList *n;
2468 const struct OutboundMessage *obm;
2469 const struct GNUNET_MessageHeader *obmm;
2473 size = ntohs (message->size);
2475 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2478 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2481 obm = (const struct OutboundMessage *) message;
2483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484 "Received `%s' request from client with target `%4s'\n",
2485 "SEND", GNUNET_i2s (&obm->peer));
2487 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2488 msize = ntohs (obmm->size);
2489 if (size != msize + sizeof (struct OutboundMessage))
2492 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2495 n = find_neighbor (&obm->peer, NULL, 0);
2497 n = setup_new_neighbor (&obm->peer, NULL, 0);
2499 while ((tc != NULL) && (tc->client != client))
2503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2504 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2506 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2508 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2509 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2514 * Handle SET_QUOTA-message.
2516 * @param cls closure (always NULL)
2517 * @param client identification of the client
2518 * @param message the actual message
2521 handle_set_quota (void *cls,
2522 struct GNUNET_SERVER_Client *client,
2523 const struct GNUNET_MessageHeader *message)
2525 const struct QuotaSetMessage *qsm =
2526 (const struct QuotaSetMessage *) message;
2527 struct NeighborList *n;
2528 struct TransportPlugin *p;
2529 struct ReadyList *rl;
2532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2533 "Received `%s' request from client for peer `%4s'\n",
2534 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2536 n = find_neighbor (&qsm->peer, NULL, 0);
2539 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2543 if (n->quota_in < ntohl (qsm->quota_in))
2544 n->last_quota_update = GNUNET_TIME_absolute_get ();
2545 n->quota_in = ntohl (qsm->quota_in);
2550 p->api->set_receive_quota (p->api->cls,
2551 &qsm->peer, ntohl (qsm->quota_in));
2554 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2559 * Handle TRY_CONNECT-message.
2561 * @param cls closure (always NULL)
2562 * @param client identification of the client
2563 * @param message the actual message
2566 handle_try_connect (void *cls,
2567 struct GNUNET_SERVER_Client *client,
2568 const struct GNUNET_MessageHeader *message)
2570 const struct TryConnectMessage *tcm;
2572 tcm = (const struct TryConnectMessage *) message;
2574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2575 "Received `%s' request from client %p asking to connect to `%4s'\n",
2576 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2578 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2579 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2580 knowing its address? Should we ask the plugin
2581 for more information about this peer? I don't
2582 think we can... Or set up new peer should only
2583 happen when transport notifies us of an address,
2584 and this setup should check for an address in
2585 the existing list only */
2588 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2589 "Client asked to connect to `%4s', but connection already exists\n",
2590 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2592 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2596 transmit_address_to_client (void *cls, const char *address)
2598 struct GNUNET_SERVER_TransmitContext *tc = cls;
2601 if (NULL == address)
2604 slen = strlen (address) + 1;
2605 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2606 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2607 if (NULL == address)
2608 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2612 * Handle AddressLookup-message.
2614 * @param cls closure (always NULL)
2615 * @param client identification of the client
2616 * @param message the actual message
2619 handle_address_lookup (void *cls,
2620 struct GNUNET_SERVER_Client *client,
2621 const struct GNUNET_MessageHeader *message)
2623 const struct AddressLookupMessage *alum;
2624 struct TransportPlugin *lsPlugin;
2625 const char *nameTransport;
2626 const char *address;
2628 struct GNUNET_SERVER_TransmitContext *tc;
2630 size = ntohs (message->size);
2631 if (size < sizeof (struct AddressLookupMessage))
2633 GNUNET_break_op (0);
2634 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2637 alum = (const struct AddressLookupMessage *) message;
2638 uint32_t addressLen = ntohl (alum->addrlen);
2639 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2641 GNUNET_break_op (0);
2642 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2645 address = (const char *) &alum[1];
2646 nameTransport = (const char *) &address[addressLen];
2648 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2650 GNUNET_break_op (0);
2651 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2654 struct GNUNET_TIME_Absolute timeout =
2655 GNUNET_TIME_absolute_ntoh (alum->timeout);
2656 struct GNUNET_TIME_Relative rtimeout =
2657 GNUNET_TIME_absolute_get_remaining (timeout);
2658 lsPlugin = find_transport (nameTransport);
2659 if (NULL == lsPlugin)
2661 tc = GNUNET_SERVER_transmit_context_create (client);
2662 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2663 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2664 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2667 tc = GNUNET_SERVER_transmit_context_create (client);
2668 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2669 address, addressLen, GNUNET_YES,
2671 &transmit_address_to_client, tc);
2675 * List of handlers for the messages understood by this
2678 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2679 {&handle_start, NULL,
2680 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2681 {&handle_hello, NULL,
2682 GNUNET_MESSAGE_TYPE_HELLO, 0},
2683 {&handle_send, NULL,
2684 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2685 {&handle_set_quota, NULL,
2686 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2687 {&handle_try_connect, NULL,
2688 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2689 sizeof (struct TryConnectMessage)},
2690 {&handle_address_lookup, NULL,
2691 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2698 * Setup the environment for this plugin.
2701 create_environment (struct TransportPlugin *plug)
2703 plug->env.cfg = cfg;
2704 plug->env.sched = sched;
2705 plug->env.my_identity = &my_identity;
2706 plug->env.cls = plug;
2707 plug->env.receive = &plugin_env_receive;
2708 plug->env.notify_address = &plugin_env_notify_address;
2709 plug->env.default_quota_in =
2710 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2711 plug->env.max_connections = max_connect_per_transport;
2716 * Start the specified transport (load the plugin).
2719 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2721 struct TransportPlugin *plug;
2724 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2725 _("Loading `%s' transport plugin\n"), name);
2726 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2727 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2728 create_environment (plug);
2729 plug->short_name = GNUNET_strdup (name);
2730 plug->lib_name = libname;
2731 plug->next = plugins;
2733 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2734 if (plug->api == NULL)
2736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2737 _("Failed to load transport plugin for `%s'\n"), name);
2738 GNUNET_free (plug->short_name);
2739 plugins = plug->next;
2740 GNUNET_free (libname);
2747 * Called whenever a client is disconnected. Frees our
2748 * resources associated with that client.
2750 * @param cls closure
2751 * @param client identification of the client
2754 client_disconnect_notification (void *cls,
2755 struct GNUNET_SERVER_Client *client)
2757 struct TransportClient *pos;
2758 struct TransportClient *prev;
2759 struct ClientMessageQueueEntry *mqe;
2764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2765 "Client disconnected, cleaning up.\n");
2769 while ((pos != NULL) && (pos->client != client))
2776 while (NULL != (mqe = pos->message_queue_head))
2778 pos->message_queue_head = mqe->next;
2781 pos->message_queue_head = NULL;
2783 clients = pos->next;
2785 prev->next = pos->next;
2786 if (GNUNET_YES == pos->tcs_pending)
2796 * Function called when the service shuts down. Unloads our plugins.
2798 * @param cls closure, unused
2799 * @param tc task context (unused)
2802 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2804 struct TransportPlugin *plug;
2805 struct AddressList *al;
2808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2809 "Transport service is unloading plugins...\n");
2811 while (NULL != (plug = plugins))
2813 plugins = plug->next;
2814 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2815 GNUNET_free (plug->lib_name);
2816 GNUNET_free (plug->short_name);
2817 while (NULL != (al = plug->addresses))
2819 plug->addresses = al->next;
2824 if (my_private_key != NULL)
2825 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2826 GNUNET_free_non_null (our_hello);
2831 * Initiate transport service.
2833 * @param cls closure
2834 * @param s scheduler to use
2835 * @param serv the initialized server
2836 * @param c configuration to use
2840 struct GNUNET_SCHEDULER_Handle *s,
2841 struct GNUNET_SERVER_Handle *serv,
2842 const struct GNUNET_CONFIGURATION_Handle *c)
2847 unsigned long long tneigh;
2852 /* parse configuration */
2854 GNUNET_CONFIGURATION_get_value_number (c,
2859 GNUNET_CONFIGURATION_get_value_filename (c,
2861 "HOSTKEY", &keyfile)))
2863 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2865 ("Transport service is lacking key configuration settings. Exiting.\n"));
2866 GNUNET_SCHEDULER_shutdown (s);
2869 max_connect_per_transport = (uint32_t) tneigh;
2870 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2871 GNUNET_free (keyfile);
2872 if (my_private_key == NULL)
2874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2876 ("Transport service could not access hostkey. Exiting.\n"));
2877 GNUNET_SCHEDULER_shutdown (s);
2880 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2881 GNUNET_CRYPTO_hash (&my_public_key,
2882 sizeof (my_public_key), &my_identity.hashPubKey);
2883 /* setup notification */
2885 GNUNET_SERVER_disconnect_notify (server,
2886 &client_disconnect_notification, NULL);
2887 /* load plugins... */
2890 GNUNET_CONFIGURATION_get_value_string (c,
2891 "TRANSPORT", "PLUGINS", &plugs))
2893 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2894 _("Starting transport plugins `%s'\n"), plugs);
2895 pos = strtok (plugs, " ");
2898 start_transport (server, pos);
2900 pos = strtok (NULL, " ");
2902 GNUNET_free (plugs);
2904 GNUNET_SCHEDULER_add_delayed (sched,
2905 GNUNET_TIME_UNIT_FOREVER_REL,
2906 &unload_plugins, NULL);
2911 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2913 /* process client requests */
2914 GNUNET_SERVER_add_handlers (server, handlers);
2919 * The main function for the transport service.
2921 * @param argc number of arguments from the command line
2922 * @param argv command line arguments
2923 * @return 0 ok, 1 on error
2926 main (int argc, char *const *argv)
2928 return (GNUNET_OK ==
2929 GNUNET_SERVICE_run (argc,
2932 GNUNET_SERVICE_OPTION_NONE,
2933 &run, NULL)) ? 0 : 1;
2936 /* end of gnunet-service-transport.c */