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 * List of addresses of other peers
102 struct PeerAddressList
105 * This is a linked list.
107 struct PeerAddressList *next;
110 * Pointer to the validation associated with this
111 * address. May be NULL if already validated!
113 struct ValidationAddress *validation;
116 * Which of our transport plugins does this entry
119 struct TransportPlugin *plugin;
122 * Neighbor this entry belongs to.
124 struct NeighborList *neighbor;
127 * Ready list (transport) that this peer belongs to
129 struct ReadyList *ready_list;
131 * How long until we auto-expire this address (unless it is
132 * re-confirmed by the transport)?
134 struct GNUNET_TIME_Absolute expires;
147 * Is this plugin ready to transmit to the specific target?
148 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
149 * transmission is in progress, "transmit_ready" is set to
155 * What was the last latency observed for this plugin
156 * and peer? Invalid if connected is GNUNET_NO.
158 struct GNUNET_TIME_Relative latency;
161 * If we did not successfully transmit a message to the given peer
162 * via this connection during the specified time, we should consider
163 * the connection to be dead. This is used in the case that a TCP
164 * transport simply stalls writing to the stream but does not
165 * formerly get a signal that the other peer died.
167 struct GNUNET_TIME_Absolute timeout;
170 * Is this plugin currently connected? The first time
171 * we transmit or send data to a peer via a particular
172 * plugin, we set this to GNUNET_YES. If we later get
173 * an error (disconnect notification or transmission
174 * failure), we set it back to GNUNET_NO. Each time the
175 * value is set to GNUNET_YES, we increment the
176 * "connect_attempts" counter. If that one reaches a
177 * particular threshold, we consider the plugin to not
178 * be working properly at this time for the given peer
179 * and remove it from the eligible list.
184 * How often have we tried to connect using this plugin?
186 unsigned int connect_attempts;
192 * Entry in linked list of network addresses.
197 * This is a linked list.
199 struct AddressList *next;
202 * The address, actually a pointer to the end
203 * of this struct. Do not free!
208 * How long until we auto-expire this address (unless it is
209 * re-confirmed by the transport)?
211 struct GNUNET_TIME_Absolute expires;
222 * Entry in linked list of all of our plugins.
224 struct TransportPlugin
228 * This is a linked list.
230 struct TransportPlugin *next;
233 * API of the transport as returned by the plugin's
234 * initialization function.
236 struct GNUNET_TRANSPORT_PluginFunctions *api;
239 * Short name for the plugin (i.e. "tcp").
244 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
249 * List of our known addresses for this transport.
251 struct AddressList *addresses;
254 * Environment this transport service is using
257 struct GNUNET_TRANSPORT_PluginEnvironment env;
260 * ID of task that is used to clean up expired addresses.
262 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
266 * Set to GNUNET_YES if we need to scrap the existing
267 * list of "addresses" and start fresh when we receive
268 * the next address update from a transport. Set to
269 * GNUNET_NO if we should just add the new address
270 * to the list and wait for the commit call.
278 * For each neighbor we keep a list of messages
279 * that we still want to transmit to the neighbor.
285 * This is a linked list.
287 struct MessageQueue *next;
290 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
291 * stuck together in memory.
296 * Size of the message buf
298 size_t message_buf_size;
301 * Client responsible for queueing the message;
302 * used to check that a client has no two messages
303 * pending for the same target. Can be NULL.
305 struct TransportClient *client;
308 * Neighbor this entry belongs to.
310 struct NeighborList *neighbor;
313 * Plugin that we used for the transmission.
314 * NULL until we scheduled a transmission.
316 struct TransportPlugin *plugin;
319 * Internal message of the transport system that should not be
320 * included in the usual SEND-SEND_OK transmission confirmation
321 * traffic management scheme. Typically, "internal_msg" will
322 * be set whenever "client" is NULL (but it is not strictly
328 * How important is the message?
330 unsigned int priority;
333 * Using which specific address should we send this message?
335 struct PeerAddressList *specific_peer;
341 * For a given Neighbor, which plugins are available
342 * to talk to this peer and what are their costs?
347 * This is a linked list.
349 struct ReadyList *next;
352 * Which of our transport plugins does this entry
355 struct TransportPlugin *plugin;
358 * Neighbor this entry belongs to.
360 struct NeighborList *neighbor;
363 * Transport addresses, latency, and readiness for
364 * this particular plugin.
366 struct PeerAddressList *addresses;
369 * Is this plugin ready to transmit to the specific target?
370 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
371 * transmission is in progress, "transmit_ready" is set to
374 int plugin_transmit_ready;
377 * Are any of our PeerAddressList addresses still connected?
379 int connected; /* FIXME: dynamically check PeerAddressList addresses when asked to! */
384 * Entry in linked list of all of our current neighbors.
390 * This is a linked list.
392 struct NeighborList *next;
395 * Which of our transports is connected to this peer
396 * and what is their status?
398 struct ReadyList *plugins;
401 * List of messages we would like to send to this peer;
402 * must contain at most one message per client.
404 struct MessageQueue *messages;
407 * Identity of this neighbor.
409 struct GNUNET_PeerIdentity id;
412 * ID of task scheduled to run when this peer is about to
413 * time out (will free resources associated with the peer).
415 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
418 * How long until we should consider this peer dead
419 * (if we don't receive another message in the
422 struct GNUNET_TIME_Absolute peer_timeout;
425 * At what time did we reset last_received last?
427 struct GNUNET_TIME_Absolute last_quota_update;
430 * At what time should we try to again add plugins to
433 struct GNUNET_TIME_Absolute retry_plugins_time;
436 * How many bytes have we received since the "last_quota_update"
439 uint64_t last_received;
442 * Global quota for inbound traffic for the neighbor in bytes/ms.
447 * How often has the other peer (recently) violated the
448 * inbound traffic limit? Incremented by 10 per violation,
449 * decremented by 1 per non-violation (for each
452 unsigned int quota_violation_count;
455 * Have we seen an ACK from this neighbor in the past?
456 * (used to make up a fake ACK for clients connecting after
457 * the neighbor connected to us).
461 /* The latency we have seen for this particular address for
462 * this particular peer. This latency may have been calculated
463 * over multiple transports. This value reflects how long it took
464 * us to receive a response when SENDING via this particular
465 * transport/neighbor/address combination!
467 struct GNUNET_TIME_RelativeNBO latency;
472 * Message used to ask a peer to validate receipt (to check an address
473 * from a HELLO). Followed by the address used. Note that the
474 * recipients response does not affirm that he has this address,
475 * only that he got the challenge message.
477 struct TransportPingMessage
481 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
483 struct GNUNET_MessageHeader header;
486 * Random challenge number (in network byte order).
488 uint32_t challenge GNUNET_PACKED;
491 * Who is the intended recipient?
493 struct GNUNET_PeerIdentity target;
499 * Message used to validate a HELLO. The challenge is included in the
500 * confirmation to make matching of replies to requests possible. The
501 * signature signs the original challenge number, our public key, the
502 * sender's address (so that the sender can check that the address we
503 * saw is plausible for him and possibly detect a MiM attack) and a
504 * timestamp (to limit replay).<p>
506 * This message is followed by the address of the
507 * client that we are observing (which is part of what
510 struct TransportPongMessage
514 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
516 struct GNUNET_MessageHeader header;
519 * For padding, always zero.
521 uint32_t reserved GNUNET_PACKED;
526 struct GNUNET_CRYPTO_RsaSignature signature;
529 * What are we signing and why?
531 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
534 * Random challenge number (in network byte order).
536 uint32_t challenge GNUNET_PACKED;
539 * Who signed this message?
541 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
544 * Size of address appended to this message
551 * Linked list of messages to be transmitted to
552 * the client. Each entry is followed by the
555 struct ClientMessageQueueEntry
558 * This is a linked list.
560 struct ClientMessageQueueEntry *next;
565 * Client connected to the transport service.
567 struct TransportClient
571 * This is a linked list.
573 struct TransportClient *next;
576 * Handle to the client.
578 struct GNUNET_SERVER_Client *client;
581 * Linked list of messages yet to be transmitted to
584 struct ClientMessageQueueEntry *message_queue_head;
587 * Tail of linked list of messages yet to be transmitted to the
590 struct ClientMessageQueueEntry *message_queue_tail;
593 * Is a call to "transmit_send_continuation" pending? If so, we
594 * must not free this struct (even if the corresponding client
595 * disconnects) and instead only remove it from the linked list and
596 * set the "client" field to NULL.
601 * Length of the list of messages pending for this client.
603 unsigned int message_count;
609 * For each HELLO, we may have to validate multiple addresses;
610 * each address gets its own request entry.
612 struct ValidationAddress
615 * This is a linked list.
617 struct ValidationAddress *next;
620 * What peer_address does this validation belong to?
622 struct PeerAddressList *peer_address;
625 * Name of the transport.
627 char *transport_name;
630 * When should this validated address expire?
632 struct GNUNET_TIME_Absolute expiration;
635 * At what time did we send this validation?
637 struct GNUNET_TIME_Absolute send_time;
640 * Challenge number we used.
645 * Set to GNUNET_YES if the challenge was met,
646 * GNUNET_SYSERR if we know it failed, GNUNET_NO
647 * if we are waiting on a response.
654 * Entry in linked list of all HELLOs awaiting validation.
656 struct ValidationList
660 * This is a linked list.
662 struct ValidationList *next;
665 * Linked list with one entry per address from the HELLO
666 * that needs to be validated.
668 struct ValidationAddress *addresses;
671 * The public key of the peer.
673 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
676 * When does this record time-out? (assuming the
677 * challenge goes unanswered)
679 struct GNUNET_TIME_Absolute timeout;
684 struct CheckHelloValidatedContext
687 * Plugin for which we are validating.
689 struct TransportPlugin *plugin;
692 * Hello that we are validating.
694 struct GNUNET_HELLO_Message *hello;
697 * Validation list being built.
699 struct ValidationList *e;
702 * Context for peerinfo iteration.
703 * NULL after we are done processing peerinfo's information.
705 struct GNUNET_PEERINFO_IteratorContext *piter;
712 * HELLOs awaiting validation.
714 static struct ValidationList *pending_validations;
719 static struct GNUNET_HELLO_Message *our_hello;
722 * "version" of "our_hello". Used to see if a given
723 * neighbor has already been sent the latest version
724 * of our HELLO message.
726 static unsigned int our_hello_version;
731 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
736 static struct GNUNET_PeerIdentity my_identity;
741 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
746 struct GNUNET_SCHEDULER_Handle *sched;
751 const struct GNUNET_CONFIGURATION_Handle *cfg;
754 * Linked list of all clients to this service.
756 static struct TransportClient *clients;
759 * All loaded plugins.
761 static struct TransportPlugin *plugins;
766 static struct GNUNET_SERVER_Handle *server;
769 * All known neighbors and their HELLOs.
771 static struct NeighborList *neighbors;
774 * Number of neighbors we'd like to have.
776 static uint32_t max_connect_per_transport;
779 * The peer specified by the given neighbor has timed-out or a plugin
780 * has disconnected. We may either need to do nothing (other plugins
781 * still up), or trigger a full disconnect and clean up. This
782 * function updates our state and do the necessary notifications.
783 * Also notifies our clients that the neighbor is now officially
786 * @param n the neighbor list entry for the peer
787 * @param check should we just check if all plugins
788 * disconnected or must we ask all plugins to
791 static void disconnect_neighbor (struct NeighborList *n, int check);
795 * Check the ready list for the given neighbor and
796 * if a plugin is ready for transmission (and if we
797 * have a message), do so!
799 * @param neighbor target peer for which to check the plugins
801 static ssize_t try_transmission_to_peer (struct NeighborList *neighbor);
805 * Find an entry in the neighbor list for a particular peer.
806 * if sender_address is not specified (NULL) then return the
807 * first matching entry. If sender_address is specified, then
808 * make sure that the address and address_len also matches.
810 * @return NULL if not found.
812 static struct NeighborList *
813 find_neighbor (const struct GNUNET_PeerIdentity *key)
815 struct NeighborList *head = neighbors;
817 while ((head != NULL) &&
818 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
826 * Find an entry in the transport list for a particular transport.
828 * @return NULL if not found.
830 static struct TransportPlugin *
831 find_transport (const char *short_name)
833 struct TransportPlugin *head = plugins;
834 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
841 * Update the quota values for the given neighbor now.
844 update_quota (struct NeighborList *n)
846 struct GNUNET_TIME_Relative delta;
850 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
851 if (delta.value < MIN_QUOTA_REFRESH_TIME)
852 return; /* not enough time passed for doing quota update */
853 allowed = delta.value * n->quota_in;
854 if (n->last_received < allowed)
856 remaining = allowed - n->last_received;
858 remaining /= n->quota_in;
861 if (remaining > MAX_BANDWIDTH_CARRY)
862 remaining = MAX_BANDWIDTH_CARRY;
863 n->last_received = 0;
864 n->last_quota_update = GNUNET_TIME_absolute_get ();
865 n->last_quota_update.value -= remaining;
866 if (n->quota_violation_count > 0)
867 n->quota_violation_count--;
871 n->last_received -= allowed;
872 n->last_quota_update = GNUNET_TIME_absolute_get ();
873 if (n->last_received > allowed)
875 /* more than twice the allowed rate! */
876 n->quota_violation_count += 10;
883 * Function called to notify a client about the socket
884 * being ready to queue more data. "buf" will be
885 * NULL and "size" zero if the socket was closed for
886 * writing in the meantime.
889 * @param size number of bytes available in buf
890 * @param buf where the callee should write the message
891 * @return number of bytes written to buf
894 transmit_to_client_callback (void *cls, size_t size, void *buf)
896 struct TransportClient *client = cls;
897 struct ClientMessageQueueEntry *q;
900 const struct GNUNET_MessageHeader *msg;
901 struct GNUNET_CONNECTION_TransmitHandle *th;
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907 "Transmission to client failed, closing connection.\n");
908 /* fatal error with client, free message queue! */
909 while (NULL != (q = client->message_queue_head))
911 client->message_queue_head = q->next;
914 client->message_queue_tail = NULL;
915 client->message_count = 0;
920 while (NULL != (q = client->message_queue_head))
922 msg = (const struct GNUNET_MessageHeader *) &q[1];
923 msize = ntohs (msg->size);
924 if (msize + tsize > size)
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "Transmitting message of type %u to client.\n",
931 client->message_queue_head = q->next;
933 client->message_queue_tail = NULL;
934 memcpy (&cbuf[tsize], msg, msize);
937 client->message_count--;
941 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
942 th = GNUNET_SERVER_notify_transmit_ready (client->client,
944 GNUNET_TIME_UNIT_FOREVER_REL,
945 &transmit_to_client_callback,
947 GNUNET_assert (th != NULL);
954 * Send the specified message to the specified client. Since multiple
955 * messages may be pending for the same client at a time, this code
956 * makes sure that no message is lost.
958 * @param client client to transmit the message to
959 * @param msg the message to send
960 * @param may_drop can this message be dropped if the
961 * message queue for this client is getting far too large?
964 transmit_to_client (struct TransportClient *client,
965 const struct GNUNET_MessageHeader *msg, int may_drop)
967 struct ClientMessageQueueEntry *q;
969 struct GNUNET_CONNECTION_TransmitHandle *th;
971 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
973 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
975 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
976 client->message_count, MAX_PENDING);
977 /* TODO: call to statistics... */
980 client->message_count++;
981 msize = ntohs (msg->size);
982 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
983 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
984 memcpy (&q[1], msg, msize);
985 /* append to message queue */
986 if (client->message_queue_tail == NULL)
988 client->message_queue_tail = q;
992 client->message_queue_tail->next = q;
993 client->message_queue_tail = q;
995 if (client->message_queue_head == NULL)
997 client->message_queue_head = q;
998 th = GNUNET_SERVER_notify_transmit_ready (client->client,
1000 GNUNET_TIME_UNIT_FOREVER_REL,
1001 &transmit_to_client_callback,
1003 GNUNET_assert (th != NULL);
1009 * Find alternative plugins for communication.
1011 * @param neighbor for which neighbor should we try to find
1015 try_alternative_plugins (struct NeighborList *neighbor)
1017 struct ReadyList *rl;
1019 if ((neighbor->plugins != NULL) &&
1020 (neighbor->retry_plugins_time.value >
1021 GNUNET_TIME_absolute_get ().value))
1022 return; /* don't try right now */
1023 neighbor->retry_plugins_time
1024 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1026 rl = neighbor->plugins;
1027 #if WTF /* FIXME: What is this supposed to do? */
1030 if (rl->connect_attempts > 0)
1031 rl->connect_attempts--; /* amnesty */
1039 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1040 * upon "completion" of a send request. This tells the API
1041 * that it is now legal to send another message to the given
1044 * @param cls closure, identifies the entry on the
1045 * message queue that was transmitted and the
1046 * client responsible for queueing the message
1047 * @param target the peer receiving the message
1048 * @param result GNUNET_OK on success, if the transmission
1049 * failed, we should not tell the client to transmit
1053 transmit_send_continuation (void *cls,
1054 const struct GNUNET_PeerIdentity *target,
1057 struct MessageQueue *mq = cls;
1058 struct ReadyList *rl;
1059 struct SendOkMessage send_ok_msg;
1060 struct NeighborList *n;
1062 GNUNET_assert (mq != NULL);
1064 GNUNET_assert (n != NULL);
1066 memcmp (&n->id, target,
1067 sizeof (struct GNUNET_PeerIdentity)));
1069 while ((rl != NULL) && (rl->plugin != mq->plugin))
1071 GNUNET_assert (rl != NULL);
1072 if (result == GNUNET_OK)
1074 mq->specific_peer->timeout =
1075 GNUNET_TIME_relative_to_absolute
1076 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1081 "Transmission to peer `%s' failed, marking connection as down.\n",
1082 GNUNET_i2s (target));
1083 mq->specific_peer->connected = GNUNET_NO;
1085 if (!mq->internal_msg)
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "Setting transmit_ready on transport!\n");
1091 mq->specific_peer->transmit_ready = GNUNET_YES;
1094 if (mq->client != NULL)
1096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1097 "Notifying client %p about transmission to peer `%4s'.\n",
1098 mq->client, GNUNET_i2s (target));
1099 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1100 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1101 send_ok_msg.success = htonl (result);
1102 send_ok_msg.peer = n->id;
1103 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1105 GNUNET_free (mq->message_buf);
1107 /* one plugin just became ready again, try transmitting
1108 another message (if available) */
1109 if (result == GNUNET_OK)
1110 try_transmission_to_peer (n);
1112 disconnect_neighbor (n, GNUNET_YES);
1118 struct PeerAddressList *
1119 find_ready_address(struct NeighborList *neighbor)
1121 struct ReadyList *head = neighbor->plugins;
1122 struct PeerAddressList *addresses;
1123 while (head != NULL)
1125 addresses = head->addresses;
1126 while ((addresses != NULL) &&
1127 ((addresses->connected != GNUNET_YES) ||
1128 (addresses->transmit_ready != GNUNET_YES)))
1130 addresses = addresses->next;
1133 if (addresses != NULL)
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137 "Found ready address, connected is %d\n",
1138 addresses->connected);
1148 #if 0 /* Do some checks to keep everything sane, return lowest latency connection */
1151 /* set plugins that are inactive for a long time back to disconnected */
1152 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "Marking long-time inactive connection to `%4s' as down.\n",
1157 GNUNET_i2s (&neighbor->id));
1159 pos->connected = GNUNET_NO;
1161 if (GNUNET_YES == pos->transmit_ready)
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 "Found transmit_ready flag...\n");
1168 if (((GNUNET_YES == pos->transmit_ready) ||
1169 (mq->internal_msg)) &&
1170 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1171 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1174 min_latency = pos->latency;
1182 * Check the ready list for the given neighbor and
1183 * if a plugin is ready for transmission (and if we
1184 * have a message), do so!
1187 try_transmission_to_peer (struct NeighborList *neighbor)
1189 struct GNUNET_TIME_Relative min_latency;
1190 struct ReadyList *rl;
1191 struct MessageQueue *mq;
1192 struct GNUNET_TIME_Absolute now;
1194 if (neighbor->messages == NULL)
1195 return 0; /* nothing to do */
1196 try_alternative_plugins (neighbor);
1197 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1199 mq = neighbor->messages;
1200 now = GNUNET_TIME_absolute_get ();
1202 if (mq->specific_peer == NULL)
1203 mq->specific_peer = find_ready_address(neighbor); /* Find first available (or best!) address to transmit to */
1205 if (mq->specific_peer == NULL)
1208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1209 "No plugin ready to transmit message\n");
1211 return 0; /* nobody ready */
1214 rl = mq->specific_peer->ready_list;
1215 neighbor->messages = mq->next;
1216 mq->plugin = rl->plugin;
1217 if (!mq->internal_msg)
1218 mq->specific_peer->transmit_ready = GNUNET_NO;
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Giving message of size `%u' for `%4s' to plugin `%s'\n",
1222 mq->message_buf_size,
1223 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1226 return rl->plugin->api->send (rl->plugin->api->cls,
1229 mq->message_buf_size,
1231 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1232 mq->specific_peer->addr,
1233 mq->specific_peer->addrlen,
1235 &transmit_send_continuation, mq);
1241 * Send the specified message to the specified peer.
1243 * @param client source of the transmission request (can be NULL)
1244 * @param peer_address PeerAddressList where we should send this message
1245 * @param priority how important is the message
1246 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1247 * @param message_buf_size total size of all messages in message_buf
1248 * @param is_internal is this an internal message
1249 * @param neighbor handle to the neighbor for transmission
1252 transmit_to_peer (struct TransportClient *client,
1253 struct PeerAddressList *peer_address,
1254 unsigned int priority,
1255 const char *message_buf,
1256 size_t message_buf_size,
1257 int is_internal, struct NeighborList *neighbor)
1259 struct MessageQueue *mq;
1260 struct MessageQueue *mqe;
1265 /* check for duplicate submission */
1266 mq = neighbor->messages;
1269 if (mq->client == client)
1271 /* client transmitted to same peer twice
1272 before getting SendOk! */
1279 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1280 mq->specific_peer = peer_address;
1281 mq->client = client;
1282 m = GNUNET_malloc (message_buf_size);
1283 memcpy (m, message_buf, message_buf_size);
1284 mq->message_buf = m;
1285 mq->message_buf_size = message_buf_size;
1286 mq->neighbor = neighbor;
1287 mq->internal_msg = is_internal;
1288 mq->priority = priority;
1291 mqe = neighbor->messages;
1293 while (mqe->next != NULL)
1298 neighbor->messages = mq;
1305 return try_transmission_to_peer (neighbor);
1312 struct GeneratorContext
1314 struct TransportPlugin *plug_pos;
1315 struct AddressList *addr_pos;
1316 struct GNUNET_TIME_Absolute expiration;
1324 address_generator (void *cls, size_t max, void *buf)
1326 struct GeneratorContext *gc = cls;
1329 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1331 gc->plug_pos = gc->plug_pos->next;
1332 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1334 if (NULL == gc->plug_pos)
1339 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1342 gc->addr_pos->addrlen, buf, max);
1343 gc->addr_pos = gc->addr_pos->next;
1349 * Construct our HELLO message from all of the addresses of
1350 * all of the transports.
1355 struct GNUNET_HELLO_Message *hello;
1356 struct TransportClient *cpos;
1357 struct NeighborList *npos;
1358 struct GeneratorContext gc;
1360 gc.plug_pos = plugins;
1361 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1362 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1363 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1366 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1369 while (cpos != NULL)
1371 transmit_to_client (cpos,
1372 (const struct GNUNET_MessageHeader *) hello,
1377 GNUNET_free_non_null (our_hello);
1379 our_hello_version++;
1380 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1382 while (npos != NULL)
1385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1386 "Transmitting updated `%s' to neighbor `%4s'\n",
1387 "HELLO", GNUNET_i2s (&npos->id));
1388 #endif // FIXME: just testing
1389 //transmit_to_peer (NULL, NULL, 0,
1390 // (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1391 // GNUNET_YES, npos);
1398 * Task used to clean up expired addresses for a plugin.
1400 * @param cls closure
1404 expire_address_task (void *cls,
1405 const struct GNUNET_SCHEDULER_TaskContext *tc);
1409 * Update the list of addresses for this plugin,
1410 * expiring those that are past their expiration date.
1412 * @param plugin addresses of which plugin should be recomputed?
1413 * @param fresh set to GNUNET_YES if a new address was added
1414 * and we need to regenerate the HELLO even if nobody
1418 update_addresses (struct TransportPlugin *plugin, int fresh)
1420 struct GNUNET_TIME_Relative min_remaining;
1421 struct GNUNET_TIME_Relative remaining;
1422 struct GNUNET_TIME_Absolute now;
1423 struct AddressList *pos;
1424 struct AddressList *prev;
1425 struct AddressList *next;
1428 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1429 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1430 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1431 now = GNUNET_TIME_absolute_get ();
1432 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1433 expired = GNUNET_NO;
1435 pos = plugin->addresses;
1439 if (pos->expires.value < now.value)
1441 expired = GNUNET_YES;
1443 plugin->addresses = pos->next;
1445 prev->next = pos->next;
1450 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1451 if (remaining.value < min_remaining.value)
1452 min_remaining = remaining;
1458 if (expired || fresh)
1460 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1461 plugin->address_update_task
1462 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1464 &expire_address_task, plugin);
1470 * Task used to clean up expired addresses for a plugin.
1472 * @param cls closure
1476 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1478 struct TransportPlugin *plugin = cls;
1479 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1480 update_addresses (plugin, GNUNET_NO);
1485 * Function that must be called by each plugin to notify the
1486 * transport service about the addresses under which the transport
1487 * provided by the plugin can be reached.
1489 * @param cls closure
1490 * @param name name of the transport that generated the address
1491 * @param addr one of the addresses of the host, NULL for the last address
1492 * the specific address format depends on the transport
1493 * @param addrlen length of the address
1494 * @param expires when should this address automatically expire?
1497 plugin_env_notify_address (void *cls,
1501 struct GNUNET_TIME_Relative expires)
1503 struct TransportPlugin *p = cls;
1504 struct AddressList *al;
1505 struct GNUNET_TIME_Absolute abex;
1507 abex = GNUNET_TIME_relative_to_absolute (expires);
1508 GNUNET_assert (p == find_transport (name));
1513 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1515 if (al->expires.value < abex.value)
1522 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1524 al->next = p->addresses;
1527 al->addrlen = addrlen;
1528 memcpy (&al[1], addr, addrlen);
1529 update_addresses (p, GNUNET_YES);
1534 * Notify all of our clients about a peer connecting.
1537 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1538 struct GNUNET_TIME_Relative latency)
1540 struct ConnectInfoMessage cim;
1541 struct TransportClient *cpos;
1543 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1544 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1545 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1546 cim.latency = GNUNET_TIME_relative_hton (latency);
1547 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1549 while (cpos != NULL)
1551 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1558 * Notify all of our clients about a peer disconnecting.
1561 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1563 struct DisconnectInfoMessage dim;
1564 struct TransportClient *cpos;
1566 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1567 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1568 dim.reserved = htonl (0);
1569 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1571 while (cpos != NULL)
1573 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1580 * Copy any validated addresses to buf.
1582 * @return 0 once all addresses have been
1586 list_validated_addresses (void *cls, size_t max, void *buf)
1588 struct ValidationAddress **va = cls;
1591 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1595 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1597 (*va)->peer_address->addr, (*va)->peer_address->addrlen, buf, max);
1604 * HELLO validation cleanup task.
1607 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1609 struct ValidationAddress *va;
1610 struct ValidationList *pos;
1611 struct ValidationList *prev;
1612 struct GNUNET_TIME_Absolute now;
1613 struct GNUNET_TIME_Absolute first;
1614 struct GNUNET_HELLO_Message *hello;
1615 struct GNUNET_PeerIdentity pid;
1616 struct NeighborList *n;
1618 now = GNUNET_TIME_absolute_get ();
1620 pos = pending_validations;
1623 if (pos->timeout.value < now.value)
1626 pending_validations = pos->next;
1628 prev->next = pos->next;
1629 va = pos->addresses;
1630 hello = GNUNET_HELLO_create (&pos->publicKey,
1631 &list_validated_addresses, &va);
1632 GNUNET_CRYPTO_hash (&pos->publicKey,
1634 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1638 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1639 "HELLO", GNUNET_i2s (&pid));
1641 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1642 n = find_neighbor (&pid);
1645 try_transmission_to_peer (n);
1647 GNUNET_free (hello);
1648 while (NULL != (va = pos->addresses))
1650 pos->addresses = va->next;
1651 GNUNET_free (va->transport_name);
1656 pos = pending_validations;
1665 /* finally, reschedule cleanup if needed; list is
1666 ordered by timeout, so we need the last element... */
1667 if (NULL != pending_validations)
1669 first = pending_validations->timeout;
1670 pos = pending_validations;
1673 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1676 GNUNET_SCHEDULER_add_delayed (sched,
1677 GNUNET_TIME_absolute_get_remaining
1678 (first), &cleanup_validation, NULL);
1684 * Function that will be called if we receive a validation
1685 * of an address challenge that we transmitted to another
1686 * peer. Note that the validation should only be considered
1687 * acceptable if the challenge matches AND if the sender
1688 * address is at least a plausible address for this peer
1689 * (otherwise we may be seeing a MiM attack).
1691 * @param cls closure
1692 * @param name name of the transport that generated the address
1693 * @param peer who responded to our challenge
1694 * @param challenge the challenge number we presumably used
1695 * @param sender_addr string describing our sender address (as observed
1696 * by the other peer in human-readable format)
1699 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1700 const struct GNUNET_PeerIdentity *peer,
1701 const char *sender_address,
1702 size_t sender_address_len)
1704 unsigned int not_done;
1706 struct ValidationList *pos;
1707 struct ValidationAddress *va;
1708 struct GNUNET_PeerIdentity id;
1709 struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
1711 unsigned int challenge = ntohl(pong->challenge);
1712 pos = pending_validations;
1715 GNUNET_CRYPTO_hash (&pos->publicKey,
1717 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1719 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1726 /* TODO: call statistics (unmatched PONG) */
1727 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1729 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1730 GNUNET_i2s (peer), count);
1734 matched = GNUNET_NO;
1735 va = pos->addresses;
1738 if (va->challenge == challenge)
1741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1742 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1744 GNUNET_a2s ((const struct sockaddr *) sender_address,
1745 sender_address_len));
1747 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1749 ("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1750 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1751 ntohs(pong->addrlen)), va->transport_name);
1752 va->ok = GNUNET_YES;
1754 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1755 matched = GNUNET_YES;
1756 va->peer_address->connected = GNUNET_YES;
1757 va->peer_address->latency = GNUNET_TIME_absolute_get_difference(GNUNET_TIME_absolute_get(), va->send_time);
1758 va->peer_address->transmit_ready = GNUNET_YES;
1759 va->peer_address->expires = GNUNET_TIME_relative_to_absolute
1760 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1762 if (va->ok != GNUNET_YES)
1766 if (GNUNET_NO == matched)
1768 /* TODO: call statistics (unmatched PONG) */
1769 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1771 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1778 "All addresses validated, will now construct `%s' for `%4s'.\n",
1779 "HELLO", GNUNET_i2s (peer));
1781 pos->timeout.value = 0;
1782 GNUNET_SCHEDULER_add_with_priority (sched,
1783 GNUNET_SCHEDULER_PRIORITY_IDLE,
1784 &cleanup_validation, NULL);
1790 * Add an entry for each of our transport plugins
1791 * (that are able to send) to the list of plugins
1792 * for this neighbor.
1794 * @param neighbor to initialize
1797 add_plugins (struct NeighborList *neighbor)
1799 struct TransportPlugin *tp;
1800 struct ReadyList *rl;
1802 neighbor->retry_plugins_time
1803 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1807 if (tp->api->send != NULL)
1809 rl = GNUNET_malloc (sizeof (struct ReadyList));
1810 rl->next = neighbor->plugins;
1811 neighbor->plugins = rl;
1813 rl->neighbor = neighbor;
1814 rl->addresses = NULL;
1821 neighbor_timeout_task (void *cls,
1822 const struct GNUNET_SCHEDULER_TaskContext *tc)
1824 struct NeighborList *n = cls;
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1828 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1830 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1831 disconnect_neighbor (n, GNUNET_NO);
1835 * Create a fresh entry in our neighbor list for the given peer.
1836 * Will try to transmit our current HELLO to the new neighbor. Also
1837 * notifies our clients about the new "connection".
1839 * @param peer the peer for which we create the entry
1840 * @return the new neighbor list entry
1842 static struct NeighborList *
1843 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1845 struct NeighborList *n;
1847 GNUNET_assert (our_hello != NULL);
1848 n = GNUNET_malloc (sizeof (struct NeighborList));
1849 n->next = neighbors;
1852 n->last_quota_update = GNUNET_TIME_absolute_get ();
1854 GNUNET_TIME_relative_to_absolute
1855 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1856 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1858 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1859 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1860 &neighbor_timeout_task, n);
1861 transmit_to_peer (NULL, NULL, 0,
1862 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1864 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1868 static struct PeerAddressList *
1869 add_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1871 /* FIXME: should return a list of PeerAddressLists, support for multiple transports! */
1872 struct ReadyList *head = neighbor->plugins;
1873 struct PeerAddressList * new_address;
1875 GNUNET_assert(addr != NULL);
1877 while (head != NULL)
1879 new_address = GNUNET_malloc(sizeof(struct PeerAddressList));
1880 new_address->addr = GNUNET_malloc(addrlen);
1881 memcpy(new_address->addr, addr, addrlen);
1882 new_address->addrlen = addrlen;
1883 new_address->connect_attempts = 0;
1884 new_address->connected = GNUNET_YES; /* Set connected to GNUNET_YES, assuming that we're good */
1885 new_address->expires = GNUNET_TIME_relative_to_absolute
1886 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1887 new_address->latency = GNUNET_TIME_relative_get_forever();
1888 new_address->neighbor = neighbor;
1889 new_address->plugin = head->plugin;
1890 new_address->transmit_ready = GNUNET_YES;
1891 new_address->timeout = GNUNET_TIME_relative_to_absolute
1892 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); /* FIXME: Do we need this? */
1893 new_address->ready_list = head;
1894 new_address->next = head->addresses;
1895 head->addresses = new_address;
1902 static struct PeerAddressList *
1903 find_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1905 struct ReadyList *head = neighbor->plugins;
1906 struct PeerAddressList *address_head;
1907 while (head != NULL)
1909 address_head = head->addresses;
1910 while ((address_head != NULL) &&
1911 (address_head->addrlen != addrlen) &&
1912 (memcmp(address_head->addr, addr, addrlen) != 0))
1914 address_head = address_head->next;
1916 if (address_head != NULL)
1917 return address_head;
1925 * Append the given address to the list of entries
1926 * that need to be validated.
1929 run_validation (void *cls,
1931 struct GNUNET_TIME_Absolute expiration,
1932 const void *addr, size_t addrlen)
1934 struct ValidationList *e = cls;
1935 struct TransportPlugin *tp;
1936 struct ValidationAddress *va;
1937 struct GNUNET_PeerIdentity id;
1938 struct NeighborList *neighbor;
1939 struct PeerAddressList *peer_address;
1941 struct TransportPingMessage *ping;
1946 tp = find_transport (tname);
1949 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1950 GNUNET_ERROR_TYPE_BULK,
1952 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1956 GNUNET_CRYPTO_hash (&e->publicKey,
1958 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1962 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1963 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1965 va = GNUNET_malloc (sizeof (struct ValidationAddress));
1966 va->next = e->addresses;
1968 va->transport_name = GNUNET_strdup (tname);
1969 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1971 va->send_time = GNUNET_TIME_absolute_get();
1973 neighbor = find_neighbor(&id);
1975 if (neighbor == NULL)
1976 neighbor = setup_new_neighbor(&id);
1978 peer_address = find_peer_address(neighbor, addr, addrlen);
1979 if (peer_address == NULL)
1981 peer_address = add_peer_address(neighbor, addr, addrlen);
1984 GNUNET_assert(peer_address != NULL);
1986 va->peer_address = peer_address; /* Back pointer FIXME: remove this nonsense! */
1987 peer_address->validation = va;
1989 hello_size = GNUNET_HELLO_size(our_hello);
1990 tsize = sizeof(struct TransportPingMessage) + hello_size;
1992 message_buf = GNUNET_malloc(tsize);
1994 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
1995 ping->challenge = htonl(va->challenge);
1996 ping->header.size = htons(sizeof(struct TransportPingMessage));
1997 ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1998 memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
2001 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "hello size is %d, ping size is %d, total size is %d", hello_size, sizeof(struct TransportPingMessage), tsize);
2003 memcpy(message_buf, our_hello, hello_size);
2004 memcpy(&message_buf[hello_size], ping, sizeof(struct TransportPingMessage));
2007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message of size %d to address `%s' via `%s' for `%4s'\n",
2008 tsize, GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
2010 sent = transmit_to_peer(NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2011 message_buf, tsize, GNUNET_NO, neighbor);
2014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
2018 GNUNET_free(message_buf);
2024 * @param cls handle to the plugin (for sending)
2025 * @param target the peer identity of the peer we are sending to
2026 * @param challenge the challenge number
2027 * @param timeout how long to await validation?
2028 * @param addr the address to validate
2029 * @param addrlen the length of the address
2031 * Perform address validation, which means sending a PING PONG to
2032 * the address via the transport plugin. If not validated, then
2033 * do not count this as a good peer/address...
2035 * Currently this function is not used, ping/pongs get sent from the
2036 * run_validation function. Haven't decided yet how to do this.
2039 validate_address (void *cls, struct ValidationAddress *va,
2040 const struct GNUNET_PeerIdentity *target,
2041 struct GNUNET_TIME_Relative timeout,
2042 const void *addr, size_t addrlen)
2044 /* struct Plugin *plugin = cls;
2045 int challenge = va->challenge; */
2053 * Check if addresses in validated hello "h" overlap with
2054 * those in "chvc->hello" and update "chvc->hello" accordingly,
2055 * removing those addresses that have already been validated.
2058 check_hello_validated (void *cls,
2059 const struct GNUNET_PeerIdentity *peer,
2060 const struct GNUNET_HELLO_Message *h, uint32_t trust)
2062 struct CheckHelloValidatedContext *chvc = cls;
2063 struct ValidationAddress *va;
2064 struct TransportPlugin *tp;
2067 struct GNUNET_PeerIdentity apeer;
2069 first_call = GNUNET_NO;
2070 if (chvc->e == NULL)
2073 first_call = GNUNET_YES;
2074 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
2075 GNUNET_assert (GNUNET_OK ==
2076 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
2077 &chvc->e->publicKey));
2079 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
2080 chvc->e->next = pending_validations;
2081 pending_validations = chvc->e;
2083 /* no existing HELLO, all addresses are new */
2084 /* GNUNET_HELLO_iterate_addresses (chvc->hello,
2085 GNUNET_NO, &run_validation, chvc->e);*/
2089 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2091 GNUNET_TIME_absolute_get (),
2092 &run_validation, chvc->e);
2094 else if (GNUNET_YES == first_call)
2096 /* no existing HELLO, all addresses are new */
2097 GNUNET_HELLO_iterate_addresses (chvc->hello,
2098 GNUNET_NO, &run_validation, chvc->e);
2102 return; /* wait for next call */
2103 /* finally, transmit validation attempts */
2104 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
2106 va = chvc->e->addresses;
2111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2112 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
2115 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
2116 va->peer_address->addrlen), GNUNET_i2s (&apeer));
2118 tp = find_transport (va->transport_name);
2119 GNUNET_assert (tp != NULL);
2120 /* This validation should happen inside the transport, not from the plugin! */
2121 va->ok = GNUNET_SYSERR;
2126 GNUNET_SCHEDULER_add_delayed (sched,
2127 GNUNET_TIME_absolute_get_remaining (chvc->
2129 &cleanup_validation, NULL);
2135 * Process HELLO-message.
2137 * @param plugin transport involved, may be NULL
2138 * @param message the actual message
2139 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2142 process_hello (struct TransportPlugin *plugin,
2143 const struct GNUNET_MessageHeader *message)
2145 struct ValidationList *e;
2147 struct GNUNET_PeerIdentity target;
2148 const struct GNUNET_HELLO_Message *hello;
2149 struct CheckHelloValidatedContext *chvc;
2150 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2152 hsize = ntohs (message->size);
2153 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2154 (hsize < sizeof (struct GNUNET_MessageHeader)))
2157 return GNUNET_SYSERR;
2159 /* first, check if load is too high */
2160 if (GNUNET_OS_load_cpu_get (cfg) > 100)
2162 /* TODO: call to stats? */
2165 hello = (const struct GNUNET_HELLO_Message *) message;
2166 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2168 GNUNET_break_op (0);
2169 return GNUNET_SYSERR;
2171 GNUNET_CRYPTO_hash (&publicKey,
2172 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2173 &target.hashPubKey);
2175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2176 "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
2177 "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
2179 /* check if a HELLO for this peer is already on the validation list */
2180 e = pending_validations;
2183 if (0 == memcmp (&e->publicKey,
2186 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
2188 /* TODO: call to stats? */
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
2192 "HELLO", GNUNET_i2s (&target));
2198 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2199 chvc->plugin = plugin;
2200 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
2202 memcpy (chvc->hello, hello, hsize);
2203 /* finally, check if HELLO was previously validated
2204 (continuation will then schedule actual validation) */
2205 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2209 HELLO_VERIFICATION_TIMEOUT,
2210 &check_hello_validated, chvc);
2216 * The peer specified by the given neighbor has timed-out or a plugin
2217 * has disconnected. We may either need to do nothing (other plugins
2218 * still up), or trigger a full disconnect and clean up. This
2219 * function updates our state and do the necessary notifications.
2220 * Also notifies our clients that the neighbor is now officially
2223 * @param n the neighbor list entry for the peer
2224 * @param check should we just check if all plugins
2225 * disconnected or must we ask all plugins to
2229 disconnect_neighbor (struct NeighborList *n, int check)
2231 struct ReadyList *rpos;
2232 struct NeighborList *npos;
2233 struct NeighborList *nprev;
2234 struct MessageQueue *mq;
2236 if (GNUNET_YES == check)
2239 while (NULL != rpos)
2241 if (GNUNET_YES == rpos->connected)
2242 return; /* still connected */
2248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2249 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2251 /* remove n from neighbors list */
2254 while ((npos != NULL) && (npos != n))
2259 GNUNET_assert (npos != NULL);
2261 neighbors = n->next;
2263 nprev->next = n->next;
2265 /* notify all clients about disconnect */
2266 notify_clients_disconnect (&n->id);
2268 /* clean up all plugins, cancel connections and pending transmissions */
2269 while (NULL != (rpos = n->plugins))
2271 n->plugins = rpos->next;
2272 GNUNET_assert (rpos->neighbor == n);
2273 if (GNUNET_YES == rpos->connected)
2274 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2278 /* free all messages on the queue */
2279 while (NULL != (mq = n->messages))
2281 n->messages = mq->next;
2282 GNUNET_assert (mq->neighbor == n);
2285 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2286 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2287 /* finally, free n itself */
2293 * We have received a PING message from someone. Need to send a PONG message
2294 * in response to the peer by any means necessary. Of course, with something
2295 * like TCP where a connection exists, we may want to send it that way. But
2296 * we may not be able to make that distinction...
2298 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2299 const struct GNUNET_PeerIdentity *peer,
2300 const char *sender_address,
2301 size_t sender_address_len)
2303 struct TransportPlugin *plugin = cls;
2304 struct TransportPingMessage *ping;
2305 struct TransportPongMessage *pong;
2306 struct PeerAddressList *peer_address;
2308 struct NeighborList *n;
2309 pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2313 "Processing `%s' from `%s'\n",
2314 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2317 msize = ntohs (message->size);
2318 if (msize < sizeof (struct TransportPingMessage))
2320 GNUNET_break_op (0);
2321 return GNUNET_SYSERR;
2323 ping = (struct TransportPingMessage *) message;
2324 if (0 != memcmp (&ping->target,
2325 plugin->env.my_identity,
2326 sizeof (struct GNUNET_PeerIdentity)))
2328 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2329 _("Received `%s' message not destined for me!\n"), "PING");
2330 return GNUNET_SYSERR;
2333 msize -= sizeof (struct TransportPingMessage);
2335 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2336 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2337 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2338 pong->purpose.size =
2339 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2341 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2342 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2343 pong->challenge = ping->challenge;
2344 pong->addrlen = htons(sender_address_len);
2346 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2347 memcpy (&pong[1], sender_address, sender_address_len);
2348 GNUNET_assert (GNUNET_OK ==
2349 GNUNET_CRYPTO_rsa_sign (my_private_key,
2350 &pong->purpose, &pong->signature));
2352 n = find_neighbor(peer);
2354 n = setup_new_neighbor(peer);
2356 peer_address = find_peer_address(n, sender_address, sender_address_len);
2357 if (peer_address == NULL)
2358 peer_address = add_peer_address(n, sender_address, sender_address_len);
2360 transmit_to_peer(NULL, NULL, TRANSPORT_DEFAULT_PRIORITY, (char *)pong, ntohs(pong->header.size), GNUNET_NO, n);
2367 * Function called by the plugin for each received message.
2368 * Update data volumes, possibly notify plugins about
2369 * reducing the rate at which they read from the socket
2370 * and generally forward to our receive callback.
2372 * @param cls the "struct TransportPlugin *" we gave to the plugin
2373 * @param message the message, NULL if peer was disconnected
2374 * @param distance the transport cost to this peer (not latency!)
2375 * @param sender_address the address that the sender reported
2376 * (opaque to transport service)
2377 * @param sender_address_len the length of the sender address
2378 * @param peer (claimed) identity of the other peer
2379 * @return the new service_context that the plugin should use
2380 * for future receive calls for messages from this
2385 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2386 const struct GNUNET_MessageHeader *message,
2387 unsigned int distance, const char *sender_address,
2388 size_t sender_address_len)
2390 struct ReadyList *service_context;
2391 struct TransportPlugin *plugin = cls;
2392 struct TransportClient *cpos;
2393 struct InboundMessage *im;
2394 struct PeerAddressList *peer_address;
2396 struct NeighborList *n;
2398 n = find_neighbor (peer);
2401 if (message == NULL)
2402 return; /* disconnect of peer already marked down */
2403 n = setup_new_neighbor (peer);
2407 peer_address = find_peer_address(n, sender_address, sender_address_len);
2408 if (peer_address == NULL)
2409 peer_address = add_peer_address(n, sender_address, sender_address_len);
2411 service_context = n->plugins;
2412 while ((service_context != NULL) && (plugin != service_context->plugin))
2413 service_context = service_context->next;
2414 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2415 if (message == NULL)
2418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2419 "Receive failed from `%4s', triggering disconnect\n",
2420 GNUNET_i2s (&n->id));
2422 /* TODO: call stats */
2423 if (service_context != NULL)
2424 service_context->connected = GNUNET_NO;
2425 disconnect_neighbor (n, GNUNET_YES);
2429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2430 "Processing message of type `%u' received by plugin...\n",
2431 ntohs (message->type));
2433 if (service_context != NULL)
2435 if (service_context->connected == GNUNET_NO)
2437 /*service_context->connected = GNUNET_YES;*/
2438 /* FIXME: What to do here? Should we use these as well, to specify some Address
2439 * in the AddressList should be available?
2441 peer_address->transmit_ready = GNUNET_YES;
2442 peer_address->connect_attempts++;
2444 peer_address->timeout
2446 GNUNET_TIME_relative_to_absolute
2447 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2449 /* update traffic received amount ... */
2450 msize = ntohs (message->size);
2451 n->last_received += msize;
2452 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2454 GNUNET_TIME_relative_to_absolute
2455 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2457 GNUNET_SCHEDULER_add_delayed (sched,
2458 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2459 &neighbor_timeout_task, n);
2461 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2463 /* dropping message due to frequent inbound volume violations! */
2464 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2465 GNUNET_ERROR_TYPE_BULK,
2467 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2468 /* TODO: call stats */
2469 GNUNET_assert ((service_context == NULL) ||
2470 (NULL != service_context->neighbor));
2473 switch (ntohs (message->type))
2475 case GNUNET_MESSAGE_TYPE_HELLO:
2477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2478 "Receiving `%s' message from `%4s'.\n", "HELLO",
2481 process_hello (plugin, message);
2483 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2484 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2486 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2487 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2492 "Received \n\nREAL MESSAGE\n\ntype %u from `%4s', sending to all clients.\n",
2493 ntohs (message->type), GNUNET_i2s (peer));
2495 /* transmit message to all clients */
2496 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2497 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2498 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2499 im->latency = n->latency;
2501 memcpy (&im[1], message, msize);
2504 while (cpos != NULL)
2506 transmit_to_client (cpos, &im->header, GNUNET_YES);
2511 GNUNET_assert ((service_context == NULL) ||
2512 (NULL != service_context->neighbor));
2517 * Handle START-message. This is the first message sent to us
2518 * by any client which causes us to add it to our list.
2520 * @param cls closure (always NULL)
2521 * @param client identification of the client
2522 * @param message the actual message
2525 handle_start (void *cls,
2526 struct GNUNET_SERVER_Client *client,
2527 const struct GNUNET_MessageHeader *message)
2529 struct TransportClient *c;
2530 struct ConnectInfoMessage cim;
2531 struct NeighborList *n;
2532 struct InboundMessage *im;
2533 struct GNUNET_MessageHeader *ack;
2536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2537 "Received `%s' request from client\n", "START");
2542 if (c->client == client)
2544 /* client already on our list! */
2546 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2551 c = GNUNET_malloc (sizeof (struct TransportClient));
2555 if (our_hello != NULL)
2558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2559 "Sending our own `%s' to new client\n", "HELLO");
2561 transmit_to_client (c,
2562 (const struct GNUNET_MessageHeader *) our_hello,
2564 /* tell new client about all existing connections */
2565 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2566 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2568 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2569 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2570 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2571 sizeof (struct GNUNET_MessageHeader));
2572 im->header.size = htons (sizeof (struct InboundMessage) +
2573 sizeof (struct GNUNET_MessageHeader));
2574 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2575 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2576 ack = (struct GNUNET_MessageHeader *) &im[1];
2577 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2578 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2579 for (n = neighbors; n != NULL; n = n->next)
2582 transmit_to_client (c, &cim.header, GNUNET_NO);
2583 if (n->received_pong)
2586 transmit_to_client (c, &im->header, GNUNET_NO);
2593 fprintf(stderr, "Our hello is NULL!\n");
2595 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2600 * Handle HELLO-message.
2602 * @param cls closure (always NULL)
2603 * @param client identification of the client
2604 * @param message the actual message
2607 handle_hello (void *cls,
2608 struct GNUNET_SERVER_Client *client,
2609 const struct GNUNET_MessageHeader *message)
2614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2615 "Received `%s' request from client\n", "HELLO");
2617 ret = process_hello (NULL, message);
2618 GNUNET_SERVER_receive_done (client, ret);
2623 * Handle SEND-message.
2625 * @param cls closure (always NULL)
2626 * @param client identification of the client
2627 * @param message the actual message
2630 handle_send (void *cls,
2631 struct GNUNET_SERVER_Client *client,
2632 const struct GNUNET_MessageHeader *message)
2634 struct TransportClient *tc;
2635 struct NeighborList *n;
2636 const struct OutboundMessage *obm;
2637 const struct GNUNET_MessageHeader *obmm;
2641 size = ntohs (message->size);
2643 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2646 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2649 obm = (const struct OutboundMessage *) message;
2651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652 "Received `%s' request from client with target `%4s'\n",
2653 "SEND", GNUNET_i2s (&obm->peer));
2655 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2656 msize = ntohs (obmm->size);
2657 if (size != msize + sizeof (struct OutboundMessage))
2660 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2663 n = find_neighbor (&obm->peer);
2665 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2667 while ((tc != NULL) && (tc->client != client))
2671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2672 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2674 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2676 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, ntohs (obmm->size), GNUNET_NO, n);
2677 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2682 * Handle SET_QUOTA-message.
2684 * @param cls closure (always NULL)
2685 * @param client identification of the client
2686 * @param message the actual message
2689 handle_set_quota (void *cls,
2690 struct GNUNET_SERVER_Client *client,
2691 const struct GNUNET_MessageHeader *message)
2693 const struct QuotaSetMessage *qsm =
2694 (const struct QuotaSetMessage *) message;
2695 struct NeighborList *n;
2696 struct TransportPlugin *p;
2697 struct ReadyList *rl;
2700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2701 "Received `%s' request from client for peer `%4s'\n",
2702 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2704 n = find_neighbor (&qsm->peer);
2707 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2711 if (n->quota_in < ntohl (qsm->quota_in))
2712 n->last_quota_update = GNUNET_TIME_absolute_get ();
2713 n->quota_in = ntohl (qsm->quota_in);
2718 p->api->set_receive_quota (p->api->cls,
2719 &qsm->peer, ntohl (qsm->quota_in));
2722 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2727 * Handle TRY_CONNECT-message.
2729 * @param cls closure (always NULL)
2730 * @param client identification of the client
2731 * @param message the actual message
2734 handle_try_connect (void *cls,
2735 struct GNUNET_SERVER_Client *client,
2736 const struct GNUNET_MessageHeader *message)
2738 const struct TryConnectMessage *tcm;
2740 tcm = (const struct TryConnectMessage *) message;
2742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2743 "Received `%s' request from client %p asking to connect to `%4s'\n",
2744 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2746 if (NULL == find_neighbor (&tcm->peer))
2747 setup_new_neighbor (&tcm->peer);
2750 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2751 "Client asked to connect to `%4s', but connection already exists\n",
2752 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2754 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2758 transmit_address_to_client (void *cls, const char *address)
2760 struct GNUNET_SERVER_TransmitContext *tc = cls;
2763 if (NULL == address)
2766 slen = strlen (address) + 1;
2767 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2768 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2769 if (NULL == address)
2770 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2774 * Handle AddressLookup-message.
2776 * @param cls closure (always NULL)
2777 * @param client identification of the client
2778 * @param message the actual message
2781 handle_address_lookup (void *cls,
2782 struct GNUNET_SERVER_Client *client,
2783 const struct GNUNET_MessageHeader *message)
2785 const struct AddressLookupMessage *alum;
2786 struct TransportPlugin *lsPlugin;
2787 const char *nameTransport;
2788 const char *address;
2790 struct GNUNET_SERVER_TransmitContext *tc;
2792 size = ntohs (message->size);
2793 if (size < sizeof (struct AddressLookupMessage))
2795 GNUNET_break_op (0);
2796 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2799 alum = (const struct AddressLookupMessage *) message;
2800 uint32_t addressLen = ntohl (alum->addrlen);
2801 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2803 GNUNET_break_op (0);
2804 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2807 address = (const char *) &alum[1];
2808 nameTransport = (const char *) &address[addressLen];
2810 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2812 GNUNET_break_op (0);
2813 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2816 struct GNUNET_TIME_Absolute timeout =
2817 GNUNET_TIME_absolute_ntoh (alum->timeout);
2818 struct GNUNET_TIME_Relative rtimeout =
2819 GNUNET_TIME_absolute_get_remaining (timeout);
2820 lsPlugin = find_transport (nameTransport);
2821 if (NULL == lsPlugin)
2823 tc = GNUNET_SERVER_transmit_context_create (client);
2824 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2825 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2826 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2829 tc = GNUNET_SERVER_transmit_context_create (client);
2830 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2831 address, addressLen, GNUNET_YES,
2833 &transmit_address_to_client, tc);
2837 * List of handlers for the messages understood by this
2840 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2841 {&handle_start, NULL,
2842 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2843 {&handle_hello, NULL,
2844 GNUNET_MESSAGE_TYPE_HELLO, 0},
2845 {&handle_send, NULL,
2846 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2847 {&handle_set_quota, NULL,
2848 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2849 {&handle_try_connect, NULL,
2850 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2851 sizeof (struct TryConnectMessage)},
2852 {&handle_address_lookup, NULL,
2853 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2860 * Setup the environment for this plugin.
2863 create_environment (struct TransportPlugin *plug)
2865 plug->env.cfg = cfg;
2866 plug->env.sched = sched;
2867 plug->env.my_identity = &my_identity;
2868 plug->env.cls = plug;
2869 plug->env.receive = &plugin_env_receive;
2870 plug->env.notify_address = &plugin_env_notify_address;
2871 plug->env.default_quota_in =
2872 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2873 plug->env.max_connections = max_connect_per_transport;
2878 * Start the specified transport (load the plugin).
2881 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2883 struct TransportPlugin *plug;
2886 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2887 _("Loading `%s' transport plugin\n"), name);
2888 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2889 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2890 create_environment (plug);
2891 plug->short_name = GNUNET_strdup (name);
2892 plug->lib_name = libname;
2893 plug->next = plugins;
2895 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2896 if (plug->api == NULL)
2898 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2899 _("Failed to load transport plugin for `%s'\n"), name);
2900 GNUNET_free (plug->short_name);
2901 plugins = plug->next;
2902 GNUNET_free (libname);
2909 * Called whenever a client is disconnected. Frees our
2910 * resources associated with that client.
2912 * @param cls closure
2913 * @param client identification of the client
2916 client_disconnect_notification (void *cls,
2917 struct GNUNET_SERVER_Client *client)
2919 struct TransportClient *pos;
2920 struct TransportClient *prev;
2921 struct ClientMessageQueueEntry *mqe;
2926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2927 "Client disconnected, cleaning up.\n");
2931 while ((pos != NULL) && (pos->client != client))
2938 while (NULL != (mqe = pos->message_queue_head))
2940 pos->message_queue_head = mqe->next;
2943 pos->message_queue_head = NULL;
2945 clients = pos->next;
2947 prev->next = pos->next;
2948 if (GNUNET_YES == pos->tcs_pending)
2958 * Function called when the service shuts down. Unloads our plugins.
2960 * @param cls closure, unused
2961 * @param tc task context (unused)
2964 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2966 struct TransportPlugin *plug;
2967 struct AddressList *al;
2970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2971 "Transport service is unloading plugins...\n");
2973 while (NULL != (plug = plugins))
2975 plugins = plug->next;
2976 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2977 GNUNET_free (plug->lib_name);
2978 GNUNET_free (plug->short_name);
2979 while (NULL != (al = plug->addresses))
2981 plug->addresses = al->next;
2986 if (my_private_key != NULL)
2987 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2988 GNUNET_free_non_null (our_hello);
2993 * Initiate transport service.
2995 * @param cls closure
2996 * @param s scheduler to use
2997 * @param serv the initialized server
2998 * @param c configuration to use
3002 struct GNUNET_SCHEDULER_Handle *s,
3003 struct GNUNET_SERVER_Handle *serv,
3004 const struct GNUNET_CONFIGURATION_Handle *c)
3009 unsigned long long tneigh;
3014 /* parse configuration */
3016 GNUNET_CONFIGURATION_get_value_number (c,
3021 GNUNET_CONFIGURATION_get_value_filename (c,
3023 "HOSTKEY", &keyfile)))
3025 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3027 ("Transport service is lacking key configuration settings. Exiting.\n"));
3028 GNUNET_SCHEDULER_shutdown (s);
3031 max_connect_per_transport = (uint32_t) tneigh;
3032 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3033 GNUNET_free (keyfile);
3034 if (my_private_key == NULL)
3036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3038 ("Transport service could not access hostkey. Exiting.\n"));
3039 GNUNET_SCHEDULER_shutdown (s);
3042 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3043 GNUNET_CRYPTO_hash (&my_public_key,
3044 sizeof (my_public_key), &my_identity.hashPubKey);
3045 /* setup notification */
3047 GNUNET_SERVER_disconnect_notify (server,
3048 &client_disconnect_notification, NULL);
3049 /* load plugins... */
3052 GNUNET_CONFIGURATION_get_value_string (c,
3053 "TRANSPORT", "PLUGINS", &plugs))
3055 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3056 _("Starting transport plugins `%s'\n"), plugs);
3057 pos = strtok (plugs, " ");
3060 start_transport (server, pos);
3062 pos = strtok (NULL, " ");
3064 GNUNET_free (plugs);
3066 GNUNET_SCHEDULER_add_delayed (sched,
3067 GNUNET_TIME_UNIT_FOREVER_REL,
3068 &unload_plugins, NULL);
3073 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3075 /* process client requests */
3076 GNUNET_SERVER_add_handlers (server, handlers);
3081 * The main function for the transport service.
3083 * @param argc number of arguments from the command line
3084 * @param argv command line arguments
3085 * @return 0 ok, 1 on error
3088 main (int argc, char *const *argv)
3090 return (GNUNET_OK ==
3091 GNUNET_SERVICE_run (argc,
3094 GNUNET_SERVICE_OPTION_NONE,
3095 &run, NULL)) ? 0 : 1;
3098 /* end of gnunet-service-transport.c */