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)
1767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1768 "Receiving `%s' message from `%4s'.\n", "PONG",
1771 if (GNUNET_SYSERR !=
1772 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1774 &check_pending_validation,
1777 /* This is *expected* to happen a lot since we send
1778 PONGs to *all* known addresses of the sender of
1779 the PING, so most likely we get multiple PONGs
1780 per PING, and all but the first PONG will end up
1781 here. So really we should not print anything here
1782 unless we want to be very, very verbose... */
1783 #if DEBUG_TRANSPORT > 1
1784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
1793 /* FIXME: add given address to potential pool of our addresses
1795 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1796 _("Another peer saw us using the address `%s' via `%s'.\n"),
1797 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1798 ntohs(pong->addrlen)),
1799 va->transport_name);
1805 neighbor_timeout_task (void *cls,
1806 const struct GNUNET_SCHEDULER_TaskContext *tc)
1808 struct NeighborList *n = cls;
1811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1812 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1814 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1815 disconnect_neighbor (n, GNUNET_NO);
1820 * Create a fresh entry in our neighbor list for the given peer.
1821 * Will try to transmit our current HELLO to the new neighbor. Also
1822 * notifies our clients about the new "connection".
1824 * @param peer the peer for which we create the entry
1825 * @return the new neighbor list entry
1827 static struct NeighborList *
1828 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1830 struct NeighborList *n;
1831 struct TransportPlugin *tp;
1832 struct ReadyList *rl;
1834 GNUNET_assert (our_hello != NULL);
1835 n = GNUNET_malloc (sizeof (struct NeighborList));
1836 n->next = neighbors;
1839 n->last_quota_update = GNUNET_TIME_absolute_get ();
1841 GNUNET_TIME_relative_to_absolute
1842 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1843 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1847 if (tp->api->send != NULL)
1849 rl = GNUNET_malloc (sizeof (struct ReadyList));
1850 rl->next = n->plugins;
1853 rl->addresses = NULL;
1857 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1858 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1859 &neighbor_timeout_task, n);
1860 transmit_to_peer (NULL, NULL, 0,
1861 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1863 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1869 * Closure for 'check_address_exists'.
1871 struct CheckAddressExistsClosure
1874 * Address to check for.
1879 * Name of the transport.
1889 * Set to GNUNET_YES if the address exists.
1896 * Iterator over hash map entries. Checks if the given
1897 * validation entry is for the same address as what is given
1900 * @param cls the 'struct CheckAddressExistsClosure*'
1901 * @param key current key code (ignored)
1902 * @param value value in the hash map ('struct ValidationEntry')
1903 * @return GNUNET_YES if we should continue to
1904 * iterate (mismatch), GNUNET_NO if not (entry matched)
1907 check_address_exists (void *cls,
1908 const GNUNET_HashCode * key,
1911 struct CheckAddressExistsClosure *caec = cls;
1912 struct ValidationEntry *ve = value;
1913 if ( (0 == strcmp (caec->tname,
1914 ve->transport_name)) &&
1915 (caec->addrlen == ve->addrlen) &&
1916 (0 == memcmp (caec->addr,
1920 caec->exists = GNUNET_YES;
1928 * HELLO validation cleanup task (validation failed).
1930 * @param cls the 'struct ValidationEntry' that failed
1931 * @param tc scheduler context (unused)
1934 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1936 struct ValidationEntry *va = cls;
1937 struct GNUNET_PeerIdentity pid;
1939 GNUNET_CRYPTO_hash (&va->publicKey,
1941 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1943 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1946 GNUNET_free (va->transport_name);
1952 * Check if the given address is already being validated; if not,
1953 * append the given address to the list of entries that are being be
1954 * validated and initiate validation.
1956 * @param cls closure ('struct CheckHelloValidatedContext *')
1957 * @param tname name of the transport
1958 * @param expiration expiration time
1959 * @param addr the address
1960 * @param addrlen length of the address
1961 * @return GNUNET_OK (always)
1964 run_validation (void *cls,
1966 struct GNUNET_TIME_Absolute expiration,
1967 const void *addr, size_t addrlen)
1969 struct CheckHelloValidatedContext *chvc = cls;
1970 struct GNUNET_PeerIdentity id;
1971 struct TransportPlugin *tp;
1972 struct ValidationEntry *va;
1973 struct NeighborList *neighbor;
1974 struct ForeignAddressList *peer_address;
1975 struct TransportPingMessage ping;
1976 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
1977 struct CheckAddressExistsClosure caec;
1979 uint16_t hello_size;
1982 tp = find_transport (tname);
1985 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1986 GNUNET_ERROR_TYPE_BULK,
1988 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1992 GNUNET_HELLO_get_key (chvc->hello, &pk);
1993 GNUNET_CRYPTO_hash (&pk,
1995 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1998 caec.addrlen = addrlen;
2000 caec.exists = GNUNET_NO;
2001 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2002 &check_address_exists,
2004 if (caec.exists == GNUNET_YES)
2006 /* During validation attempts we will likely trigger the other
2007 peer trying to validate our address which in turn will cause
2008 it to send us its HELLO, so we expect to hit this case rather
2009 frequently. Only print something if we are very verbose. */
2010 #if DEBUG_TRANSPORT > 1
2011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2012 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2013 GNUNET_a2s (addr, addrlen),
2019 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2020 va->transport_name = GNUNET_strdup (tname);
2021 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2023 va->send_time = GNUNET_TIME_absolute_get();
2024 va->addr = (const void*) &va[1];
2025 memcpy (&va[1], addr, addrlen);
2026 va->addrlen = addrlen;
2027 GNUNET_HELLO_get_key (chvc->hello,
2029 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2030 HELLO_VERIFICATION_TIMEOUT,
2031 &timeout_hello_validation,
2033 GNUNET_CONTAINER_multihashmap_put (validation_map,
2036 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2037 neighbor = find_neighbor(&id);
2038 if (neighbor == NULL)
2039 neighbor = setup_new_neighbor(&id);
2040 peer_address = add_peer_address(neighbor, tname, addr, addrlen);
2041 GNUNET_assert(peer_address != NULL);
2042 hello_size = GNUNET_HELLO_size(our_hello);
2043 tsize = sizeof(struct TransportPingMessage) + hello_size;
2044 message_buf = GNUNET_malloc(tsize);
2045 ping.challenge = htonl(va->challenge);
2046 ping.header.size = htons(sizeof(struct TransportPingMessage));
2047 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2048 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2049 memcpy(message_buf, our_hello, hello_size);
2050 memcpy(&message_buf[hello_size],
2052 sizeof(struct TransportPingMessage));
2054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2055 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2056 GNUNET_a2s (addr, addrlen),
2059 "HELLO", hello_size,
2060 "PING", sizeof (struct TransportPingMessage));
2062 transmit_to_peer(NULL, peer_address,
2063 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2065 GNUNET_YES, neighbor);
2066 GNUNET_free(message_buf);
2072 * Add the given address to the list of foreign addresses
2073 * available for the given peer (check for duplicates).
2075 * @param cls the respective 'struct NeighborList' to update
2076 * @param tname name of the transport
2077 * @param expiration expiration time
2078 * @param addr the address
2079 * @param addrlen length of the address
2080 * @return GNUNET_OK (always)
2083 add_to_foreign_address_list (void *cls,
2085 struct GNUNET_TIME_Absolute expiration,
2086 const void *addr, size_t addrlen)
2088 struct NeighborList *n = cls;
2089 struct ForeignAddressList *fal;
2091 fal = find_peer_address (n, tname, addr, addrlen);
2095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2096 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data.\n",
2097 GNUNET_a2s (addr, addrlen),
2099 GNUNET_i2s (&n->id));
2101 fal = add_peer_address (n, tname, addr, addrlen);
2103 fal->expires = GNUNET_TIME_absolute_max (expiration,
2105 fal->validated = GNUNET_YES;
2111 * Check if addresses in validated hello "h" overlap with
2112 * those in "chvc->hello" and validate the rest.
2114 * @param cls closure
2115 * @param peer id of the peer, NULL for last call
2116 * @param hello hello message for the peer (can be NULL)
2117 * @param trust amount of trust we have in the peer (not used)
2120 check_hello_validated (void *cls,
2121 const struct GNUNET_PeerIdentity *peer,
2122 const struct GNUNET_HELLO_Message *h,
2125 struct CheckHelloValidatedContext *chvc = cls;
2126 struct GNUNET_HELLO_Message *plain_hello;
2127 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2128 struct GNUNET_PeerIdentity target;
2129 struct NeighborList *n;
2134 GNUNET_CONTAINER_DLL_remove (chvc_head,
2137 if (GNUNET_NO == chvc->hello_known)
2139 /* notify PEERINFO about the peer now, so that we at least
2140 have the public key if some other component needs it */
2141 GNUNET_HELLO_get_key (chvc->hello, &pk);
2142 GNUNET_CRYPTO_hash (&pk,
2143 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2144 &target.hashPubKey);
2145 plain_hello = GNUNET_HELLO_create (&pk,
2148 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2149 GNUNET_free (plain_hello);
2151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2152 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2154 GNUNET_i2s (&target));
2156 GNUNET_HELLO_iterate_addresses (chvc->hello,
2166 chvc->hello_known = GNUNET_YES;
2167 n = find_neighbor (peer);
2169 GNUNET_HELLO_iterate_addresses (h,
2171 &add_to_foreign_address_list,
2173 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2175 GNUNET_TIME_absolute_get (),
2181 * Process HELLO-message.
2183 * @param plugin transport involved, may be NULL
2184 * @param message the actual message
2185 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2188 process_hello (struct TransportPlugin *plugin,
2189 const struct GNUNET_MessageHeader *message)
2192 struct GNUNET_PeerIdentity target;
2193 const struct GNUNET_HELLO_Message *hello;
2194 struct CheckHelloValidatedContext *chvc;
2195 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2197 hsize = ntohs (message->size);
2198 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2199 (hsize < sizeof (struct GNUNET_MessageHeader)))
2202 return GNUNET_SYSERR;
2204 /* first, check if load is too high */
2205 if (GNUNET_SCHEDULER_get_load (sched,
2206 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2208 /* TODO: call to stats? */
2211 hello = (const struct GNUNET_HELLO_Message *) message;
2212 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2214 GNUNET_break_op (0);
2215 return GNUNET_SYSERR;
2217 GNUNET_CRYPTO_hash (&publicKey,
2218 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2219 &target.hashPubKey);
2221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2222 "Processing `%s' message for `%4s' of size %u\n",
2224 GNUNET_i2s (&target),
2225 GNUNET_HELLO_size(hello));
2228 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2229 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2230 memcpy (&chvc[1], hello, hsize);
2231 GNUNET_CONTAINER_DLL_insert (chvc_head,
2234 /* finally, check if HELLO was previously validated
2235 (continuation will then schedule actual validation) */
2236 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2240 HELLO_VERIFICATION_TIMEOUT,
2241 &check_hello_validated, chvc);
2247 * The peer specified by the given neighbor has timed-out or a plugin
2248 * has disconnected. We may either need to do nothing (other plugins
2249 * still up), or trigger a full disconnect and clean up. This
2250 * function updates our state and does the necessary notifications.
2251 * Also notifies our clients that the neighbor is now officially
2254 * @param n the neighbor list entry for the peer
2255 * @param check should we just check if all plugins
2256 * disconnected or must we ask all plugins to
2260 disconnect_neighbor (struct NeighborList *current_handle, int check)
2262 struct ReadyList *rpos;
2263 struct NeighborList *npos;
2264 struct NeighborList *nprev;
2265 struct NeighborList *n;
2266 struct MessageQueue *mq;
2267 struct ForeignAddressList *peer_addresses;
2268 struct ForeignAddressList *peer_pos;
2270 if (neighbors == NULL)
2271 return; /* We don't have any neighbors, so client has an already removed handle! */
2274 while ((npos != NULL) && (current_handle != npos))
2278 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2282 if (GNUNET_YES == check)
2285 while (NULL != rpos)
2287 peer_addresses = rpos->addresses;
2288 while (peer_addresses != NULL)
2290 if (GNUNET_YES == peer_addresses->connected)
2291 return; /* still connected */
2292 peer_addresses = peer_addresses->next;
2299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2300 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2302 /* remove n from neighbors list */
2305 while ((npos != NULL) && (npos != n))
2310 GNUNET_assert (npos != NULL);
2312 neighbors = n->next;
2314 nprev->next = n->next;
2316 /* notify all clients about disconnect */
2317 notify_clients_disconnect (&n->id);
2319 /* clean up all plugins, cancel connections and pending transmissions */
2320 while (NULL != (rpos = n->plugins))
2322 n->plugins = rpos->next;
2323 if (GNUNET_YES == rpos->connected)
2324 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2326 while (rpos->addresses != NULL)
2328 peer_pos = rpos->addresses;
2329 rpos->addresses = peer_pos->next;
2330 GNUNET_free(peer_pos);
2335 /* free all messages on the queue */
2336 while (NULL != (mq = n->messages))
2338 n->messages = mq->next;
2339 GNUNET_assert (0 == memcmp(&mq->neighbor_id,
2341 sizeof(struct GNUNET_PeerIdentity)));
2344 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2345 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2346 /* finally, free n itself */
2352 * We have received a PING message from someone. Need to send a PONG message
2353 * in response to the peer by any means necessary.
2355 * FIXME: With something like TCP where a connection exists, we may
2356 * want to send it that way. But the current API does not seem to
2357 * allow us to do so (can't tell this to the transport!)
2360 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2361 const struct GNUNET_PeerIdentity *peer,
2362 const char *sender_address,
2363 size_t sender_address_len)
2365 struct TransportPlugin *plugin = cls;
2366 struct TransportPingMessage *ping;
2367 struct TransportPongMessage *pong;
2369 struct NeighborList *n;
2370 struct ReadyList *rl;
2371 struct ForeignAddressList *fal;
2373 msize = ntohs (message->size);
2374 if (msize < sizeof (struct TransportPingMessage))
2376 GNUNET_break_op (0);
2377 return GNUNET_SYSERR;
2379 ping = (struct TransportPingMessage *) message;
2380 if (0 != memcmp (&ping->target,
2381 plugin->env.my_identity,
2382 sizeof (struct GNUNET_PeerIdentity)))
2384 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2385 _("Received `%s' message not destined for me!\n"),
2387 return GNUNET_SYSERR;
2390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2391 "Processing `%s' from `%s'\n",
2393 GNUNET_a2s ((const struct sockaddr *)sender_address,
2394 sender_address_len));
2396 msize -= sizeof (struct TransportPingMessage);
2397 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2398 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2399 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2400 pong->purpose.size =
2401 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2403 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2404 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2405 pong->challenge = ping->challenge;
2406 pong->addrlen = htons(sender_address_len);
2407 memcpy(&pong->signer,
2409 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2410 memcpy (&pong[1], sender_address, sender_address_len);
2411 GNUNET_assert (GNUNET_OK ==
2412 GNUNET_CRYPTO_rsa_sign (my_private_key,
2413 &pong->purpose, &pong->signature));
2415 n = find_neighbor(peer);
2417 n = setup_new_neighbor(peer);
2418 /* broadcast 'PONG' to all available addresses */
2422 fal = rl->addresses;
2425 transmit_to_peer(NULL, fal,
2426 TRANSPORT_DEFAULT_PRIORITY,
2428 ntohs(pong->header.size),
2441 * Function called by the plugin for each received message.
2442 * Update data volumes, possibly notify plugins about
2443 * reducing the rate at which they read from the socket
2444 * and generally forward to our receive callback.
2446 * @param cls the "struct TransportPlugin *" we gave to the plugin
2447 * @param message the message, NULL if peer was disconnected
2448 * @param distance the transport cost to this peer (not latency!)
2449 * @param sender_address the address that the sender reported
2450 * (opaque to transport service)
2451 * @param sender_address_len the length of the sender address
2452 * @param peer (claimed) identity of the other peer
2453 * @return the new service_context that the plugin should use
2454 * for future receive calls for messages from this
2459 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2460 const struct GNUNET_MessageHeader *message,
2461 unsigned int distance, const char *sender_address,
2462 size_t sender_address_len)
2464 struct ReadyList *service_context;
2465 struct TransportPlugin *plugin = cls;
2466 struct TransportClient *cpos;
2467 struct InboundMessage *im;
2468 struct ForeignAddressList *peer_address;
2470 struct NeighborList *n;
2472 n = find_neighbor (peer);
2475 if (message == NULL)
2476 return; /* disconnect of peer already marked down */
2477 n = setup_new_neighbor (peer);
2480 service_context = n->plugins;
2481 while ((service_context != NULL) && (plugin != service_context->plugin))
2482 service_context = service_context->next;
2483 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2484 if (message == NULL)
2487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2488 "Receive failed from `%4s', triggering disconnect\n",
2489 GNUNET_i2s (&n->id));
2491 /* TODO: call stats */
2492 if (service_context != NULL)
2493 service_context->connected = GNUNET_NO;
2494 disconnect_neighbor (n, GNUNET_YES);
2497 peer_address = add_peer_address(n,
2500 sender_address_len);
2501 if (service_context != NULL)
2503 if (service_context->connected == GNUNET_NO)
2505 service_context->connected = GNUNET_YES;
2506 /* FIXME: What to do here? Should we use these as well,
2507 to specify some Address in the AddressList should be
2509 peer_address->transmit_ready = GNUNET_YES;
2510 peer_address->connect_attempts++;
2512 peer_address->timeout
2514 GNUNET_TIME_relative_to_absolute
2515 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2517 /* update traffic received amount ... */
2518 msize = ntohs (message->size);
2519 n->last_received += msize;
2520 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2522 GNUNET_TIME_relative_to_absolute
2523 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2525 GNUNET_SCHEDULER_add_delayed (sched,
2526 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2527 &neighbor_timeout_task, n);
2529 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2531 /* dropping message due to frequent inbound volume violations! */
2532 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2533 GNUNET_ERROR_TYPE_BULK,
2535 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2536 /* TODO: call stats */
2539 switch (ntohs (message->type))
2541 case GNUNET_MESSAGE_TYPE_HELLO:
2542 process_hello (plugin, message);
2544 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2545 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2547 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2548 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2553 "Received message of type %u from `%4s', sending to all clients.\n",
2554 ntohs (message->type), GNUNET_i2s (peer));
2556 /* transmit message to all clients */
2557 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2558 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2559 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2560 im->latency = n->latency;
2562 memcpy (&im[1], message, msize);
2565 while (cpos != NULL)
2567 transmit_to_client (cpos, &im->header, GNUNET_YES);
2576 * Handle START-message. This is the first message sent to us
2577 * by any client which causes us to add it to our list.
2579 * @param cls closure (always NULL)
2580 * @param client identification of the client
2581 * @param message the actual message
2584 handle_start (void *cls,
2585 struct GNUNET_SERVER_Client *client,
2586 const struct GNUNET_MessageHeader *message)
2588 struct TransportClient *c;
2589 struct ConnectInfoMessage cim;
2590 struct NeighborList *n;
2591 struct InboundMessage *im;
2592 struct GNUNET_MessageHeader *ack;
2595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2596 "Received `%s' request from client\n", "START");
2601 if (c->client == client)
2603 /* client already on our list! */
2605 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2610 c = GNUNET_malloc (sizeof (struct TransportClient));
2614 if (our_hello != NULL)
2617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2618 "Sending our own `%s' to new client\n", "HELLO");
2620 transmit_to_client (c,
2621 (const struct GNUNET_MessageHeader *) our_hello,
2623 /* tell new client about all existing connections */
2624 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2625 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2627 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2628 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2629 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2630 sizeof (struct GNUNET_MessageHeader));
2631 im->header.size = htons (sizeof (struct InboundMessage) +
2632 sizeof (struct GNUNET_MessageHeader));
2633 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2634 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2635 ack = (struct GNUNET_MessageHeader *) &im[1];
2636 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2637 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2638 for (n = neighbors; n != NULL; n = n->next)
2641 transmit_to_client (c, &cim.header, GNUNET_NO);
2642 if (n->received_pong)
2645 transmit_to_client (c, &im->header, GNUNET_NO);
2652 fprintf(stderr, "Our hello is NULL!\n");
2654 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2659 * Handle HELLO-message.
2661 * @param cls closure (always NULL)
2662 * @param client identification of the client
2663 * @param message the actual message
2666 handle_hello (void *cls,
2667 struct GNUNET_SERVER_Client *client,
2668 const struct GNUNET_MessageHeader *message)
2673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2674 "Received `%s' request from client\n", "HELLO");
2676 ret = process_hello (NULL, message);
2677 GNUNET_SERVER_receive_done (client, ret);
2682 * Handle SEND-message.
2684 * @param cls closure (always NULL)
2685 * @param client identification of the client
2686 * @param message the actual message
2689 handle_send (void *cls,
2690 struct GNUNET_SERVER_Client *client,
2691 const struct GNUNET_MessageHeader *message)
2693 struct TransportClient *tc;
2694 struct NeighborList *n;
2695 const struct OutboundMessage *obm;
2696 const struct GNUNET_MessageHeader *obmm;
2700 size = ntohs (message->size);
2702 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2705 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2708 obm = (const struct OutboundMessage *) message;
2710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2711 "Received `%s' request from client with target `%4s'\n",
2712 "SEND", GNUNET_i2s (&obm->peer));
2714 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2715 msize = ntohs (obmm->size);
2716 if (size != msize + sizeof (struct OutboundMessage))
2719 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2722 n = find_neighbor (&obm->peer);
2724 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2726 while ((tc != NULL) && (tc->client != client))
2730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2731 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2733 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2735 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm,
2736 ntohs (obmm->size), GNUNET_NO, n);
2737 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2742 * Handle SET_QUOTA-message.
2744 * @param cls closure (always NULL)
2745 * @param client identification of the client
2746 * @param message the actual message
2749 handle_set_quota (void *cls,
2750 struct GNUNET_SERVER_Client *client,
2751 const struct GNUNET_MessageHeader *message)
2753 const struct QuotaSetMessage *qsm =
2754 (const struct QuotaSetMessage *) message;
2755 struct NeighborList *n;
2756 struct TransportPlugin *p;
2757 struct ReadyList *rl;
2759 n = find_neighbor (&qsm->peer);
2762 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2768 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2769 "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2773 if (n->quota_in < ntohl (qsm->quota_in))
2774 n->last_quota_update = GNUNET_TIME_absolute_get ();
2775 n->quota_in = ntohl (qsm->quota_in);
2780 p->api->set_receive_quota (p->api->cls,
2781 &qsm->peer, ntohl (qsm->quota_in));
2784 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2789 * Handle TRY_CONNECT-message.
2791 * @param cls closure (always NULL)
2792 * @param client identification of the client
2793 * @param message the actual message
2796 handle_try_connect (void *cls,
2797 struct GNUNET_SERVER_Client *client,
2798 const struct GNUNET_MessageHeader *message)
2800 const struct TryConnectMessage *tcm;
2801 struct NeighborList *neighbor;
2802 tcm = (const struct TryConnectMessage *) message;
2804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2805 "Received `%s' request from client %p asking to connect to `%4s'\n",
2806 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2808 neighbor = find_neighbor(&tcm->peer);
2809 if (neighbor == NULL)
2810 setup_new_neighbor (&tcm->peer);
2811 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2816 transmit_address_to_client (void *cls, const char *address)
2818 struct GNUNET_SERVER_TransmitContext *tc = cls;
2821 if (NULL == address)
2824 slen = strlen (address) + 1;
2825 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2826 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2827 if (NULL == address)
2828 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2833 * Handle AddressLookup-message.
2835 * @param cls closure (always NULL)
2836 * @param client identification of the client
2837 * @param message the actual message
2840 handle_address_lookup (void *cls,
2841 struct GNUNET_SERVER_Client *client,
2842 const struct GNUNET_MessageHeader *message)
2844 const struct AddressLookupMessage *alum;
2845 struct TransportPlugin *lsPlugin;
2846 const char *nameTransport;
2847 const char *address;
2849 struct GNUNET_SERVER_TransmitContext *tc;
2851 size = ntohs (message->size);
2852 if (size < sizeof (struct AddressLookupMessage))
2854 GNUNET_break_op (0);
2855 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2858 alum = (const struct AddressLookupMessage *) message;
2859 uint32_t addressLen = ntohl (alum->addrlen);
2860 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2862 GNUNET_break_op (0);
2863 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2866 address = (const char *) &alum[1];
2867 nameTransport = (const char *) &address[addressLen];
2869 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2871 GNUNET_break_op (0);
2872 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2875 struct GNUNET_TIME_Absolute timeout =
2876 GNUNET_TIME_absolute_ntoh (alum->timeout);
2877 struct GNUNET_TIME_Relative rtimeout =
2878 GNUNET_TIME_absolute_get_remaining (timeout);
2879 lsPlugin = find_transport (nameTransport);
2880 if (NULL == lsPlugin)
2882 tc = GNUNET_SERVER_transmit_context_create (client);
2883 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2884 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2885 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2888 tc = GNUNET_SERVER_transmit_context_create (client);
2889 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2890 address, addressLen, GNUNET_YES,
2892 &transmit_address_to_client, tc);
2896 * List of handlers for the messages understood by this
2899 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2900 {&handle_start, NULL,
2901 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2902 {&handle_hello, NULL,
2903 GNUNET_MESSAGE_TYPE_HELLO, 0},
2904 {&handle_send, NULL,
2905 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2906 {&handle_set_quota, NULL,
2907 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2908 {&handle_try_connect, NULL,
2909 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2910 sizeof (struct TryConnectMessage)},
2911 {&handle_address_lookup, NULL,
2912 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2919 * Setup the environment for this plugin.
2922 create_environment (struct TransportPlugin *plug)
2924 plug->env.cfg = cfg;
2925 plug->env.sched = sched;
2926 plug->env.my_identity = &my_identity;
2927 plug->env.cls = plug;
2928 plug->env.receive = &plugin_env_receive;
2929 plug->env.notify_address = &plugin_env_notify_address;
2930 plug->env.default_quota_in =
2931 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2932 plug->env.max_connections = max_connect_per_transport;
2937 * Start the specified transport (load the plugin).
2940 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2942 struct TransportPlugin *plug;
2945 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2946 _("Loading `%s' transport plugin\n"), name);
2947 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2948 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2949 create_environment (plug);
2950 plug->short_name = GNUNET_strdup (name);
2951 plug->lib_name = libname;
2952 plug->next = plugins;
2954 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2955 if (plug->api == NULL)
2957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2958 _("Failed to load transport plugin for `%s'\n"), name);
2959 GNUNET_free (plug->short_name);
2960 plugins = plug->next;
2961 GNUNET_free (libname);
2968 * Called whenever a client is disconnected. Frees our
2969 * resources associated with that client.
2971 * @param cls closure
2972 * @param client identification of the client
2975 client_disconnect_notification (void *cls,
2976 struct GNUNET_SERVER_Client *client)
2978 struct TransportClient *pos;
2979 struct TransportClient *prev;
2980 struct ClientMessageQueueEntry *mqe;
2985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2986 "Client disconnected, cleaning up.\n");
2990 while ((pos != NULL) && (pos->client != client))
2997 while (NULL != (mqe = pos->message_queue_head))
2999 pos->message_queue_head = mqe->next;
3002 pos->message_queue_head = NULL;
3004 clients = pos->next;
3006 prev->next = pos->next;
3007 if (GNUNET_YES == pos->tcs_pending)
3017 * Iterator to free entries in the validation_map.
3019 * @param cls closure (unused)
3020 * @param key current key code
3021 * @param value value in the hash map (validation to abort)
3022 * @return GNUNET_YES (always)
3025 abort_validation (void *cls,
3026 const GNUNET_HashCode * key,
3029 struct ValidationEntry *va = value;
3031 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3032 GNUNET_free (va->transport_name);
3039 * Function called when the service shuts down. Unloads our plugins
3040 * and cancels pending validations.
3042 * @param cls closure, unused
3043 * @param tc task context (unused)
3046 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3048 struct TransportPlugin *plug;
3049 struct OwnAddressList *al;
3050 struct CheckHelloValidatedContext *chvc;
3053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054 "Transport service is unloading plugins...\n");
3056 while (NULL != (plug = plugins))
3058 plugins = plug->next;
3059 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3060 GNUNET_free (plug->lib_name);
3061 GNUNET_free (plug->short_name);
3062 while (NULL != (al = plug->addresses))
3064 plug->addresses = al->next;
3069 if (my_private_key != NULL)
3070 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3071 GNUNET_free_non_null (our_hello);
3073 /* free 'chvc' data structure */
3074 while (NULL != (chvc = chvc_head))
3076 chvc_head = chvc->next;
3077 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3082 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3085 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3090 * Initiate transport service.
3092 * @param cls closure
3093 * @param s scheduler to use
3094 * @param serv the initialized server
3095 * @param c configuration to use
3099 struct GNUNET_SCHEDULER_Handle *s,
3100 struct GNUNET_SERVER_Handle *serv,
3101 const struct GNUNET_CONFIGURATION_Handle *c)
3106 unsigned long long tneigh;
3111 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3112 /* parse configuration */
3114 GNUNET_CONFIGURATION_get_value_number (c,
3119 GNUNET_CONFIGURATION_get_value_filename (c,
3121 "HOSTKEY", &keyfile)))
3123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3125 ("Transport service is lacking key configuration settings. Exiting.\n"));
3126 GNUNET_SCHEDULER_shutdown (s);
3129 max_connect_per_transport = (uint32_t) tneigh;
3130 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3131 GNUNET_free (keyfile);
3132 if (my_private_key == NULL)
3134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3136 ("Transport service could not access hostkey. Exiting.\n"));
3137 GNUNET_SCHEDULER_shutdown (s);
3140 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3141 GNUNET_CRYPTO_hash (&my_public_key,
3142 sizeof (my_public_key), &my_identity.hashPubKey);
3143 /* setup notification */
3145 GNUNET_SERVER_disconnect_notify (server,
3146 &client_disconnect_notification, NULL);
3147 /* load plugins... */
3150 GNUNET_CONFIGURATION_get_value_string (c,
3151 "TRANSPORT", "PLUGINS", &plugs))
3153 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3154 _("Starting transport plugins `%s'\n"), plugs);
3155 pos = strtok (plugs, " ");
3158 start_transport (server, pos);
3160 pos = strtok (NULL, " ");
3162 GNUNET_free (plugs);
3164 GNUNET_SCHEDULER_add_delayed (sched,
3165 GNUNET_TIME_UNIT_FOREVER_REL,
3166 &shutdown_task, NULL);
3171 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3173 /* process client requests */
3174 GNUNET_SERVER_add_handlers (server, handlers);
3179 * The main function for the transport service.
3181 * @param argc number of arguments from the command line
3182 * @param argv command line arguments
3183 * @return 0 ok, 1 on error
3186 main (int argc, char *const *argv)
3188 return (GNUNET_OK ==
3189 GNUNET_SERVICE_run (argc,
3192 GNUNET_SERVICE_OPTION_NONE,
3193 &run, NULL)) ? 0 : 1;
3196 /* end of gnunet-service-transport.c */