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 * - This code uses 'GNUNET_a2s' for debug printing in many places,
28 * which is technically wrong since it assumes we have IP+Port
29 * (v4/v6) addresses. Once we add transports like http or smtp
30 * this will have to be changed!
33 #include "gnunet_client_lib.h"
34 #include "gnunet_container_lib.h"
35 #include "gnunet_constants.h"
36 #include "gnunet_getopt_lib.h"
37 #include "gnunet_hello_lib.h"
38 #include "gnunet_os_lib.h"
39 #include "gnunet_peerinfo_service.h"
40 #include "gnunet_plugin_lib.h"
41 #include "gnunet_protocols.h"
42 #include "gnunet_service_lib.h"
43 #include "gnunet_signatures.h"
44 #include "plugin_transport.h"
45 #include "transport.h"
48 * How many messages can we have pending for a given client process
49 * before we start to drop incoming messages? We typically should
50 * have only one client and so this would be the primary buffer for
51 * messages, so the number should be chosen rather generously.
53 * The expectation here is that most of the time the queue is large
54 * enough so that a drop is virtually never required.
56 #define MAX_PENDING 128
59 * How often should we try to reconnect to a peer using a particular
60 * transport plugin before giving up? Note that the plugin may be
61 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
63 #define MAX_CONNECT_RETRY 3
66 * Limit on the number of ready-to-run tasks when validating
67 * HELLOs. If more tasks are ready to run, we will drop
68 * HELLOs instead of validating them.
70 #define MAX_HELLO_LOAD 4
73 * How often must a peer violate bandwidth quotas before we start
74 * to simply drop its messages?
76 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
79 * How long until a HELLO verification attempt should time out?
80 * Must be rather small, otherwise a partially successful HELLO
81 * validation (some addresses working) might not be available
82 * before a client's request for a connection fails for good.
83 * Besides, if a single request to an address takes a long time,
84 * then the peer is unlikely worthwhile anyway.
86 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
89 * How long will we allow sending of a ping to be delayed?
91 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
96 #define TRANSPORT_DEFAULT_PRIORITY 4
99 * How often do we re-add (cheaper) plugins to our list of plugins
100 * to try for a given connected peer?
102 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
105 * After how long do we expire an address in a HELLO that we just
106 * validated? This value is also used for our own addresses when we
109 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
113 * List of addresses of other peers
115 struct ForeignAddressList
118 * This is a linked list.
120 struct ForeignAddressList *next;
123 * Which ready list does this entry belong to.
125 struct ReadyList *ready_list;
128 * How long until we auto-expire this address (unless it is
129 * re-confirmed by the transport)?
131 struct GNUNET_TIME_Absolute expires;
144 * What was the last latency observed for this plugin
145 * and peer? Invalid if connected is GNUNET_NO.
147 struct GNUNET_TIME_Relative latency;
150 * If we did not successfully transmit a message to the given peer
151 * via this connection during the specified time, we should consider
152 * the connection to be dead. This is used in the case that a TCP
153 * transport simply stalls writing to the stream but does not
154 * formerly get a signal that the other peer died.
156 /* FIXME: Do we need this? */
157 struct GNUNET_TIME_Absolute timeout;
160 * Is this plugin currently connected? The first time we transmit
161 * or send data to a peer via a particular plugin, we set this to
162 * GNUNET_YES. If we later get an error (disconnect notification or
163 * transmission failure), we set it back to GNUNET_NO. Each time
164 * the value is set to GNUNET_YES, we increment the
165 * "connect_attempts" counter. If that one reaches a particular
166 * threshold, we consider the address to not be working properly at
167 * this time and remove it from the eligible list.
172 * Is this plugin ready to transmit to the specific target?
173 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
174 * transmission is in progress, "transmit_ready" is set to
180 * Has this address been validated yet?
185 * How often have we tried to connect using this plugin?
187 unsigned int connect_attempts;
193 * Entry in linked list of network addresses for ourselves.
195 struct OwnAddressList
198 * This is a linked list.
200 struct OwnAddressList *next;
203 * The address, actually a pointer to the end
204 * of this struct. Do not free!
209 * How long until we auto-expire this address (unless it is
210 * re-confirmed by the transport)?
212 struct GNUNET_TIME_Absolute expires;
223 * Entry in linked list of all of our plugins.
225 struct TransportPlugin
229 * This is a linked list.
231 struct TransportPlugin *next;
234 * API of the transport as returned by the plugin's
235 * initialization function.
237 struct GNUNET_TRANSPORT_PluginFunctions *api;
240 * Short name for the plugin (i.e. "tcp").
245 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
250 * List of our known addresses for this transport.
252 struct OwnAddressList *addresses;
255 * Environment this transport service is using
258 struct GNUNET_TRANSPORT_PluginEnvironment env;
261 * ID of task that is used to clean up expired addresses.
263 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.
279 * For each neighbor we keep a list of messages
280 * that we still want to transmit to the neighbor.
286 * This is a linked list.
288 struct MessageQueue *next;
291 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
292 * stuck together in memory. Allocated at the end of this struct.
294 const char *message_buf;
297 * Size of the message buf
299 size_t message_buf_size;
302 * Client responsible for queueing the message;
303 * used to check that a client has no two messages
304 * pending for the same target. Can be NULL.
306 struct TransportClient *client;
309 * Using which specific address should we send this message?
311 struct ForeignAddressList *specific_address;
314 * Peer ID of the Neighbor this entry belongs to.
316 struct GNUNET_PeerIdentity neighbor_id;
319 * Plugin that we used for the transmission.
320 * NULL until we scheduled a transmission.
322 struct TransportPlugin *plugin;
325 * Internal message of the transport system that should not be
326 * included in the usual SEND-SEND_OK transmission confirmation
327 * traffic management scheme. Typically, "internal_msg" will
328 * be set whenever "client" is NULL (but it is not strictly
334 * How important is the message?
336 unsigned int priority;
342 * For a given Neighbor, which plugins are available
343 * to talk to this peer and what are their costs?
348 * This is a linked list.
350 struct ReadyList *next;
353 * Which of our transport plugins does this entry
356 struct TransportPlugin *plugin;
359 * Transport addresses, latency, and readiness for
360 * this particular plugin.
362 struct ForeignAddressList *addresses;
365 * Is this plugin ready to transmit to the specific target?
366 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
367 * transmission is in progress, "transmit_ready" is set to
370 // FIXME: is this dead?
371 int plugin_transmit_ready;
374 * Is the plugin represented by this entry currently connected to
375 * the respective peer?
383 * Entry in linked list of all of our current neighbors.
389 * This is a linked list.
391 struct NeighborList *next;
394 * Which of our transports is connected to this peer
395 * and what is their status?
397 struct ReadyList *plugins;
400 * List of messages we would like to send to this peer;
401 * must contain at most one message per client.
403 struct MessageQueue *messages;
406 * Identity of this neighbor.
408 struct GNUNET_PeerIdentity id;
411 * ID of task scheduled to run when this peer is about to
412 * time out (will free resources associated with the peer).
414 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
417 * How long until we should consider this peer dead
418 * (if we don't receive another message in the
421 struct GNUNET_TIME_Absolute peer_timeout;
424 * At what time did we reset last_received last?
426 struct GNUNET_TIME_Absolute last_quota_update;
429 * The latency we have seen for this particular address for
430 * this particular peer. This latency may have been calculated
431 * over multiple transports. This value reflects how long it took
432 * us to receive a response when SENDING via this particular
433 * transport/neighbor/address combination!
434 * FIXME: why is this NBO?
436 struct GNUNET_TIME_RelativeNBO latency;
439 * How many bytes have we received since the "last_quota_update"
442 uint64_t last_received;
445 * Global quota for inbound traffic for the neighbor in bytes/ms.
450 * How often has the other peer (recently) violated the
451 * inbound traffic limit? Incremented by 10 per violation,
452 * decremented by 1 per non-violation (for each
455 unsigned int quota_violation_count;
458 * Have we seen an ACK from this neighbor in the past?
459 * (used to make up a fake ACK for clients connecting after
460 * the neighbor connected to us).
467 * Message used to ask a peer to validate receipt (to check an address
468 * from a HELLO). Followed by the address used. Note that the
469 * recipients response does not affirm that he has this address,
470 * only that he got the challenge message.
472 struct TransportPingMessage
476 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
478 struct GNUNET_MessageHeader header;
481 * Random challenge number (in network byte order).
483 uint32_t challenge GNUNET_PACKED;
486 * Who is the intended recipient?
488 struct GNUNET_PeerIdentity target;
494 * Message used to validate a HELLO. The challenge is included in the
495 * confirmation to make matching of replies to requests possible. The
496 * signature signs the original challenge number, our public key, the
497 * sender's address (so that the sender can check that the address we
498 * saw is plausible for him and possibly detect a MiM attack) and a
499 * timestamp (to limit replay).<p>
501 * This message is followed by the address of the
502 * client that we are observing (which is part of what
505 struct TransportPongMessage
509 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
511 struct GNUNET_MessageHeader header;
514 * For padding, always zero.
516 uint32_t reserved GNUNET_PACKED;
521 struct GNUNET_CRYPTO_RsaSignature signature;
524 * What are we signing and why?
526 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
529 * Random challenge number (in network byte order).
531 uint32_t challenge GNUNET_PACKED;
534 * Who signed this message?
536 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
539 * Size of address appended to this message
546 * Linked list of messages to be transmitted to
547 * the client. Each entry is followed by the
550 struct ClientMessageQueueEntry
553 * This is a linked list.
555 struct ClientMessageQueueEntry *next;
560 * Client connected to the transport service.
562 struct TransportClient
566 * This is a linked list.
568 struct TransportClient *next;
571 * Handle to the client.
573 struct GNUNET_SERVER_Client *client;
576 * Linked list of messages yet to be transmitted to
579 struct ClientMessageQueueEntry *message_queue_head;
582 * Tail of linked list of messages yet to be transmitted to the
585 struct ClientMessageQueueEntry *message_queue_tail;
588 * Is a call to "transmit_send_continuation" pending? If so, we
589 * must not free this struct (even if the corresponding client
590 * disconnects) and instead only remove it from the linked list and
591 * set the "client" field to NULL.
596 * Length of the list of messages pending for this client.
598 unsigned int message_count;
604 * Entry in map of all HELLOs awaiting validation.
606 struct ValidationEntry
610 * The address, actually a pointer to the end
611 * of this struct. Do not free!
616 * Name of the transport.
618 char *transport_name;
621 * The public key of the peer.
623 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
626 * ID of task that will clean up this entry if we don't succeed
627 * with the validation first.
629 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
632 * At what time did we send this validation?
634 struct GNUNET_TIME_Absolute send_time;
642 * Challenge number we used.
650 * Context of currently active requests to peerinfo
651 * for validation of HELLOs.
653 struct CheckHelloValidatedContext
657 * This is a doubly-linked list.
659 struct CheckHelloValidatedContext *next;
662 * This is a doubly-linked list.
664 struct CheckHelloValidatedContext *prev;
667 * Hello that we are validating.
669 const struct GNUNET_HELLO_Message *hello;
672 * Context for peerinfo iteration.
673 * NULL after we are done processing peerinfo's information.
675 struct GNUNET_PEERINFO_IteratorContext *piter;
678 * Was a HELLO known for this peer to peerinfo?
688 static struct GNUNET_HELLO_Message *our_hello;
691 * "version" of "our_hello". Used to see if a given neighbor has
692 * already been sent the latest version of our HELLO message.
694 static unsigned int our_hello_version;
699 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
704 static struct GNUNET_PeerIdentity my_identity;
709 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
714 struct GNUNET_SCHEDULER_Handle *sched;
719 const struct GNUNET_CONFIGURATION_Handle *cfg;
722 * Linked list of all clients to this service.
724 static struct TransportClient *clients;
727 * All loaded plugins.
729 static struct TransportPlugin *plugins;
734 static struct GNUNET_SERVER_Handle *server;
737 * All known neighbors and their HELLOs.
739 static struct NeighborList *neighbors;
742 * Number of neighbors we'd like to have.
744 static uint32_t max_connect_per_transport;
747 * Head of linked list.
749 static struct CheckHelloValidatedContext *chvc_head;
752 * Tail of linked list.
754 static struct CheckHelloValidatedContext *chvc_tail;
758 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
759 * of the given peer that we are currently validating).
761 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
766 * The peer specified by the given neighbor has timed-out or a plugin
767 * has disconnected. We may either need to do nothing (other plugins
768 * still up), or trigger a full disconnect and clean up. This
769 * function updates our state and do the necessary notifications.
770 * Also notifies our clients that the neighbor is now officially
773 * @param n the neighbor list entry for the peer
774 * @param check should we just check if all plugins
775 * disconnected or must we ask all plugins to
778 static void disconnect_neighbor (struct NeighborList *n, int check);
781 * Check the ready list for the given neighbor and if a plugin is
782 * ready for transmission (and if we have a message), do so!
784 * @param neighbor target peer for which to transmit
786 static void try_transmission_to_peer (struct NeighborList *neighbor);
790 * Find an entry in the neighbor list for a particular peer.
791 * if sender_address is not specified (NULL) then return the
792 * first matching entry. If sender_address is specified, then
793 * make sure that the address and address_len also matches.
795 * @return NULL if not found.
797 static struct NeighborList *
798 find_neighbor (const struct GNUNET_PeerIdentity *key)
800 struct NeighborList *head = neighbors;
802 while ((head != NULL) &&
803 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
810 * Find an entry in the transport list for a particular transport.
812 * @return NULL if not found.
814 static struct TransportPlugin *
815 find_transport (const char *short_name)
817 struct TransportPlugin *head = plugins;
818 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
825 * Update the quota values for the given neighbor now.
828 update_quota (struct NeighborList *n)
830 struct GNUNET_TIME_Relative delta;
834 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
835 if (delta.value < MIN_QUOTA_REFRESH_TIME)
836 return; /* not enough time passed for doing quota update */
837 allowed = delta.value * n->quota_in;
839 if (n->last_received < allowed)
841 remaining = allowed - n->last_received;
843 remaining /= n->quota_in;
846 if (remaining > MAX_BANDWIDTH_CARRY)
847 remaining = MAX_BANDWIDTH_CARRY;
848 n->last_received = 0;
849 n->last_quota_update = GNUNET_TIME_absolute_get ();
850 n->last_quota_update.value -= remaining;
851 if (n->quota_violation_count > 0)
852 n->quota_violation_count--;
856 n->last_received -= allowed;
857 n->last_quota_update = GNUNET_TIME_absolute_get ();
858 if (n->last_received > allowed)
860 /* more than twice the allowed rate! */
861 n->quota_violation_count += 10;
868 * Function called to notify a client about the socket being ready to
869 * queue more data. "buf" will be NULL and "size" zero if the socket
870 * was closed for writing in the meantime.
873 * @param size number of bytes available in buf
874 * @param buf where the callee should write the message
875 * @return number of bytes written to buf
878 transmit_to_client_callback (void *cls, size_t size, void *buf)
880 struct TransportClient *client = cls;
881 struct ClientMessageQueueEntry *q;
884 const struct GNUNET_MessageHeader *msg;
885 struct GNUNET_CONNECTION_TransmitHandle *th;
890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891 "Transmission to client failed, closing connection.\n");
892 /* fatal error with client, free message queue! */
893 while (NULL != (q = client->message_queue_head))
895 client->message_queue_head = q->next;
898 client->message_queue_tail = NULL;
899 client->message_count = 0;
904 while (NULL != (q = client->message_queue_head))
906 msg = (const struct GNUNET_MessageHeader *) &q[1];
907 msize = ntohs (msg->size);
908 if (msize + tsize > size)
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
912 "Transmitting message of type %u to client.\n",
915 client->message_queue_head = q->next;
917 client->message_queue_tail = NULL;
918 memcpy (&cbuf[tsize], msg, msize);
921 client->message_count--;
925 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
926 th = GNUNET_SERVER_notify_transmit_ready (client->client,
928 GNUNET_TIME_UNIT_FOREVER_REL,
929 &transmit_to_client_callback,
931 GNUNET_assert (th != NULL);
938 * Send the specified message to the specified client. Since multiple
939 * messages may be pending for the same client at a time, this code
940 * makes sure that no message is lost.
942 * @param client client to transmit the message to
943 * @param msg the message to send
944 * @param may_drop can this message be dropped if the
945 * message queue for this client is getting far too large?
948 transmit_to_client (struct TransportClient *client,
949 const struct GNUNET_MessageHeader *msg, int may_drop)
951 struct ClientMessageQueueEntry *q;
953 struct GNUNET_CONNECTION_TransmitHandle *th;
955 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
957 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
959 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
960 client->message_count, MAX_PENDING);
961 /* TODO: call to statistics... */
964 client->message_count++;
965 msize = ntohs (msg->size);
966 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
967 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
968 memcpy (&q[1], msg, msize);
969 /* append to message queue */
970 if (client->message_queue_tail == NULL)
972 client->message_queue_tail = q;
976 client->message_queue_tail->next = q;
977 client->message_queue_tail = q;
979 if (client->message_queue_head == NULL)
981 client->message_queue_head = q;
982 th = GNUNET_SERVER_notify_transmit_ready (client->client,
984 GNUNET_TIME_UNIT_FOREVER_REL,
985 &transmit_to_client_callback,
987 GNUNET_assert (th != NULL);
993 * Function called by the GNUNET_TRANSPORT_TransmitFunction
994 * upon "completion" of a send request. This tells the API
995 * that it is now legal to send another message to the given
998 * @param cls closure, identifies the entry on the
999 * message queue that was transmitted and the
1000 * client responsible for queueing the message
1001 * @param target the peer receiving the message
1002 * @param result GNUNET_OK on success, if the transmission
1003 * failed, we should not tell the client to transmit
1007 transmit_send_continuation (void *cls,
1008 const struct GNUNET_PeerIdentity *target,
1011 struct MessageQueue *mq = cls;
1012 /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1013 struct SendOkMessage send_ok_msg;
1014 struct NeighborList *n;
1016 GNUNET_assert (mq != NULL);
1017 n = find_neighbor(&mq->neighbor_id);
1018 if (n == NULL) /* Neighbor must have been removed asynchronously! */
1021 /* Otherwise, let's make sure we've got the right peer */
1023 memcmp (&n->id, target,
1024 sizeof (struct GNUNET_PeerIdentity)));
1026 if (result == GNUNET_OK)
1028 mq->specific_address->timeout =
1029 GNUNET_TIME_relative_to_absolute
1030 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035 "Transmission to peer `%s' failed, marking connection as down.\n",
1036 GNUNET_i2s (target));
1037 mq->specific_address->connected = GNUNET_NO;
1039 if (!mq->internal_msg)
1042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043 "Setting transmit_ready on transport!\n");
1045 mq->specific_address->transmit_ready = GNUNET_YES;
1048 if (mq->client != NULL)
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Notifying client %p about transmission to peer `%4s'.\n",
1052 mq->client, GNUNET_i2s (target));
1053 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1054 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1055 send_ok_msg.success = htonl (result);
1056 send_ok_msg.peer = n->id;
1057 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1060 /* one plugin just became ready again, try transmitting
1061 another message (if available) */
1062 if (result == GNUNET_OK)
1063 try_transmission_to_peer (n);
1065 disconnect_neighbor (n, GNUNET_YES);
1070 * Find an address in any of the available transports for
1071 * the given neighbor that would be good for message
1072 * transmission. This is essentially the transport selection
1075 * @param neighbor for whom to select an address
1076 * @return selected address, NULL if we have none
1078 struct ForeignAddressList *
1079 find_ready_address(struct NeighborList *neighbor)
1081 struct ReadyList *head = neighbor->plugins;
1082 struct ForeignAddressList *addresses;
1083 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1084 struct ForeignAddressList *best_address;
1086 best_address = NULL;
1087 while (head != NULL)
1089 addresses = head->addresses;
1090 while (addresses != NULL)
1092 if ( (addresses->timeout.value < now.value) &&
1093 (addresses->connected == GNUNET_YES) )
1096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1097 "Marking long-time inactive connection to `%4s' as down.\n",
1098 GNUNET_i2s (&neighbor->id));
1100 addresses->connected = GNUNET_NO;
1102 addresses = addresses->next;
1105 addresses = head->addresses;
1106 while (addresses != NULL)
1108 if ( ( (best_address == NULL) ||
1109 (addresses->connected == GNUNET_YES) ||
1110 (best_address->connected == GNUNET_NO) ) &&
1111 (addresses->transmit_ready == GNUNET_YES) &&
1112 ( (best_address == NULL) ||
1113 (addresses->latency.value < best_address->latency.value)) )
1114 best_address = addresses;
1115 /* FIXME: also give lower-latency addresses that are not
1116 connected a chance some times... */
1117 addresses = addresses->next;
1122 if (best_address != NULL)
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Best address found has latency of %llu ms.\n",
1126 best_address->latency.value);
1129 return best_address;
1135 * Check the ready list for the given neighbor and if a plugin is
1136 * ready for transmission (and if we have a message), do so!
1138 * @param neighbor target peer for which to transmit
1141 try_transmission_to_peer (struct NeighborList *neighbor)
1143 struct GNUNET_TIME_Relative min_latency;
1144 struct ReadyList *rl;
1145 struct MessageQueue *mq;
1147 if (neighbor->messages == NULL)
1148 return; /* nothing to do */
1149 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1151 mq = neighbor->messages;
1152 if (mq->specific_address == NULL)
1153 mq->specific_address = find_ready_address(neighbor);
1154 if (mq->specific_address == NULL)
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 "No destination address available to transmit message of size %u to peer `%4s'\n",
1159 mq->message_buf_size,
1160 GNUNET_i2s (&mq->neighbor_id));
1162 return; /* nobody ready */
1164 rl = mq->specific_address->ready_list;
1165 neighbor->messages = mq->next;
1166 mq->plugin = rl->plugin;
1167 if (!mq->internal_msg)
1168 mq->specific_address->transmit_ready = GNUNET_NO;
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1172 mq->message_buf_size,
1173 GNUNET_i2s (&neighbor->id),
1174 GNUNET_a2s (mq->specific_address->addr,
1175 mq->specific_address->addrlen),
1176 rl->plugin->short_name);
1178 rl->plugin->api->send (rl->plugin->api->cls,
1181 mq->message_buf_size,
1183 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1184 mq->specific_address->addr,
1185 mq->specific_address->addrlen,
1186 GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1187 &transmit_send_continuation, mq);
1192 * Send the specified message to the specified peer.
1194 * @param client source of the transmission request (can be NULL)
1195 * @param peer_address ForeignAddressList where we should send this message
1196 * @param priority how important is the message
1197 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1198 * @param message_buf_size total size of all messages in message_buf
1199 * @param is_internal is this an internal message
1200 * @param neighbor handle to the neighbor for transmission
1203 transmit_to_peer (struct TransportClient *client,
1204 struct ForeignAddressList *peer_address,
1205 unsigned int priority,
1206 const char *message_buf,
1207 size_t message_buf_size,
1208 int is_internal, struct NeighborList *neighbor)
1210 struct MessageQueue *mq;
1211 struct MessageQueue *mqe;
1215 /* check for duplicate submission */
1216 mq = neighbor->messages;
1219 if (mq->client == client)
1221 /* client transmitted to same peer twice
1222 before getting SendOk! */
1229 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1230 mq->specific_address = peer_address;
1231 mq->client = client;
1232 memcpy (&mq[1], message_buf, message_buf_size);
1233 mq->message_buf = (const char*) &mq[1];
1234 mq->message_buf_size = message_buf_size;
1235 memcpy(&mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1236 mq->internal_msg = is_internal;
1237 mq->priority = priority;
1241 /* append at head */
1242 mq->next = neighbor->messages;
1243 neighbor->messages = mq;
1248 mqe = neighbor->messages;
1250 while (mqe->next != NULL)
1255 neighbor->messages = mq;
1263 try_transmission_to_peer (neighbor);
1270 struct GeneratorContext
1272 struct TransportPlugin *plug_pos;
1273 struct OwnAddressList *addr_pos;
1274 struct GNUNET_TIME_Absolute expiration;
1282 address_generator (void *cls, size_t max, void *buf)
1284 struct GeneratorContext *gc = cls;
1287 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1289 gc->plug_pos = gc->plug_pos->next;
1290 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1292 if (NULL == gc->plug_pos)
1297 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1300 gc->addr_pos->addrlen, buf, max);
1301 gc->addr_pos = gc->addr_pos->next;
1307 * Construct our HELLO message from all of the addresses of
1308 * all of the transports.
1313 struct GNUNET_HELLO_Message *hello;
1314 struct TransportClient *cpos;
1315 struct NeighborList *npos;
1316 struct GeneratorContext gc;
1318 gc.plug_pos = plugins;
1319 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1320 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1321 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1324 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1327 while (cpos != NULL)
1329 transmit_to_client (cpos,
1330 (const struct GNUNET_MessageHeader *) hello,
1335 GNUNET_free_non_null (our_hello);
1337 our_hello_version++;
1338 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1340 while (npos != NULL)
1343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1344 "Transmitting updated `%s' to neighbor `%4s'\n",
1345 "HELLO", GNUNET_i2s (&npos->id));
1347 transmit_to_peer (NULL, NULL, 0,
1348 (const char *) our_hello,
1349 GNUNET_HELLO_size(our_hello),
1357 * Task used to clean up expired addresses for a plugin.
1359 * @param cls closure
1363 expire_address_task (void *cls,
1364 const struct GNUNET_SCHEDULER_TaskContext *tc);
1368 * Update the list of addresses for this plugin,
1369 * expiring those that are past their expiration date.
1371 * @param plugin addresses of which plugin should be recomputed?
1372 * @param fresh set to GNUNET_YES if a new address was added
1373 * and we need to regenerate the HELLO even if nobody
1377 update_addresses (struct TransportPlugin *plugin, int fresh)
1379 struct GNUNET_TIME_Relative min_remaining;
1380 struct GNUNET_TIME_Relative remaining;
1381 struct GNUNET_TIME_Absolute now;
1382 struct OwnAddressList *pos;
1383 struct OwnAddressList *prev;
1384 struct OwnAddressList *next;
1387 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1388 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1389 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1390 now = GNUNET_TIME_absolute_get ();
1391 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1392 expired = GNUNET_NO;
1394 pos = plugin->addresses;
1398 if (pos->expires.value < now.value)
1400 expired = GNUNET_YES;
1402 plugin->addresses = pos->next;
1404 prev->next = pos->next;
1409 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1410 if (remaining.value < min_remaining.value)
1411 min_remaining = remaining;
1417 if (expired || fresh)
1419 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1420 plugin->address_update_task
1421 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1423 &expire_address_task, plugin);
1429 * Task used to clean up expired addresses for a plugin.
1431 * @param cls closure
1435 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1437 struct TransportPlugin *plugin = cls;
1438 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1439 update_addresses (plugin, GNUNET_NO);
1444 * Function that must be called by each plugin to notify the
1445 * transport service about the addresses under which the transport
1446 * provided by the plugin can be reached.
1448 * @param cls closure
1449 * @param name name of the transport that generated the address
1450 * @param addr one of the addresses of the host, NULL for the last address
1451 * the specific address format depends on the transport
1452 * @param addrlen length of the address
1453 * @param expires when should this address automatically expire?
1456 plugin_env_notify_address (void *cls,
1460 struct GNUNET_TIME_Relative expires)
1462 struct TransportPlugin *p = cls;
1463 struct OwnAddressList *al;
1464 struct GNUNET_TIME_Absolute abex;
1466 abex = GNUNET_TIME_relative_to_absolute (expires);
1467 GNUNET_assert (p == find_transport (name));
1472 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1474 if (al->expires.value < abex.value)
1481 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1483 al->next = p->addresses;
1486 al->addrlen = addrlen;
1487 memcpy (&al[1], addr, addrlen);
1488 update_addresses (p, GNUNET_YES);
1493 * Notify all of our clients about a peer connecting.
1496 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1497 struct GNUNET_TIME_Relative latency)
1499 struct ConnectInfoMessage cim;
1500 struct TransportClient *cpos;
1502 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1503 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1504 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1505 cim.latency = GNUNET_TIME_relative_hton (latency);
1506 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1508 while (cpos != NULL)
1510 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1517 * Notify all of our clients about a peer disconnecting.
1520 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1522 struct DisconnectInfoMessage dim;
1523 struct TransportClient *cpos;
1525 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1526 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1527 dim.reserved = htonl (0);
1528 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1530 while (cpos != NULL)
1532 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1539 * Find a ForeignAddressList entry for the given neighbour
1540 * that matches the given address and transport.
1542 * @param neighbor which peer we care about
1543 * @param tname name of the transport plugin
1544 * @param addr binary address
1545 * @param addrlen length of addr
1546 * @return NULL if no such entry exists
1548 static struct ForeignAddressList *
1549 find_peer_address(struct NeighborList *neighbor,
1554 struct ReadyList *head;
1555 struct ForeignAddressList *address_head;
1557 head = neighbor->plugins;
1558 while (head != NULL)
1560 if (0 == strcmp (tname, head->plugin->short_name))
1567 address_head = head->addresses;
1568 while ( (address_head != NULL) &&
1569 ( (address_head->addrlen != addrlen) ||
1570 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1571 address_head = address_head->next;
1572 return address_head;
1577 * Get the peer address struct for the given neighbor and
1578 * address. If it doesn't yet exist, create it.
1580 * @param neighbor which peer we care about
1581 * @param tname name of the transport plugin
1582 * @param addr binary address
1583 * @param addrlen length of addr
1584 * @return NULL if we do not have a transport plugin for 'tname'
1586 static struct ForeignAddressList *
1587 add_peer_address(struct NeighborList *neighbor,
1592 struct ReadyList *head;
1593 struct ForeignAddressList *ret;
1595 ret = find_peer_address (neighbor, tname, addr, addrlen);
1598 head = neighbor->plugins;
1599 while (head != NULL)
1601 if (0 == strcmp (tname, head->plugin->short_name))
1607 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1608 ret->addr = (const char*) &ret[1];
1609 memcpy (&ret[1], addr, addrlen);
1610 ret->addrlen = addrlen;
1611 ret->expires = GNUNET_TIME_relative_to_absolute
1612 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1613 ret->latency = GNUNET_TIME_relative_get_forever();
1614 ret->transmit_ready = GNUNET_YES;
1615 ret->timeout = GNUNET_TIME_relative_to_absolute
1616 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1617 ret->ready_list = head;
1618 ret->next = head->addresses;
1619 head->addresses = ret;
1625 * Closure for 'add_validated_address'.
1627 struct AddValidatedAddressContext
1630 * Entry that has been validated.
1632 const struct ValidationEntry *ve;
1635 * Flag set after we have added the address so
1636 * that we terminate the iteration next time.
1643 * Callback function used to fill a buffer of max bytes with a list of
1644 * addresses in the format used by HELLOs. Should use
1645 * "GNUNET_HELLO_add_address" as a helper function.
1647 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1648 * @param max maximum number of bytes that can be written to buf
1649 * @param buf where to write the address information
1650 * @return number of bytes written, 0 to signal the
1651 * end of the iteration.
1654 add_validated_address (void *cls,
1655 size_t max, void *buf)
1657 struct AddValidatedAddressContext *avac = cls;
1658 const struct ValidationEntry *ve = avac->ve;
1660 if (GNUNET_YES == avac->done)
1662 avac->done = GNUNET_YES;
1663 return GNUNET_HELLO_add_address (ve->transport_name,
1664 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1673 * Iterator over hash map entries. Checks if the given
1674 * validation entry is for the same challenge as what
1675 * is given in the PONG.
1677 * @param cls the 'struct TransportPongMessage*'
1678 * @param key peer identity
1679 * @param value value in the hash map ('struct ValidationEntry')
1680 * @return GNUNET_YES if we should continue to
1681 * iterate (mismatch), GNUNET_NO if not (entry matched)
1684 check_pending_validation (void *cls,
1685 const GNUNET_HashCode * key,
1688 const struct TransportPongMessage *pong = cls;
1689 struct ValidationEntry *ve = value;
1690 struct AddValidatedAddressContext avac;
1691 unsigned int challenge = ntohl(pong->challenge);
1692 struct GNUNET_HELLO_Message *hello;
1693 struct GNUNET_PeerIdentity target;
1694 struct NeighborList *n;
1695 struct ForeignAddressList *fal;
1697 if (ve->challenge != challenge)
1701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
1704 GNUNET_a2s ((const struct sockaddr *) ve->addr,
1706 ve->transport_name);
1708 /* create the updated HELLO */
1709 GNUNET_CRYPTO_hash (&ve->publicKey,
1710 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1711 &target.hashPubKey);
1712 avac.done = GNUNET_NO;
1714 hello = GNUNET_HELLO_create (&ve->publicKey,
1715 &add_validated_address,
1717 GNUNET_PEERINFO_add_peer (cfg, sched,
1720 GNUNET_free (hello);
1721 n = find_neighbor (&target);
1724 fal = add_peer_address (n, ve->transport_name,
1727 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1728 fal->validated = GNUNET_YES;
1729 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
1732 /* clean up validation entry */
1733 GNUNET_assert (GNUNET_YES ==
1734 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1737 GNUNET_SCHEDULER_cancel (sched,
1739 GNUNET_free (ve->transport_name);
1746 * Function that will be called if we receive a validation
1747 * of an address challenge that we transmitted to another
1748 * peer. Note that the validation should only be considered
1749 * acceptable if the challenge matches AND if the sender
1750 * address is at least a plausible address for this peer
1751 * (otherwise we may be seeing a MiM attack).
1753 * @param cls closure
1754 * @param name name of the transport that generated the address
1755 * @param peer who responded to our challenge
1756 * @param challenge the challenge number we presumably used
1757 * @param sender_addr string describing our sender address (as observed
1758 * by the other peer in human-readable format)
1761 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1762 const struct GNUNET_PeerIdentity *peer,
1763 const char *sender_address,
1764 size_t sender_address_len)
1766 #if DEBUG_TRANSPORT > 1
1767 /* we get tons of these that just get discarded, only log
1768 if we are quite verbose */
1769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1770 "Receiving `%s' message from `%4s'.\n", "PONG",
1773 if (GNUNET_SYSERR !=
1774 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1776 &check_pending_validation,
1779 /* This is *expected* to happen a lot since we send
1780 PONGs to *all* known addresses of the sender of
1781 the PING, so most likely we get multiple PONGs
1782 per PING, and all but the first PONG will end up
1783 here. So really we should not print anything here
1784 unless we want to be very, very verbose... */
1785 #if DEBUG_TRANSPORT > 2
1786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1787 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
1795 /* FIXME: add given address to potential pool of our addresses
1797 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1798 _("Another peer saw us using the address `%s' via `%s'.\n"),
1799 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1800 ntohs(pong->addrlen)),
1801 va->transport_name);
1807 neighbor_timeout_task (void *cls,
1808 const struct GNUNET_SCHEDULER_TaskContext *tc)
1810 struct NeighborList *n = cls;
1813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1814 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1816 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1817 disconnect_neighbor (n, GNUNET_NO);
1822 * Create a fresh entry in our neighbor list for the given peer.
1823 * Will try to transmit our current HELLO to the new neighbor. Also
1824 * notifies our clients about the new "connection".
1826 * @param peer the peer for which we create the entry
1827 * @return the new neighbor list entry
1829 static struct NeighborList *
1830 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1832 struct NeighborList *n;
1833 struct TransportPlugin *tp;
1834 struct ReadyList *rl;
1836 GNUNET_assert (our_hello != NULL);
1837 n = GNUNET_malloc (sizeof (struct NeighborList));
1838 n->next = neighbors;
1841 n->last_quota_update = GNUNET_TIME_absolute_get ();
1843 GNUNET_TIME_relative_to_absolute
1844 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1845 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1849 if (tp->api->send != NULL)
1851 rl = GNUNET_malloc (sizeof (struct ReadyList));
1852 rl->next = n->plugins;
1855 rl->addresses = NULL;
1859 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1860 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1861 &neighbor_timeout_task, n);
1862 transmit_to_peer (NULL, NULL, 0,
1863 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1865 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1871 * Closure for 'check_address_exists'.
1873 struct CheckAddressExistsClosure
1876 * Address to check for.
1881 * Name of the transport.
1891 * Set to GNUNET_YES if the address exists.
1898 * Iterator over hash map entries. Checks if the given
1899 * validation entry is for the same address as what is given
1902 * @param cls the 'struct CheckAddressExistsClosure*'
1903 * @param key current key code (ignored)
1904 * @param value value in the hash map ('struct ValidationEntry')
1905 * @return GNUNET_YES if we should continue to
1906 * iterate (mismatch), GNUNET_NO if not (entry matched)
1909 check_address_exists (void *cls,
1910 const GNUNET_HashCode * key,
1913 struct CheckAddressExistsClosure *caec = cls;
1914 struct ValidationEntry *ve = value;
1915 if ( (0 == strcmp (caec->tname,
1916 ve->transport_name)) &&
1917 (caec->addrlen == ve->addrlen) &&
1918 (0 == memcmp (caec->addr,
1922 caec->exists = GNUNET_YES;
1930 * HELLO validation cleanup task (validation failed).
1932 * @param cls the 'struct ValidationEntry' that failed
1933 * @param tc scheduler context (unused)
1936 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1938 struct ValidationEntry *va = cls;
1939 struct GNUNET_PeerIdentity pid;
1941 GNUNET_CRYPTO_hash (&va->publicKey,
1943 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1945 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1948 GNUNET_free (va->transport_name);
1954 * Check if the given address is already being validated; if not,
1955 * append the given address to the list of entries that are being be
1956 * validated and initiate validation.
1958 * @param cls closure ('struct CheckHelloValidatedContext *')
1959 * @param tname name of the transport
1960 * @param expiration expiration time
1961 * @param addr the address
1962 * @param addrlen length of the address
1963 * @return GNUNET_OK (always)
1966 run_validation (void *cls,
1968 struct GNUNET_TIME_Absolute expiration,
1969 const void *addr, size_t addrlen)
1971 struct CheckHelloValidatedContext *chvc = cls;
1972 struct GNUNET_PeerIdentity id;
1973 struct TransportPlugin *tp;
1974 struct ValidationEntry *va;
1975 struct NeighborList *neighbor;
1976 struct ForeignAddressList *peer_address;
1977 struct TransportPingMessage ping;
1978 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
1979 struct CheckAddressExistsClosure caec;
1981 uint16_t hello_size;
1984 tp = find_transport (tname);
1987 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1988 GNUNET_ERROR_TYPE_BULK,
1990 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1994 GNUNET_HELLO_get_key (chvc->hello, &pk);
1995 GNUNET_CRYPTO_hash (&pk,
1997 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2000 caec.addrlen = addrlen;
2002 caec.exists = GNUNET_NO;
2003 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2004 &check_address_exists,
2006 if (caec.exists == GNUNET_YES)
2008 /* During validation attempts we will likely trigger the other
2009 peer trying to validate our address which in turn will cause
2010 it to send us its HELLO, so we expect to hit this case rather
2011 frequently. Only print something if we are very verbose. */
2012 #if DEBUG_TRANSPORT > 1
2013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2014 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2015 GNUNET_a2s (addr, addrlen),
2021 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2022 va->transport_name = GNUNET_strdup (tname);
2023 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2025 va->send_time = GNUNET_TIME_absolute_get();
2026 va->addr = (const void*) &va[1];
2027 memcpy (&va[1], addr, addrlen);
2028 va->addrlen = addrlen;
2029 GNUNET_HELLO_get_key (chvc->hello,
2031 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2032 HELLO_VERIFICATION_TIMEOUT,
2033 &timeout_hello_validation,
2035 GNUNET_CONTAINER_multihashmap_put (validation_map,
2038 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2039 neighbor = find_neighbor(&id);
2040 if (neighbor == NULL)
2041 neighbor = setup_new_neighbor(&id);
2042 peer_address = add_peer_address(neighbor, tname, addr, addrlen);
2043 GNUNET_assert(peer_address != NULL);
2044 hello_size = GNUNET_HELLO_size(our_hello);
2045 tsize = sizeof(struct TransportPingMessage) + hello_size;
2046 message_buf = GNUNET_malloc(tsize);
2047 ping.challenge = htonl(va->challenge);
2048 ping.header.size = htons(sizeof(struct TransportPingMessage));
2049 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2050 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2051 memcpy(message_buf, our_hello, hello_size);
2052 memcpy(&message_buf[hello_size],
2054 sizeof(struct TransportPingMessage));
2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2057 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2058 GNUNET_a2s (addr, addrlen),
2061 "HELLO", hello_size,
2062 "PING", sizeof (struct TransportPingMessage));
2064 transmit_to_peer(NULL, peer_address,
2065 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2067 GNUNET_YES, neighbor);
2068 GNUNET_free(message_buf);
2074 * Add the given address to the list of foreign addresses
2075 * available for the given peer (check for duplicates).
2077 * @param cls the respective 'struct NeighborList' to update
2078 * @param tname name of the transport
2079 * @param expiration expiration time
2080 * @param addr the address
2081 * @param addrlen length of the address
2082 * @return GNUNET_OK (always)
2085 add_to_foreign_address_list (void *cls,
2087 struct GNUNET_TIME_Absolute expiration,
2088 const void *addr, size_t addrlen)
2090 struct NeighborList *n = cls;
2091 struct ForeignAddressList *fal;
2093 fal = find_peer_address (n, tname, addr, addrlen);
2097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2098 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data.\n",
2099 GNUNET_a2s (addr, addrlen),
2101 GNUNET_i2s (&n->id));
2103 fal = add_peer_address (n, tname, addr, addrlen);
2105 fal->expires = GNUNET_TIME_absolute_max (expiration,
2107 fal->validated = GNUNET_YES;
2113 * Check if addresses in validated hello "h" overlap with
2114 * those in "chvc->hello" and validate the rest.
2116 * @param cls closure
2117 * @param peer id of the peer, NULL for last call
2118 * @param hello hello message for the peer (can be NULL)
2119 * @param trust amount of trust we have in the peer (not used)
2122 check_hello_validated (void *cls,
2123 const struct GNUNET_PeerIdentity *peer,
2124 const struct GNUNET_HELLO_Message *h,
2127 struct CheckHelloValidatedContext *chvc = cls;
2128 struct GNUNET_HELLO_Message *plain_hello;
2129 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2130 struct GNUNET_PeerIdentity target;
2131 struct NeighborList *n;
2136 GNUNET_CONTAINER_DLL_remove (chvc_head,
2139 if (GNUNET_NO == chvc->hello_known)
2141 /* notify PEERINFO about the peer now, so that we at least
2142 have the public key if some other component needs it */
2143 GNUNET_HELLO_get_key (chvc->hello, &pk);
2144 GNUNET_CRYPTO_hash (&pk,
2145 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2146 &target.hashPubKey);
2147 plain_hello = GNUNET_HELLO_create (&pk,
2150 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2151 GNUNET_free (plain_hello);
2153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2154 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2156 GNUNET_i2s (&target));
2158 GNUNET_HELLO_iterate_addresses (chvc->hello,
2168 chvc->hello_known = GNUNET_YES;
2169 n = find_neighbor (peer);
2171 GNUNET_HELLO_iterate_addresses (h,
2173 &add_to_foreign_address_list,
2175 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2177 GNUNET_TIME_absolute_get (),
2183 * Process HELLO-message.
2185 * @param plugin transport involved, may be NULL
2186 * @param message the actual message
2187 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2190 process_hello (struct TransportPlugin *plugin,
2191 const struct GNUNET_MessageHeader *message)
2194 struct GNUNET_PeerIdentity target;
2195 const struct GNUNET_HELLO_Message *hello;
2196 struct CheckHelloValidatedContext *chvc;
2197 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2199 hsize = ntohs (message->size);
2200 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2201 (hsize < sizeof (struct GNUNET_MessageHeader)))
2204 return GNUNET_SYSERR;
2206 /* first, check if load is too high */
2207 if (GNUNET_SCHEDULER_get_load (sched,
2208 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2210 /* TODO: call to stats? */
2213 hello = (const struct GNUNET_HELLO_Message *) message;
2214 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2216 GNUNET_break_op (0);
2217 return GNUNET_SYSERR;
2219 GNUNET_CRYPTO_hash (&publicKey,
2220 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2221 &target.hashPubKey);
2223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2224 "Processing `%s' message for `%4s' of size %u\n",
2226 GNUNET_i2s (&target),
2227 GNUNET_HELLO_size(hello));
2230 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2231 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2232 memcpy (&chvc[1], hello, hsize);
2233 GNUNET_CONTAINER_DLL_insert (chvc_head,
2236 /* finally, check if HELLO was previously validated
2237 (continuation will then schedule actual validation) */
2238 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2242 HELLO_VERIFICATION_TIMEOUT,
2243 &check_hello_validated, chvc);
2249 * The peer specified by the given neighbor has timed-out or a plugin
2250 * has disconnected. We may either need to do nothing (other plugins
2251 * still up), or trigger a full disconnect and clean up. This
2252 * function updates our state and does the necessary notifications.
2253 * Also notifies our clients that the neighbor is now officially
2256 * @param n the neighbor list entry for the peer
2257 * @param check should we just check if all plugins
2258 * disconnected or must we ask all plugins to
2262 disconnect_neighbor (struct NeighborList *current_handle, int check)
2264 struct ReadyList *rpos;
2265 struct NeighborList *npos;
2266 struct NeighborList *nprev;
2267 struct NeighborList *n;
2268 struct MessageQueue *mq;
2269 struct ForeignAddressList *peer_addresses;
2270 struct ForeignAddressList *peer_pos;
2272 if (neighbors == NULL)
2273 return; /* We don't have any neighbors, so client has an already removed handle! */
2276 while ((npos != NULL) && (current_handle != npos))
2280 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2284 if (GNUNET_YES == check)
2287 while (NULL != rpos)
2289 peer_addresses = rpos->addresses;
2290 while (peer_addresses != NULL)
2292 if (GNUNET_YES == peer_addresses->connected)
2293 return; /* still connected */
2294 peer_addresses = peer_addresses->next;
2301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2302 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2304 /* remove n from neighbors list */
2307 while ((npos != NULL) && (npos != n))
2312 GNUNET_assert (npos != NULL);
2314 neighbors = n->next;
2316 nprev->next = n->next;
2318 /* notify all clients about disconnect */
2319 notify_clients_disconnect (&n->id);
2321 /* clean up all plugins, cancel connections and pending transmissions */
2322 while (NULL != (rpos = n->plugins))
2324 n->plugins = rpos->next;
2325 if (GNUNET_YES == rpos->connected)
2326 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2328 while (rpos->addresses != NULL)
2330 peer_pos = rpos->addresses;
2331 rpos->addresses = peer_pos->next;
2332 GNUNET_free(peer_pos);
2337 /* free all messages on the queue */
2338 while (NULL != (mq = n->messages))
2340 n->messages = mq->next;
2341 GNUNET_assert (0 == memcmp(&mq->neighbor_id,
2343 sizeof(struct GNUNET_PeerIdentity)));
2346 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2347 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2348 /* finally, free n itself */
2354 * We have received a PING message from someone. Need to send a PONG message
2355 * in response to the peer by any means necessary.
2357 * FIXME: With something like TCP where a connection exists, we may
2358 * want to send it that way. But the current API does not seem to
2359 * allow us to do so (can't tell this to the transport!)
2362 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2363 const struct GNUNET_PeerIdentity *peer,
2364 const char *sender_address,
2365 size_t sender_address_len)
2367 struct TransportPlugin *plugin = cls;
2368 struct TransportPingMessage *ping;
2369 struct TransportPongMessage *pong;
2371 struct NeighborList *n;
2372 struct ReadyList *rl;
2373 struct ForeignAddressList *fal;
2375 msize = ntohs (message->size);
2376 if (msize < sizeof (struct TransportPingMessage))
2378 GNUNET_break_op (0);
2379 return GNUNET_SYSERR;
2381 ping = (struct TransportPingMessage *) message;
2382 if (0 != memcmp (&ping->target,
2383 plugin->env.my_identity,
2384 sizeof (struct GNUNET_PeerIdentity)))
2386 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2387 _("Received `%s' message not destined for me!\n"),
2389 return GNUNET_SYSERR;
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2393 "Processing `%s' from `%s'\n",
2395 GNUNET_a2s ((const struct sockaddr *)sender_address,
2396 sender_address_len));
2398 msize -= sizeof (struct TransportPingMessage);
2399 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2400 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2401 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2402 pong->purpose.size =
2403 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2405 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2406 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2407 pong->challenge = ping->challenge;
2408 pong->addrlen = htons(sender_address_len);
2409 memcpy(&pong->signer,
2411 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2412 memcpy (&pong[1], sender_address, sender_address_len);
2413 GNUNET_assert (GNUNET_OK ==
2414 GNUNET_CRYPTO_rsa_sign (my_private_key,
2415 &pong->purpose, &pong->signature));
2417 n = find_neighbor(peer);
2419 n = setup_new_neighbor(peer);
2420 /* broadcast 'PONG' to all available addresses */
2424 fal = rl->addresses;
2427 transmit_to_peer(NULL, fal,
2428 TRANSPORT_DEFAULT_PRIORITY,
2430 ntohs(pong->header.size),
2443 * Function called by the plugin for each received message.
2444 * Update data volumes, possibly notify plugins about
2445 * reducing the rate at which they read from the socket
2446 * and generally forward to our receive callback.
2448 * @param cls the "struct TransportPlugin *" we gave to the plugin
2449 * @param message the message, NULL if peer was disconnected
2450 * @param distance the transport cost to this peer (not latency!)
2451 * @param sender_address the address that the sender reported
2452 * (opaque to transport service)
2453 * @param sender_address_len the length of the sender address
2454 * @param peer (claimed) identity of the other peer
2455 * @return the new service_context that the plugin should use
2456 * for future receive calls for messages from this
2461 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2462 const struct GNUNET_MessageHeader *message,
2463 unsigned int distance, const char *sender_address,
2464 size_t sender_address_len)
2466 struct ReadyList *service_context;
2467 struct TransportPlugin *plugin = cls;
2468 struct TransportClient *cpos;
2469 struct InboundMessage *im;
2470 struct ForeignAddressList *peer_address;
2472 struct NeighborList *n;
2474 n = find_neighbor (peer);
2477 if (message == NULL)
2478 return; /* disconnect of peer already marked down */
2479 n = setup_new_neighbor (peer);
2482 service_context = n->plugins;
2483 while ((service_context != NULL) && (plugin != service_context->plugin))
2484 service_context = service_context->next;
2485 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2486 if (message == NULL)
2489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2490 "Receive failed from `%4s', triggering disconnect\n",
2491 GNUNET_i2s (&n->id));
2493 /* TODO: call stats */
2494 if (service_context != NULL)
2495 service_context->connected = GNUNET_NO;
2496 disconnect_neighbor (n, GNUNET_YES);
2499 peer_address = add_peer_address(n,
2502 sender_address_len);
2503 if (service_context != NULL)
2505 if (service_context->connected == GNUNET_NO)
2507 service_context->connected = GNUNET_YES;
2508 /* FIXME: What to do here? Should we use these as well,
2509 to specify some Address in the AddressList should be
2511 peer_address->transmit_ready = GNUNET_YES;
2512 peer_address->connect_attempts++;
2514 peer_address->timeout
2516 GNUNET_TIME_relative_to_absolute
2517 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2519 /* update traffic received amount ... */
2520 msize = ntohs (message->size);
2521 n->last_received += msize;
2522 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2524 GNUNET_TIME_relative_to_absolute
2525 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2527 GNUNET_SCHEDULER_add_delayed (sched,
2528 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2529 &neighbor_timeout_task, n);
2531 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2533 /* dropping message due to frequent inbound volume violations! */
2534 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2535 GNUNET_ERROR_TYPE_BULK,
2537 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2538 /* TODO: call stats */
2541 switch (ntohs (message->type))
2543 case GNUNET_MESSAGE_TYPE_HELLO:
2544 process_hello (plugin, message);
2546 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2547 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2549 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2550 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2555 "Received message of type %u from `%4s', sending to all clients.\n",
2556 ntohs (message->type), GNUNET_i2s (peer));
2558 /* transmit message to all clients */
2559 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2560 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2561 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2562 im->latency = n->latency;
2564 memcpy (&im[1], message, msize);
2567 while (cpos != NULL)
2569 transmit_to_client (cpos, &im->header, GNUNET_YES);
2578 * Handle START-message. This is the first message sent to us
2579 * by any client which causes us to add it to our list.
2581 * @param cls closure (always NULL)
2582 * @param client identification of the client
2583 * @param message the actual message
2586 handle_start (void *cls,
2587 struct GNUNET_SERVER_Client *client,
2588 const struct GNUNET_MessageHeader *message)
2590 struct TransportClient *c;
2591 struct ConnectInfoMessage cim;
2592 struct NeighborList *n;
2593 struct InboundMessage *im;
2594 struct GNUNET_MessageHeader *ack;
2597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2598 "Received `%s' request from client\n", "START");
2603 if (c->client == client)
2605 /* client already on our list! */
2607 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2612 c = GNUNET_malloc (sizeof (struct TransportClient));
2616 if (our_hello != NULL)
2619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2620 "Sending our own `%s' to new client\n", "HELLO");
2622 transmit_to_client (c,
2623 (const struct GNUNET_MessageHeader *) our_hello,
2625 /* tell new client about all existing connections */
2626 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2627 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2629 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2630 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2631 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2632 sizeof (struct GNUNET_MessageHeader));
2633 im->header.size = htons (sizeof (struct InboundMessage) +
2634 sizeof (struct GNUNET_MessageHeader));
2635 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2636 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2637 ack = (struct GNUNET_MessageHeader *) &im[1];
2638 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2639 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2640 for (n = neighbors; n != NULL; n = n->next)
2643 transmit_to_client (c, &cim.header, GNUNET_NO);
2644 if (n->received_pong)
2647 transmit_to_client (c, &im->header, GNUNET_NO);
2654 fprintf(stderr, "Our hello is NULL!\n");
2656 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2661 * Handle HELLO-message.
2663 * @param cls closure (always NULL)
2664 * @param client identification of the client
2665 * @param message the actual message
2668 handle_hello (void *cls,
2669 struct GNUNET_SERVER_Client *client,
2670 const struct GNUNET_MessageHeader *message)
2675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2676 "Received `%s' request from client\n", "HELLO");
2678 ret = process_hello (NULL, message);
2679 GNUNET_SERVER_receive_done (client, ret);
2684 * Handle SEND-message.
2686 * @param cls closure (always NULL)
2687 * @param client identification of the client
2688 * @param message the actual message
2691 handle_send (void *cls,
2692 struct GNUNET_SERVER_Client *client,
2693 const struct GNUNET_MessageHeader *message)
2695 struct TransportClient *tc;
2696 struct NeighborList *n;
2697 const struct OutboundMessage *obm;
2698 const struct GNUNET_MessageHeader *obmm;
2702 size = ntohs (message->size);
2704 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2707 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2710 obm = (const struct OutboundMessage *) message;
2712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2713 "Received `%s' request from client with target `%4s'\n",
2714 "SEND", GNUNET_i2s (&obm->peer));
2716 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2717 msize = ntohs (obmm->size);
2718 if (size != msize + sizeof (struct OutboundMessage))
2721 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2724 n = find_neighbor (&obm->peer);
2726 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2728 while ((tc != NULL) && (tc->client != client))
2732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2733 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2735 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2737 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm,
2738 ntohs (obmm->size), GNUNET_NO, n);
2739 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2744 * Handle SET_QUOTA-message.
2746 * @param cls closure (always NULL)
2747 * @param client identification of the client
2748 * @param message the actual message
2751 handle_set_quota (void *cls,
2752 struct GNUNET_SERVER_Client *client,
2753 const struct GNUNET_MessageHeader *message)
2755 const struct QuotaSetMessage *qsm =
2756 (const struct QuotaSetMessage *) message;
2757 struct NeighborList *n;
2758 struct TransportPlugin *p;
2759 struct ReadyList *rl;
2761 n = find_neighbor (&qsm->peer);
2764 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2770 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2771 "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2775 if (n->quota_in < ntohl (qsm->quota_in))
2776 n->last_quota_update = GNUNET_TIME_absolute_get ();
2777 n->quota_in = ntohl (qsm->quota_in);
2782 p->api->set_receive_quota (p->api->cls,
2783 &qsm->peer, ntohl (qsm->quota_in));
2786 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2791 * Handle TRY_CONNECT-message.
2793 * @param cls closure (always NULL)
2794 * @param client identification of the client
2795 * @param message the actual message
2798 handle_try_connect (void *cls,
2799 struct GNUNET_SERVER_Client *client,
2800 const struct GNUNET_MessageHeader *message)
2802 const struct TryConnectMessage *tcm;
2803 struct NeighborList *neighbor;
2804 tcm = (const struct TryConnectMessage *) message;
2806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2807 "Received `%s' request from client %p asking to connect to `%4s'\n",
2808 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2810 neighbor = find_neighbor(&tcm->peer);
2811 if (neighbor == NULL)
2812 setup_new_neighbor (&tcm->peer);
2813 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2818 transmit_address_to_client (void *cls, const char *address)
2820 struct GNUNET_SERVER_TransmitContext *tc = cls;
2823 if (NULL == address)
2826 slen = strlen (address) + 1;
2827 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2828 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2829 if (NULL == address)
2830 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2835 * Handle AddressLookup-message.
2837 * @param cls closure (always NULL)
2838 * @param client identification of the client
2839 * @param message the actual message
2842 handle_address_lookup (void *cls,
2843 struct GNUNET_SERVER_Client *client,
2844 const struct GNUNET_MessageHeader *message)
2846 const struct AddressLookupMessage *alum;
2847 struct TransportPlugin *lsPlugin;
2848 const char *nameTransport;
2849 const char *address;
2851 struct GNUNET_SERVER_TransmitContext *tc;
2853 size = ntohs (message->size);
2854 if (size < sizeof (struct AddressLookupMessage))
2856 GNUNET_break_op (0);
2857 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2860 alum = (const struct AddressLookupMessage *) message;
2861 uint32_t addressLen = ntohl (alum->addrlen);
2862 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2864 GNUNET_break_op (0);
2865 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2868 address = (const char *) &alum[1];
2869 nameTransport = (const char *) &address[addressLen];
2871 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2873 GNUNET_break_op (0);
2874 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2877 struct GNUNET_TIME_Absolute timeout =
2878 GNUNET_TIME_absolute_ntoh (alum->timeout);
2879 struct GNUNET_TIME_Relative rtimeout =
2880 GNUNET_TIME_absolute_get_remaining (timeout);
2881 lsPlugin = find_transport (nameTransport);
2882 if (NULL == lsPlugin)
2884 tc = GNUNET_SERVER_transmit_context_create (client);
2885 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2886 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2887 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2890 tc = GNUNET_SERVER_transmit_context_create (client);
2891 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2892 address, addressLen, GNUNET_YES,
2894 &transmit_address_to_client, tc);
2898 * List of handlers for the messages understood by this
2901 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2902 {&handle_start, NULL,
2903 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2904 {&handle_hello, NULL,
2905 GNUNET_MESSAGE_TYPE_HELLO, 0},
2906 {&handle_send, NULL,
2907 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2908 {&handle_set_quota, NULL,
2909 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2910 {&handle_try_connect, NULL,
2911 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2912 sizeof (struct TryConnectMessage)},
2913 {&handle_address_lookup, NULL,
2914 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2921 * Setup the environment for this plugin.
2924 create_environment (struct TransportPlugin *plug)
2926 plug->env.cfg = cfg;
2927 plug->env.sched = sched;
2928 plug->env.my_identity = &my_identity;
2929 plug->env.cls = plug;
2930 plug->env.receive = &plugin_env_receive;
2931 plug->env.notify_address = &plugin_env_notify_address;
2932 plug->env.default_quota_in =
2933 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2934 plug->env.max_connections = max_connect_per_transport;
2939 * Start the specified transport (load the plugin).
2942 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2944 struct TransportPlugin *plug;
2947 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2948 _("Loading `%s' transport plugin\n"), name);
2949 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2950 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2951 create_environment (plug);
2952 plug->short_name = GNUNET_strdup (name);
2953 plug->lib_name = libname;
2954 plug->next = plugins;
2956 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2957 if (plug->api == NULL)
2959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2960 _("Failed to load transport plugin for `%s'\n"), name);
2961 GNUNET_free (plug->short_name);
2962 plugins = plug->next;
2963 GNUNET_free (libname);
2970 * Called whenever a client is disconnected. Frees our
2971 * resources associated with that client.
2973 * @param cls closure
2974 * @param client identification of the client
2977 client_disconnect_notification (void *cls,
2978 struct GNUNET_SERVER_Client *client)
2980 struct TransportClient *pos;
2981 struct TransportClient *prev;
2982 struct ClientMessageQueueEntry *mqe;
2987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2988 "Client disconnected, cleaning up.\n");
2992 while ((pos != NULL) && (pos->client != client))
2999 while (NULL != (mqe = pos->message_queue_head))
3001 pos->message_queue_head = mqe->next;
3004 pos->message_queue_head = NULL;
3006 clients = pos->next;
3008 prev->next = pos->next;
3009 if (GNUNET_YES == pos->tcs_pending)
3019 * Iterator to free entries in the validation_map.
3021 * @param cls closure (unused)
3022 * @param key current key code
3023 * @param value value in the hash map (validation to abort)
3024 * @return GNUNET_YES (always)
3027 abort_validation (void *cls,
3028 const GNUNET_HashCode * key,
3031 struct ValidationEntry *va = value;
3033 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3034 GNUNET_free (va->transport_name);
3041 * Function called when the service shuts down. Unloads our plugins
3042 * and cancels pending validations.
3044 * @param cls closure, unused
3045 * @param tc task context (unused)
3048 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3050 struct TransportPlugin *plug;
3051 struct OwnAddressList *al;
3052 struct CheckHelloValidatedContext *chvc;
3055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056 "Transport service is unloading plugins...\n");
3058 while (NULL != (plug = plugins))
3060 plugins = plug->next;
3061 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3062 GNUNET_free (plug->lib_name);
3063 GNUNET_free (plug->short_name);
3064 while (NULL != (al = plug->addresses))
3066 plug->addresses = al->next;
3071 if (my_private_key != NULL)
3072 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3073 GNUNET_free_non_null (our_hello);
3075 /* free 'chvc' data structure */
3076 while (NULL != (chvc = chvc_head))
3078 chvc_head = chvc->next;
3079 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3084 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3087 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3092 * Initiate transport service.
3094 * @param cls closure
3095 * @param s scheduler to use
3096 * @param serv the initialized server
3097 * @param c configuration to use
3101 struct GNUNET_SCHEDULER_Handle *s,
3102 struct GNUNET_SERVER_Handle *serv,
3103 const struct GNUNET_CONFIGURATION_Handle *c)
3108 unsigned long long tneigh;
3113 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3114 /* parse configuration */
3116 GNUNET_CONFIGURATION_get_value_number (c,
3121 GNUNET_CONFIGURATION_get_value_filename (c,
3123 "HOSTKEY", &keyfile)))
3125 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3127 ("Transport service is lacking key configuration settings. Exiting.\n"));
3128 GNUNET_SCHEDULER_shutdown (s);
3131 max_connect_per_transport = (uint32_t) tneigh;
3132 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3133 GNUNET_free (keyfile);
3134 if (my_private_key == NULL)
3136 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3138 ("Transport service could not access hostkey. Exiting.\n"));
3139 GNUNET_SCHEDULER_shutdown (s);
3142 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3143 GNUNET_CRYPTO_hash (&my_public_key,
3144 sizeof (my_public_key), &my_identity.hashPubKey);
3145 /* setup notification */
3147 GNUNET_SERVER_disconnect_notify (server,
3148 &client_disconnect_notification, NULL);
3149 /* load plugins... */
3152 GNUNET_CONFIGURATION_get_value_string (c,
3153 "TRANSPORT", "PLUGINS", &plugs))
3155 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3156 _("Starting transport plugins `%s'\n"), plugs);
3157 pos = strtok (plugs, " ");
3160 start_transport (server, pos);
3162 pos = strtok (NULL, " ");
3164 GNUNET_free (plugs);
3166 GNUNET_SCHEDULER_add_delayed (sched,
3167 GNUNET_TIME_UNIT_FOREVER_REL,
3168 &shutdown_task, NULL);
3173 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3175 /* process client requests */
3176 GNUNET_SERVER_add_handlers (server, handlers);
3181 * The main function for the transport service.
3183 * @param argc number of arguments from the command line
3184 * @param argv command line arguments
3185 * @return 0 ok, 1 on error
3188 main (int argc, char *const *argv)
3190 return (GNUNET_OK ==
3191 GNUNET_SERVICE_run (argc,
3194 GNUNET_SERVICE_OPTION_NONE,
3195 &run, NULL)) ? 0 : 1;
3198 /* end of gnunet-service-transport.c */