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 * Should we do some additional checks (to validate behavior
51 #define EXTRA_CHECKS GNUNET_YES
54 * How many messages can we have pending for a given client process
55 * before we start to drop incoming messages? We typically should
56 * have only one client and so this would be the primary buffer for
57 * messages, so the number should be chosen rather generously.
59 * The expectation here is that most of the time the queue is large
60 * enough so that a drop is virtually never required.
62 #define MAX_PENDING 128
65 * How often should we try to reconnect to a peer using a particular
66 * transport plugin before giving up? Note that the plugin may be
67 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
69 #define MAX_CONNECT_RETRY 3
72 * Limit on the number of ready-to-run tasks when validating
73 * HELLOs. If more tasks are ready to run, we will drop
74 * HELLOs instead of validating them.
76 #define MAX_HELLO_LOAD 4
79 * How often must a peer violate bandwidth quotas before we start
80 * to simply drop its messages?
82 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
85 * How long until a HELLO verification attempt should time out?
86 * Must be rather small, otherwise a partially successful HELLO
87 * validation (some addresses working) might not be available
88 * before a client's request for a connection fails for good.
89 * Besides, if a single request to an address takes a long time,
90 * then the peer is unlikely worthwhile anyway.
92 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
95 * How long will we allow sending of a ping to be delayed?
97 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
100 * Priority to use for PONG messages.
102 #define TRANSPORT_PONG_PRIORITY 4
105 * How often do we re-add (cheaper) plugins to our list of plugins
106 * to try for a given connected peer?
108 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
111 * After how long do we expire an address in a HELLO that we just
112 * validated? This value is also used for our own addresses when we
115 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
119 * How long before an existing address expires should we again try to
120 * validate it? Must be (significantly) smaller than
121 * HELLO_ADDRESS_EXPIRATION.
123 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
127 * List of addresses of other peers
129 struct ForeignAddressList
132 * This is a linked list.
134 struct ForeignAddressList *next;
137 * Which ready list does this entry belong to.
139 struct ReadyList *ready_list;
142 * How long until we auto-expire this address (unless it is
143 * re-confirmed by the transport)?
145 struct GNUNET_TIME_Absolute expires;
158 * What was the last latency observed for this plugin
159 * and peer? Invalid if connected is GNUNET_NO.
161 struct GNUNET_TIME_Relative latency;
164 * If we did not successfully transmit a message to the given peer
165 * via this connection during the specified time, we should consider
166 * the connection to be dead. This is used in the case that a TCP
167 * transport simply stalls writing to the stream but does not
168 * formerly get a signal that the other peer died.
170 struct GNUNET_TIME_Absolute timeout;
173 * Are we currently connected via this address? The first time we
174 * successfully transmit or receive data to a peer via a particular
175 * address, we set this to GNUNET_YES. If we later get an error
176 * (disconnect notification, transmission failure, timeout), we set
177 * it back to GNUNET_NO.
182 * Is this plugin currently busy transmitting to the specific target?
183 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
184 * messages do not count as 'in transmit'.
189 * Has this address been validated yet?
194 * How often have we tried to connect using this plugin? Used to
195 * discriminate against addresses that do not work well.
196 * FIXME: not yet used, but should be!
198 unsigned int connect_attempts;
204 * Entry in linked list of network addresses for ourselves.
206 struct OwnAddressList
209 * This is a linked list.
211 struct OwnAddressList *next;
214 * The address, actually a pointer to the end
215 * of this struct. Do not free!
220 * How long until we auto-expire this address (unless it is
221 * re-confirmed by the transport)?
223 struct GNUNET_TIME_Absolute expires;
234 * Entry in linked list of all of our plugins.
236 struct TransportPlugin
240 * This is a linked list.
242 struct TransportPlugin *next;
245 * API of the transport as returned by the plugin's
246 * initialization function.
248 struct GNUNET_TRANSPORT_PluginFunctions *api;
251 * Short name for the plugin (i.e. "tcp").
256 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
261 * List of our known addresses for this transport.
263 struct OwnAddressList *addresses;
266 * Environment this transport service is using
269 struct GNUNET_TRANSPORT_PluginEnvironment env;
272 * ID of task that is used to clean up expired addresses.
274 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
277 * Set to GNUNET_YES if we need to scrap the existing
278 * list of "addresses" and start fresh when we receive
279 * the next address update from a transport. Set to
280 * GNUNET_NO if we should just add the new address
281 * to the list and wait for the commit call.
290 * For each neighbor we keep a list of messages
291 * that we still want to transmit to the neighbor.
297 * This is a doubly linked list.
299 struct MessageQueue *next;
302 * This is a doubly linked list.
304 struct MessageQueue *prev;
307 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
308 * stuck together in memory. Allocated at the end of this struct.
310 const char *message_buf;
313 * Size of the message buf
315 size_t message_buf_size;
318 * Client responsible for queueing the message;
319 * used to check that a client has no two messages
320 * pending for the same target. Can be NULL.
322 struct TransportClient *client;
325 * Using which specific address should we send this message?
327 struct ForeignAddressList *specific_address;
330 * Peer ID of the Neighbor this entry belongs to.
332 struct GNUNET_PeerIdentity neighbor_id;
335 * Plugin that we used for the transmission.
336 * NULL until we scheduled a transmission.
338 struct TransportPlugin *plugin;
341 * Internal message of the transport system that should not be
342 * included in the usual SEND-SEND_OK transmission confirmation
343 * traffic management scheme. Typically, "internal_msg" will
344 * be set whenever "client" is NULL (but it is not strictly
350 * How important is the message?
352 unsigned int priority;
358 * For a given Neighbor, which plugins are available
359 * to talk to this peer and what are their costs?
364 * This is a linked list.
366 struct ReadyList *next;
369 * Which of our transport plugins does this entry
372 struct TransportPlugin *plugin;
375 * Transport addresses, latency, and readiness for
376 * this particular plugin.
378 struct ForeignAddressList *addresses;
384 * Entry in linked list of all of our current neighbors.
390 * This is a linked list.
392 struct NeighborList *next;
395 * Which of our transports is connected to this peer
396 * and what is their status?
398 struct ReadyList *plugins;
401 * Head of list of messages we would like to send to this peer;
402 * must contain at most one message per client.
404 struct MessageQueue *messages_head;
407 * Tail of list of messages we would like to send to this peer; must
408 * contain at most one message per client.
410 struct MessageQueue *messages_tail;
413 * Identity of this neighbor.
415 struct GNUNET_PeerIdentity id;
418 * ID of task scheduled to run when this peer is about to
419 * time out (will free resources associated with the peer).
421 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
424 * How long until we should consider this peer dead
425 * (if we don't receive another message in the
428 struct GNUNET_TIME_Absolute peer_timeout;
431 * At what time did we reset last_received last?
433 struct GNUNET_TIME_Absolute last_quota_update;
436 * The latency we have seen for this particular address for
437 * this particular peer. This latency may have been calculated
438 * over multiple transports. This value reflects how long it took
439 * us to receive a response when SENDING via this particular
440 * transport/neighbor/address combination!
442 * FIXME: we need to periodically send PINGs to update this
443 * latency (at least more often than the current "huge" (11h?)
446 struct GNUNET_TIME_Relative latency;
449 * How many bytes have we received since the "last_quota_update"
452 uint64_t last_received;
455 * Global quota for inbound traffic for the neighbor in bytes/ms.
460 * How often has the other peer (recently) violated the
461 * inbound traffic limit? Incremented by 10 per violation,
462 * decremented by 1 per non-violation (for each
465 unsigned int quota_violation_count;
468 * Have we seen an ACK from this neighbor in the past?
469 * (used to make up a fake ACK for clients connecting after
470 * the neighbor connected to us).
477 * Message used to ask a peer to validate receipt (to check an address
478 * from a HELLO). Followed by the address used. Note that the
479 * recipients response does not affirm that he has this address,
480 * only that he got the challenge message.
482 struct TransportPingMessage
486 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
488 struct GNUNET_MessageHeader header;
491 * Random challenge number (in network byte order).
493 uint32_t challenge GNUNET_PACKED;
496 * Who is the intended recipient?
498 struct GNUNET_PeerIdentity target;
504 * Message used to validate a HELLO. The challenge is included in the
505 * confirmation to make matching of replies to requests possible. The
506 * signature signs the original challenge number, our public key, the
507 * sender's address (so that the sender can check that the address we
508 * saw is plausible for him and possibly detect a MiM attack) and a
509 * timestamp (to limit replay).<p>
511 * This message is followed by the address of the
512 * client that we are observing (which is part of what
515 struct TransportPongMessage
519 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
521 struct GNUNET_MessageHeader header;
524 * For padding, always zero.
526 uint32_t reserved GNUNET_PACKED;
531 struct GNUNET_CRYPTO_RsaSignature signature;
534 * What are we signing and why?
536 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
539 * Random challenge number (in network byte order).
541 uint32_t challenge GNUNET_PACKED;
544 * Who signed this message?
546 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
549 * Size of address appended to this message
556 * Linked list of messages to be transmitted to
557 * the client. Each entry is followed by the
560 struct ClientMessageQueueEntry
563 * This is a linked list.
565 struct ClientMessageQueueEntry *next;
570 * Client connected to the transport service.
572 struct TransportClient
576 * This is a linked list.
578 struct TransportClient *next;
581 * Handle to the client.
583 struct GNUNET_SERVER_Client *client;
586 * Linked list of messages yet to be transmitted to
589 struct ClientMessageQueueEntry *message_queue_head;
592 * Tail of linked list of messages yet to be transmitted to the
595 struct ClientMessageQueueEntry *message_queue_tail;
598 * Is a call to "transmit_send_continuation" pending? If so, we
599 * must not free this struct (even if the corresponding client
600 * disconnects) and instead only remove it from the linked list and
601 * set the "client" field to NULL.
606 * Length of the list of messages pending for this client.
608 unsigned int message_count;
614 * Entry in map of all HELLOs awaiting validation.
616 struct ValidationEntry
620 * The address, actually a pointer to the end
621 * of this struct. Do not free!
626 * Name of the transport.
628 char *transport_name;
631 * The public key of the peer.
633 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
636 * ID of task that will clean up this entry if we don't succeed
637 * with the validation first.
639 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
642 * At what time did we send this validation?
644 struct GNUNET_TIME_Absolute send_time;
652 * Challenge number we used.
660 * Context of currently active requests to peerinfo
661 * for validation of HELLOs.
663 struct CheckHelloValidatedContext
667 * This is a doubly-linked list.
669 struct CheckHelloValidatedContext *next;
672 * This is a doubly-linked list.
674 struct CheckHelloValidatedContext *prev;
677 * Hello that we are validating.
679 const struct GNUNET_HELLO_Message *hello;
682 * Context for peerinfo iteration.
683 * NULL after we are done processing peerinfo's information.
685 struct GNUNET_PEERINFO_IteratorContext *piter;
688 * Was a HELLO known for this peer to peerinfo?
698 static struct GNUNET_HELLO_Message *our_hello;
701 * "version" of "our_hello". Used to see if a given neighbor has
702 * already been sent the latest version of our HELLO message.
704 static unsigned int our_hello_version;
709 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
714 static struct GNUNET_PeerIdentity my_identity;
719 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
724 struct GNUNET_SCHEDULER_Handle *sched;
729 const struct GNUNET_CONFIGURATION_Handle *cfg;
732 * Linked list of all clients to this service.
734 static struct TransportClient *clients;
737 * All loaded plugins.
739 static struct TransportPlugin *plugins;
744 static struct GNUNET_SERVER_Handle *server;
747 * All known neighbors and their HELLOs.
749 static struct NeighborList *neighbors;
752 * Number of neighbors we'd like to have.
754 static uint32_t max_connect_per_transport;
757 * Head of linked list.
759 static struct CheckHelloValidatedContext *chvc_head;
762 * Tail of linked list.
764 static struct CheckHelloValidatedContext *chvc_tail;
768 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
769 * of the given peer that we are currently validating).
771 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
776 * The peer specified by the given neighbor has timed-out or a plugin
777 * has disconnected. We may either need to do nothing (other plugins
778 * still up), or trigger a full disconnect and clean up. This
779 * function updates our state and do the necessary notifications.
780 * Also notifies our clients that the neighbor is now officially
783 * @param n the neighbor list entry for the peer
784 * @param check should we just check if all plugins
785 * disconnected or must we ask all plugins to
788 static void disconnect_neighbor (struct NeighborList *n, int check);
791 * Check the ready list for the given neighbor and if a plugin is
792 * ready for transmission (and if we have a message), do so!
794 * @param neighbor target peer for which to transmit
796 static void try_transmission_to_peer (struct NeighborList *neighbor);
800 * Find an entry in the neighbor list for a particular peer.
801 * if sender_address is not specified (NULL) then return the
802 * first matching entry. If sender_address is specified, then
803 * make sure that the address and address_len also matches.
805 * @return NULL if not found.
807 static struct NeighborList *
808 find_neighbor (const struct GNUNET_PeerIdentity *key)
810 struct NeighborList *head = neighbors;
812 while ((head != NULL) &&
813 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
820 * Find an entry in the transport list for a particular transport.
822 * @return NULL if not found.
824 static struct TransportPlugin *
825 find_transport (const char *short_name)
827 struct TransportPlugin *head = plugins;
828 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
835 * Update the quota values for the given neighbor now.
838 update_quota (struct NeighborList *n)
840 struct GNUNET_TIME_Relative delta;
844 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
845 if (delta.value < MIN_QUOTA_REFRESH_TIME)
846 return; /* not enough time passed for doing quota update */
847 allowed = delta.value * n->quota_in;
849 if (n->last_received < allowed)
851 remaining = allowed - n->last_received;
853 remaining /= n->quota_in;
856 if (remaining > MAX_BANDWIDTH_CARRY)
857 remaining = MAX_BANDWIDTH_CARRY;
858 n->last_received = 0;
859 n->last_quota_update = GNUNET_TIME_absolute_get ();
860 n->last_quota_update.value -= remaining;
861 if (n->quota_violation_count > 0)
862 n->quota_violation_count--;
866 n->last_received -= allowed;
867 n->last_quota_update = GNUNET_TIME_absolute_get ();
868 if (n->last_received > allowed)
870 /* more than twice the allowed rate! */
871 n->quota_violation_count += 10;
878 * Function called to notify a client about the socket being ready to
879 * queue more data. "buf" will be NULL and "size" zero if the socket
880 * was closed for writing in the meantime.
883 * @param size number of bytes available in buf
884 * @param buf where the callee should write the message
885 * @return number of bytes written to buf
888 transmit_to_client_callback (void *cls, size_t size, void *buf)
890 struct TransportClient *client = cls;
891 struct ClientMessageQueueEntry *q;
894 const struct GNUNET_MessageHeader *msg;
895 struct GNUNET_CONNECTION_TransmitHandle *th;
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
901 "Transmission to client failed, closing connection.\n");
902 /* fatal error with client, free message queue! */
903 while (NULL != (q = client->message_queue_head))
905 client->message_queue_head = q->next;
908 client->message_queue_tail = NULL;
909 client->message_count = 0;
914 while (NULL != (q = client->message_queue_head))
916 msg = (const struct GNUNET_MessageHeader *) &q[1];
917 msize = ntohs (msg->size);
918 if (msize + tsize > size)
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "Transmitting message of type %u to client.\n",
925 client->message_queue_head = q->next;
927 client->message_queue_tail = NULL;
928 memcpy (&cbuf[tsize], msg, msize);
931 client->message_count--;
935 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
936 th = GNUNET_SERVER_notify_transmit_ready (client->client,
938 GNUNET_TIME_UNIT_FOREVER_REL,
939 &transmit_to_client_callback,
941 GNUNET_assert (th != NULL);
948 * Send the specified message to the specified client. Since multiple
949 * messages may be pending for the same client at a time, this code
950 * makes sure that no message is lost.
952 * @param client client to transmit the message to
953 * @param msg the message to send
954 * @param may_drop can this message be dropped if the
955 * message queue for this client is getting far too large?
958 transmit_to_client (struct TransportClient *client,
959 const struct GNUNET_MessageHeader *msg, int may_drop)
961 struct ClientMessageQueueEntry *q;
963 struct GNUNET_CONNECTION_TransmitHandle *th;
965 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
967 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
969 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
970 client->message_count, MAX_PENDING);
971 /* TODO: call to statistics... */
974 client->message_count++;
975 msize = ntohs (msg->size);
976 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
977 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
978 memcpy (&q[1], msg, msize);
979 /* append to message queue */
980 if (client->message_queue_tail == NULL)
982 client->message_queue_tail = q;
986 client->message_queue_tail->next = q;
987 client->message_queue_tail = q;
989 if (client->message_queue_head == NULL)
991 client->message_queue_head = q;
992 th = GNUNET_SERVER_notify_transmit_ready (client->client,
994 GNUNET_TIME_UNIT_FOREVER_REL,
995 &transmit_to_client_callback,
997 GNUNET_assert (th != NULL);
1003 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1004 * upon "completion" of a send request. This tells the API
1005 * that it is now legal to send another message to the given
1008 * @param cls closure, identifies the entry on the
1009 * message queue that was transmitted and the
1010 * client responsible for queueing the message
1011 * @param target the peer receiving the message
1012 * @param result GNUNET_OK on success, if the transmission
1013 * failed, we should not tell the client to transmit
1017 transmit_send_continuation (void *cls,
1018 const struct GNUNET_PeerIdentity *target,
1021 struct MessageQueue *mq = cls;
1022 /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1023 struct SendOkMessage send_ok_msg;
1024 struct NeighborList *n;
1026 GNUNET_assert (mq != NULL);
1027 n = find_neighbor(&mq->neighbor_id);
1028 if (n == NULL) /* Neighbor must have been removed asynchronously! */
1031 /* Otherwise, let's make sure we've got the right peer */
1033 memcmp (&n->id, target,
1034 sizeof (struct GNUNET_PeerIdentity)));
1036 if (result == GNUNET_OK)
1038 if (mq->specific_address != NULL)
1040 mq->specific_address->timeout =
1041 GNUNET_TIME_relative_to_absolute
1042 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1043 mq->specific_address->connected = GNUNET_YES;
1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1049 "Transmission to peer `%s' failed, marking connection as down.\n",
1050 GNUNET_i2s (target));
1051 if (mq->specific_address != NULL)
1052 mq->specific_address->connected = GNUNET_NO;
1054 if ( (! mq->internal_msg) &&
1055 (mq->specific_address != NULL) )
1056 mq->specific_address->in_transmit = GNUNET_NO;
1058 if (mq->client != NULL)
1060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061 "Notifying client %p about transmission to peer `%4s'.\n",
1062 mq->client, GNUNET_i2s (target));
1063 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1064 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1065 send_ok_msg.success = htonl (result);
1066 send_ok_msg.peer = n->id;
1067 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1070 /* one plugin just became ready again, try transmitting
1071 another message (if available) */
1072 if (result == GNUNET_OK)
1073 try_transmission_to_peer (n);
1075 disconnect_neighbor (n, GNUNET_YES);
1080 * Find an address in any of the available transports for
1081 * the given neighbor that would be good for message
1082 * transmission. This is essentially the transport selection
1085 * @param neighbor for whom to select an address
1086 * @return selected address, NULL if we have none
1088 struct ForeignAddressList *
1089 find_ready_address(struct NeighborList *neighbor)
1091 struct ReadyList *head = neighbor->plugins;
1092 struct ForeignAddressList *addresses;
1093 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1094 struct ForeignAddressList *best_address;
1096 best_address = NULL;
1097 while (head != NULL)
1099 addresses = head->addresses;
1100 while (addresses != NULL)
1102 if ( (addresses->timeout.value < now.value) &&
1103 (addresses->connected == GNUNET_YES) )
1106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1107 "Marking long-time inactive connection to `%4s' as down.\n",
1108 GNUNET_i2s (&neighbor->id));
1110 addresses->connected = GNUNET_NO;
1112 addresses = addresses->next;
1115 addresses = head->addresses;
1116 while (addresses != NULL)
1118 if ( ( (best_address == NULL) ||
1119 (addresses->connected == GNUNET_YES) ||
1120 (best_address->connected == GNUNET_NO) ) &&
1121 (addresses->in_transmit == GNUNET_NO) &&
1122 ( (best_address == NULL) ||
1123 (addresses->latency.value < best_address->latency.value)) )
1124 best_address = addresses;
1125 /* FIXME: also give lower-latency addresses that are not
1126 connected a chance some times... */
1127 addresses = addresses->next;
1132 if (best_address != NULL)
1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1135 "Best address found has latency of %llu ms.\n",
1136 best_address->latency.value);
1139 return best_address;
1145 * Check the ready list for the given neighbor and if a plugin is
1146 * ready for transmission (and if we have a message), do so!
1148 * @param neighbor target peer for which to transmit
1151 try_transmission_to_peer (struct NeighborList *neighbor)
1153 struct GNUNET_TIME_Relative min_latency;
1154 struct ReadyList *rl;
1155 struct MessageQueue *mq;
1157 if (neighbor->messages_head == NULL)
1158 return; /* nothing to do */
1159 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1161 mq = neighbor->messages_head;
1162 if (mq->specific_address == NULL)
1163 mq->specific_address = find_ready_address(neighbor);
1164 if (mq->specific_address == NULL)
1167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1168 "No destination address available to transmit message of size %u to peer `%4s'\n",
1169 mq->message_buf_size,
1170 GNUNET_i2s (&mq->neighbor_id));
1172 return; /* nobody ready */
1174 if (mq->specific_address->connected == GNUNET_NO)
1175 mq->specific_address->connect_attempts++;
1176 rl = mq->specific_address->ready_list;
1177 GNUNET_CONTAINER_DLL_remove (neighbor->messages_head,
1178 neighbor->messages_tail,
1180 mq->plugin = rl->plugin;
1181 if (!mq->internal_msg)
1182 mq->specific_address->in_transmit = GNUNET_YES;
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1186 mq->message_buf_size,
1187 GNUNET_i2s (&neighbor->id),
1188 GNUNET_a2s (mq->specific_address->addr,
1189 mq->specific_address->addrlen),
1190 rl->plugin->short_name);
1192 rl->plugin->api->send (rl->plugin->api->cls,
1195 mq->message_buf_size,
1197 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1198 mq->specific_address->addr,
1199 mq->specific_address->addrlen,
1200 GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1201 &transmit_send_continuation, mq);
1206 * Send the specified message to the specified peer.
1208 * @param client source of the transmission request (can be NULL)
1209 * @param peer_address ForeignAddressList where we should send this message
1210 * @param priority how important is the message
1211 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1212 * @param message_buf_size total size of all messages in message_buf
1213 * @param is_internal is this an internal message; these are pre-pended and
1214 * also do not count for plugins being "ready" to transmit
1215 * @param neighbor handle to the neighbor for transmission
1218 transmit_to_peer (struct TransportClient *client,
1219 struct ForeignAddressList *peer_address,
1220 unsigned int priority,
1221 const char *message_buf,
1222 size_t message_buf_size,
1223 int is_internal, struct NeighborList *neighbor)
1225 struct MessageQueue *mq;
1230 /* check for duplicate submission */
1231 mq = neighbor->messages_head;
1234 if (mq->client == client)
1236 /* client transmitted to same peer twice
1237 before getting SendOk! */
1245 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1246 mq->specific_address = peer_address;
1247 mq->client = client;
1248 memcpy (&mq[1], message_buf, message_buf_size);
1249 mq->message_buf = (const char*) &mq[1];
1250 mq->message_buf_size = message_buf_size;
1251 memcpy(&mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1252 mq->internal_msg = is_internal;
1253 mq->priority = priority;
1256 GNUNET_CONTAINER_DLL_insert (neighbor->messages_head,
1257 neighbor->messages_tail,
1260 GNUNET_CONTAINER_DLL_insert_after (neighbor->messages_head,
1261 neighbor->messages_tail,
1262 neighbor->messages_tail,
1264 try_transmission_to_peer (neighbor);
1271 struct GeneratorContext
1273 struct TransportPlugin *plug_pos;
1274 struct OwnAddressList *addr_pos;
1275 struct GNUNET_TIME_Absolute expiration;
1283 address_generator (void *cls, size_t max, void *buf)
1285 struct GeneratorContext *gc = cls;
1288 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1290 gc->plug_pos = gc->plug_pos->next;
1291 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1293 if (NULL == gc->plug_pos)
1298 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1301 gc->addr_pos->addrlen, buf, max);
1302 gc->addr_pos = gc->addr_pos->next;
1308 * Construct our HELLO message from all of the addresses of
1309 * all of the transports.
1314 struct GNUNET_HELLO_Message *hello;
1315 struct TransportClient *cpos;
1316 struct NeighborList *npos;
1317 struct GeneratorContext gc;
1319 gc.plug_pos = plugins;
1320 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1321 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1322 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1325 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1328 while (cpos != NULL)
1330 transmit_to_client (cpos,
1331 (const struct GNUNET_MessageHeader *) hello,
1336 GNUNET_free_non_null (our_hello);
1338 our_hello_version++;
1339 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1341 while (npos != NULL)
1344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1345 "Transmitting updated `%s' to neighbor `%4s'\n",
1346 "HELLO", GNUNET_i2s (&npos->id));
1348 transmit_to_peer (NULL, NULL, 0,
1349 (const char *) our_hello,
1350 GNUNET_HELLO_size(our_hello),
1358 * Task used to clean up expired addresses for a plugin.
1360 * @param cls closure
1364 expire_address_task (void *cls,
1365 const struct GNUNET_SCHEDULER_TaskContext *tc);
1369 * Update the list of addresses for this plugin,
1370 * expiring those that are past their expiration date.
1372 * @param plugin addresses of which plugin should be recomputed?
1373 * @param fresh set to GNUNET_YES if a new address was added
1374 * and we need to regenerate the HELLO even if nobody
1378 update_addresses (struct TransportPlugin *plugin, int fresh)
1380 struct GNUNET_TIME_Relative min_remaining;
1381 struct GNUNET_TIME_Relative remaining;
1382 struct GNUNET_TIME_Absolute now;
1383 struct OwnAddressList *pos;
1384 struct OwnAddressList *prev;
1385 struct OwnAddressList *next;
1388 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1389 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1390 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1391 now = GNUNET_TIME_absolute_get ();
1392 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1393 expired = GNUNET_NO;
1395 pos = plugin->addresses;
1399 if (pos->expires.value < now.value)
1401 expired = GNUNET_YES;
1403 plugin->addresses = pos->next;
1405 prev->next = pos->next;
1410 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1411 if (remaining.value < min_remaining.value)
1412 min_remaining = remaining;
1418 if (expired || fresh)
1420 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1421 plugin->address_update_task
1422 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1424 &expire_address_task, plugin);
1430 * Task used to clean up expired addresses for a plugin.
1432 * @param cls closure
1436 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1438 struct TransportPlugin *plugin = cls;
1439 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1440 update_addresses (plugin, GNUNET_NO);
1445 * Function that must be called by each plugin to notify the
1446 * transport service about the addresses under which the transport
1447 * provided by the plugin can be reached.
1449 * @param cls closure
1450 * @param name name of the transport that generated the address
1451 * @param addr one of the addresses of the host, NULL for the last address
1452 * the specific address format depends on the transport
1453 * @param addrlen length of the address
1454 * @param expires when should this address automatically expire?
1457 plugin_env_notify_address (void *cls,
1461 struct GNUNET_TIME_Relative expires)
1463 struct TransportPlugin *p = cls;
1464 struct OwnAddressList *al;
1465 struct GNUNET_TIME_Absolute abex;
1467 abex = GNUNET_TIME_relative_to_absolute (expires);
1468 GNUNET_assert (p == find_transport (name));
1473 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1475 if (al->expires.value < abex.value)
1482 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1484 al->next = p->addresses;
1487 al->addrlen = addrlen;
1488 memcpy (&al[1], addr, addrlen);
1489 update_addresses (p, GNUNET_YES);
1494 * Notify all of our clients about a peer connecting.
1497 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1498 struct GNUNET_TIME_Relative latency)
1500 struct ConnectInfoMessage cim;
1501 struct TransportClient *cpos;
1503 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1504 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1505 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1506 cim.latency = GNUNET_TIME_relative_hton (latency);
1507 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1509 while (cpos != NULL)
1511 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1518 * Notify all of our clients about a peer disconnecting.
1521 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1523 struct DisconnectInfoMessage dim;
1524 struct TransportClient *cpos;
1526 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1527 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1528 dim.reserved = htonl (0);
1529 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1531 while (cpos != NULL)
1533 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1540 * Find a ForeignAddressList entry for the given neighbour
1541 * that matches the given address and transport.
1543 * @param neighbor which peer we care about
1544 * @param tname name of the transport plugin
1545 * @param addr binary address
1546 * @param addrlen length of addr
1547 * @return NULL if no such entry exists
1549 static struct ForeignAddressList *
1550 find_peer_address(struct NeighborList *neighbor,
1555 struct ReadyList *head;
1556 struct ForeignAddressList *address_head;
1558 head = neighbor->plugins;
1559 while (head != NULL)
1561 if (0 == strcmp (tname, head->plugin->short_name))
1568 address_head = head->addresses;
1569 while ( (address_head != NULL) &&
1570 ( (address_head->addrlen != addrlen) ||
1571 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1572 address_head = address_head->next;
1573 return address_head;
1578 * Get the peer address struct for the given neighbor and
1579 * address. If it doesn't yet exist, create it.
1581 * @param neighbor which peer we care about
1582 * @param tname name of the transport plugin
1583 * @param addr binary address
1584 * @param addrlen length of addr
1585 * @return NULL if we do not have a transport plugin for 'tname'
1587 static struct ForeignAddressList *
1588 add_peer_address(struct NeighborList *neighbor,
1593 struct ReadyList *head;
1594 struct ForeignAddressList *ret;
1596 ret = find_peer_address (neighbor, tname, addr, addrlen);
1599 head = neighbor->plugins;
1600 while (head != NULL)
1602 if (0 == strcmp (tname, head->plugin->short_name))
1608 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1609 ret->addr = (const char*) &ret[1];
1610 memcpy (&ret[1], addr, addrlen);
1611 ret->addrlen = addrlen;
1612 ret->expires = GNUNET_TIME_relative_to_absolute
1613 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1614 ret->latency = GNUNET_TIME_relative_get_forever();
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);
1730 if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
1731 n->latency = fal->latency;
1733 n->latency.value = (fal->latency.value + n->latency.value) / 2;
1736 /* clean up validation entry */
1737 GNUNET_assert (GNUNET_YES ==
1738 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1741 GNUNET_SCHEDULER_cancel (sched,
1743 GNUNET_free (ve->transport_name);
1750 * Function that will be called if we receive a validation
1751 * of an address challenge that we transmitted to another
1752 * peer. Note that the validation should only be considered
1753 * acceptable if the challenge matches AND if the sender
1754 * address is at least a plausible address for this peer
1755 * (otherwise we may be seeing a MiM attack).
1757 * @param cls closure
1758 * @param name name of the transport that generated the address
1759 * @param peer who responded to our challenge
1760 * @param challenge the challenge number we presumably used
1761 * @param sender_addr string describing our sender address (as observed
1762 * by the other peer in human-readable format)
1765 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1766 const struct GNUNET_PeerIdentity *peer,
1767 const char *sender_address,
1768 size_t sender_address_len)
1770 #if DEBUG_TRANSPORT > 1
1771 /* we get tons of these that just get discarded, only log
1772 if we are quite verbose */
1773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1774 "Receiving `%s' message from `%4s'.\n", "PONG",
1777 if (GNUNET_SYSERR !=
1778 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1780 &check_pending_validation,
1783 /* This is *expected* to happen a lot since we send
1784 PONGs to *all* known addresses of the sender of
1785 the PING, so most likely we get multiple PONGs
1786 per PING, and all but the first PONG will end up
1787 here. So really we should not print anything here
1788 unless we want to be very, very verbose... */
1789 #if DEBUG_TRANSPORT > 2
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
1799 /* FIXME: add given address to potential pool of our addresses
1801 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1802 _("Another peer saw us using the address `%s' via `%s'.\n"),
1803 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1804 ntohs(pong->addrlen)),
1805 va->transport_name);
1811 neighbor_timeout_task (void *cls,
1812 const struct GNUNET_SCHEDULER_TaskContext *tc)
1814 struct NeighborList *n = cls;
1817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1818 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1820 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1821 disconnect_neighbor (n, GNUNET_NO);
1826 * Create a fresh entry in our neighbor list for the given peer.
1827 * Will try to transmit our current HELLO to the new neighbor. Also
1828 * notifies our clients about the new "connection".
1830 * @param peer the peer for which we create the entry
1831 * @return the new neighbor list entry
1833 static struct NeighborList *
1834 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1836 struct NeighborList *n;
1837 struct TransportPlugin *tp;
1838 struct ReadyList *rl;
1840 GNUNET_assert (our_hello != NULL);
1841 n = GNUNET_malloc (sizeof (struct NeighborList));
1842 n->next = neighbors;
1845 n->last_quota_update = GNUNET_TIME_absolute_get ();
1847 GNUNET_TIME_relative_to_absolute
1848 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1849 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1853 if (tp->api->send != NULL)
1855 rl = GNUNET_malloc (sizeof (struct ReadyList));
1856 rl->next = n->plugins;
1859 rl->addresses = NULL;
1863 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
1864 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1865 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1866 &neighbor_timeout_task, n);
1867 transmit_to_peer (NULL, NULL, 0,
1868 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1870 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1876 * Closure for 'check_address_exists'.
1878 struct CheckAddressExistsClosure
1881 * Address to check for.
1886 * Name of the transport.
1896 * Set to GNUNET_YES if the address exists.
1903 * Iterator over hash map entries. Checks if the given
1904 * validation entry is for the same address as what is given
1907 * @param cls the 'struct CheckAddressExistsClosure*'
1908 * @param key current key code (ignored)
1909 * @param value value in the hash map ('struct ValidationEntry')
1910 * @return GNUNET_YES if we should continue to
1911 * iterate (mismatch), GNUNET_NO if not (entry matched)
1914 check_address_exists (void *cls,
1915 const GNUNET_HashCode * key,
1918 struct CheckAddressExistsClosure *caec = cls;
1919 struct ValidationEntry *ve = value;
1920 if ( (0 == strcmp (caec->tname,
1921 ve->transport_name)) &&
1922 (caec->addrlen == ve->addrlen) &&
1923 (0 == memcmp (caec->addr,
1927 caec->exists = GNUNET_YES;
1935 * HELLO validation cleanup task (validation failed).
1937 * @param cls the 'struct ValidationEntry' that failed
1938 * @param tc scheduler context (unused)
1941 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1943 struct ValidationEntry *va = cls;
1944 struct GNUNET_PeerIdentity pid;
1946 GNUNET_CRYPTO_hash (&va->publicKey,
1948 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1950 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1953 GNUNET_free (va->transport_name);
1959 * Check if the given address is already being validated; if not,
1960 * append the given address to the list of entries that are being be
1961 * validated and initiate validation.
1963 * @param cls closure ('struct CheckHelloValidatedContext *')
1964 * @param tname name of the transport
1965 * @param expiration expiration time
1966 * @param addr the address
1967 * @param addrlen length of the address
1968 * @return GNUNET_OK (always)
1971 run_validation (void *cls,
1973 struct GNUNET_TIME_Absolute expiration,
1974 const void *addr, size_t addrlen)
1976 struct CheckHelloValidatedContext *chvc = cls;
1977 struct GNUNET_PeerIdentity id;
1978 struct TransportPlugin *tp;
1979 struct ValidationEntry *va;
1980 struct NeighborList *neighbor;
1981 struct ForeignAddressList *peer_address;
1982 struct TransportPingMessage ping;
1983 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
1984 struct CheckAddressExistsClosure caec;
1986 uint16_t hello_size;
1989 tp = find_transport (tname);
1992 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1993 GNUNET_ERROR_TYPE_BULK,
1995 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1999 GNUNET_HELLO_get_key (chvc->hello, &pk);
2000 GNUNET_CRYPTO_hash (&pk,
2002 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2005 caec.addrlen = addrlen;
2007 caec.exists = GNUNET_NO;
2008 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2009 &check_address_exists,
2011 if (caec.exists == GNUNET_YES)
2013 /* During validation attempts we will likely trigger the other
2014 peer trying to validate our address which in turn will cause
2015 it to send us its HELLO, so we expect to hit this case rather
2016 frequently. Only print something if we are very verbose. */
2017 #if DEBUG_TRANSPORT > 1
2018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2019 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2020 GNUNET_a2s (addr, addrlen),
2026 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2027 va->transport_name = GNUNET_strdup (tname);
2028 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2030 va->send_time = GNUNET_TIME_absolute_get();
2031 va->addr = (const void*) &va[1];
2032 memcpy (&va[1], addr, addrlen);
2033 va->addrlen = addrlen;
2034 GNUNET_HELLO_get_key (chvc->hello,
2036 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2037 HELLO_VERIFICATION_TIMEOUT,
2038 &timeout_hello_validation,
2040 GNUNET_CONTAINER_multihashmap_put (validation_map,
2043 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2044 neighbor = find_neighbor(&id);
2045 if (neighbor == NULL)
2046 neighbor = setup_new_neighbor(&id);
2047 peer_address = add_peer_address(neighbor, tname, addr, addrlen);
2048 GNUNET_assert(peer_address != NULL);
2049 hello_size = GNUNET_HELLO_size(our_hello);
2050 tsize = sizeof(struct TransportPingMessage) + hello_size;
2051 message_buf = GNUNET_malloc(tsize);
2052 ping.challenge = htonl(va->challenge);
2053 ping.header.size = htons(sizeof(struct TransportPingMessage));
2054 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2055 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2056 memcpy(message_buf, our_hello, hello_size);
2057 memcpy(&message_buf[hello_size],
2059 sizeof(struct TransportPingMessage));
2061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2063 GNUNET_a2s (addr, addrlen),
2066 "HELLO", hello_size,
2067 "PING", sizeof (struct TransportPingMessage));
2069 transmit_to_peer (NULL, peer_address,
2070 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2072 GNUNET_YES, neighbor);
2073 GNUNET_free(message_buf);
2079 * Add the given address to the list of foreign addresses
2080 * available for the given peer (check for duplicates).
2082 * @param cls the respective 'struct NeighborList' to update
2083 * @param tname name of the transport
2084 * @param expiration expiration time
2085 * @param addr the address
2086 * @param addrlen length of the address
2087 * @return GNUNET_OK (always)
2090 add_to_foreign_address_list (void *cls,
2092 struct GNUNET_TIME_Absolute expiration,
2093 const void *addr, size_t addrlen)
2095 struct NeighborList *n = cls;
2096 struct ForeignAddressList *fal;
2098 fal = find_peer_address (n, tname, addr, addrlen);
2102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2103 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data.\n",
2104 GNUNET_a2s (addr, addrlen),
2106 GNUNET_i2s (&n->id));
2108 fal = add_peer_address (n, tname, addr, addrlen);
2112 fal->expires = GNUNET_TIME_absolute_max (expiration,
2114 fal->validated = GNUNET_YES;
2120 * Check if addresses in validated hello "h" overlap with
2121 * those in "chvc->hello" and validate the rest.
2123 * @param cls closure
2124 * @param peer id of the peer, NULL for last call
2125 * @param hello hello message for the peer (can be NULL)
2126 * @param trust amount of trust we have in the peer (not used)
2129 check_hello_validated (void *cls,
2130 const struct GNUNET_PeerIdentity *peer,
2131 const struct GNUNET_HELLO_Message *h,
2134 struct CheckHelloValidatedContext *chvc = cls;
2135 struct GNUNET_HELLO_Message *plain_hello;
2136 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2137 struct GNUNET_PeerIdentity target;
2138 struct NeighborList *n;
2143 GNUNET_CONTAINER_DLL_remove (chvc_head,
2146 if (GNUNET_NO == chvc->hello_known)
2148 /* notify PEERINFO about the peer now, so that we at least
2149 have the public key if some other component needs it */
2150 GNUNET_HELLO_get_key (chvc->hello, &pk);
2151 GNUNET_CRYPTO_hash (&pk,
2152 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2153 &target.hashPubKey);
2154 plain_hello = GNUNET_HELLO_create (&pk,
2157 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2158 GNUNET_free (plain_hello);
2160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2161 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2163 GNUNET_i2s (&target));
2165 GNUNET_HELLO_iterate_addresses (chvc->hello,
2175 chvc->hello_known = GNUNET_YES;
2176 n = find_neighbor (peer);
2178 GNUNET_HELLO_iterate_addresses (h,
2180 &add_to_foreign_address_list,
2182 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2184 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2190 * Process HELLO-message.
2192 * @param plugin transport involved, may be NULL
2193 * @param message the actual message
2194 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2197 process_hello (struct TransportPlugin *plugin,
2198 const struct GNUNET_MessageHeader *message)
2201 struct GNUNET_PeerIdentity target;
2202 const struct GNUNET_HELLO_Message *hello;
2203 struct CheckHelloValidatedContext *chvc;
2204 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2206 hsize = ntohs (message->size);
2207 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2208 (hsize < sizeof (struct GNUNET_MessageHeader)))
2211 return GNUNET_SYSERR;
2213 /* first, check if load is too high */
2214 if (GNUNET_SCHEDULER_get_load (sched,
2215 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2217 /* TODO: call to stats? */
2220 hello = (const struct GNUNET_HELLO_Message *) message;
2221 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2223 GNUNET_break_op (0);
2224 return GNUNET_SYSERR;
2226 GNUNET_CRYPTO_hash (&publicKey,
2227 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2228 &target.hashPubKey);
2230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2231 "Processing `%s' message for `%4s' of size %u\n",
2233 GNUNET_i2s (&target),
2234 GNUNET_HELLO_size(hello));
2237 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2238 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2239 memcpy (&chvc[1], hello, hsize);
2240 GNUNET_CONTAINER_DLL_insert (chvc_head,
2243 /* finally, check if HELLO was previously validated
2244 (continuation will then schedule actual validation) */
2245 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2249 HELLO_VERIFICATION_TIMEOUT,
2250 &check_hello_validated, chvc);
2256 * The peer specified by the given neighbor has timed-out or a plugin
2257 * has disconnected. We may either need to do nothing (other plugins
2258 * still up), or trigger a full disconnect and clean up. This
2259 * function updates our state and does the necessary notifications.
2260 * Also notifies our clients that the neighbor is now officially
2263 * @param n the neighbor list entry for the peer
2264 * @param check should we just check if all plugins
2265 * disconnected or must we ask all plugins to
2269 disconnect_neighbor (struct NeighborList *current_handle, int check)
2271 struct ReadyList *rpos;
2272 struct NeighborList *npos;
2273 struct NeighborList *nprev;
2274 struct NeighborList *n;
2275 struct MessageQueue *mq;
2276 struct ForeignAddressList *peer_addresses;
2277 struct ForeignAddressList *peer_pos;
2279 if (neighbors == NULL)
2280 return; /* We don't have any neighbors, so client has an already removed handle! */
2283 while ((npos != NULL) && (current_handle != npos))
2287 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2291 if (GNUNET_YES == check)
2294 while (NULL != rpos)
2296 peer_addresses = rpos->addresses;
2297 while (peer_addresses != NULL)
2299 if (GNUNET_YES == peer_addresses->connected)
2300 return; /* still connected */
2301 peer_addresses = peer_addresses->next;
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2309 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2311 /* remove n from neighbors list */
2314 while ((npos != NULL) && (npos != n))
2319 GNUNET_assert (npos != NULL);
2321 neighbors = n->next;
2323 nprev->next = n->next;
2325 /* notify all clients about disconnect */
2326 notify_clients_disconnect (&n->id);
2328 /* clean up all plugins, cancel connections and pending transmissions */
2329 while (NULL != (rpos = n->plugins))
2331 n->plugins = rpos->next;
2332 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2334 while (rpos->addresses != NULL)
2336 peer_pos = rpos->addresses;
2337 rpos->addresses = peer_pos->next;
2338 GNUNET_free(peer_pos);
2343 /* free all messages on the queue */
2344 while (NULL != (mq = n->messages_head))
2346 GNUNET_CONTAINER_DLL_remove (n->messages_head,
2349 GNUNET_assert (0 == memcmp(&mq->neighbor_id,
2351 sizeof(struct GNUNET_PeerIdentity)));
2354 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2355 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2356 /* finally, free n itself */
2362 * We have received a PING message from someone. Need to send a PONG message
2363 * in response to the peer by any means necessary.
2365 * FIXME: With something like TCP where a connection exists, we may
2366 * want to send it that way. But the current API does not seem to
2367 * allow us to do so (can't tell this to the transport!)
2370 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2371 const struct GNUNET_PeerIdentity *peer,
2372 const char *sender_address,
2373 size_t sender_address_len)
2375 struct TransportPlugin *plugin = cls;
2376 struct TransportPingMessage *ping;
2377 struct TransportPongMessage *pong;
2379 struct NeighborList *n;
2380 struct ReadyList *rl;
2381 struct ForeignAddressList *fal;
2383 msize = ntohs (message->size);
2384 if (msize < sizeof (struct TransportPingMessage))
2386 GNUNET_break_op (0);
2387 return GNUNET_SYSERR;
2389 ping = (struct TransportPingMessage *) message;
2390 if (0 != memcmp (&ping->target,
2391 plugin->env.my_identity,
2392 sizeof (struct GNUNET_PeerIdentity)))
2394 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2395 _("Received `%s' message not destined for me!\n"),
2397 return GNUNET_SYSERR;
2400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2401 "Processing `%s' from `%s'\n",
2403 GNUNET_a2s ((const struct sockaddr *)sender_address,
2404 sender_address_len));
2406 msize -= sizeof (struct TransportPingMessage);
2407 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2408 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2409 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2410 pong->purpose.size =
2411 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2413 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2414 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2415 pong->challenge = ping->challenge;
2416 pong->addrlen = htons(sender_address_len);
2417 memcpy(&pong->signer,
2419 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2420 memcpy (&pong[1], sender_address, sender_address_len);
2421 GNUNET_assert (GNUNET_OK ==
2422 GNUNET_CRYPTO_rsa_sign (my_private_key,
2423 &pong->purpose, &pong->signature));
2425 n = find_neighbor(peer);
2427 n = setup_new_neighbor(peer);
2428 /* broadcast 'PONG' to all available addresses */
2432 fal = rl->addresses;
2435 transmit_to_peer(NULL, fal,
2436 TRANSPORT_PONG_PRIORITY,
2438 ntohs(pong->header.size),
2451 * Function called by the plugin for each received message.
2452 * Update data volumes, possibly notify plugins about
2453 * reducing the rate at which they read from the socket
2454 * and generally forward to our receive callback.
2456 * @param cls the "struct TransportPlugin *" we gave to the plugin
2457 * @param message the message, NULL if peer was disconnected
2458 * @param distance the transport cost to this peer (not latency!)
2459 * @param sender_address the address that the sender reported
2460 * (opaque to transport service)
2461 * @param sender_address_len the length of the sender address
2462 * @param peer (claimed) identity of the other peer
2463 * @return the new service_context that the plugin should use
2464 * for future receive calls for messages from this
2469 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2470 const struct GNUNET_MessageHeader *message,
2471 unsigned int distance, const char *sender_address,
2472 size_t sender_address_len)
2474 struct ReadyList *service_context;
2475 struct TransportPlugin *plugin = cls;
2476 struct TransportClient *cpos;
2477 struct InboundMessage *im;
2478 struct ForeignAddressList *peer_address;
2480 struct NeighborList *n;
2482 n = find_neighbor (peer);
2485 if (message == NULL)
2486 return; /* disconnect of peer already marked down */
2487 n = setup_new_neighbor (peer);
2489 service_context = n->plugins;
2490 while ((service_context != NULL) && (plugin != service_context->plugin))
2491 service_context = service_context->next;
2492 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2493 if (message == NULL)
2496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2497 "Receive failed from `%4s', triggering disconnect\n",
2498 GNUNET_i2s (&n->id));
2500 /* TODO: call stats */
2501 disconnect_neighbor (n, GNUNET_YES);
2504 peer_address = add_peer_address(n,
2507 sender_address_len);
2508 if (peer_address != NULL)
2510 if (peer_address->connected == GNUNET_NO)
2512 peer_address->connected = GNUNET_YES;
2513 peer_address->connect_attempts++;
2515 peer_address->timeout
2517 GNUNET_TIME_relative_to_absolute
2518 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2520 /* update traffic received amount ... */
2521 msize = ntohs (message->size);
2522 n->last_received += msize;
2523 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2525 GNUNET_TIME_relative_to_absolute
2526 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2528 GNUNET_SCHEDULER_add_delayed (sched,
2529 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2530 &neighbor_timeout_task, n);
2532 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2534 /* dropping message due to frequent inbound volume violations! */
2535 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2536 GNUNET_ERROR_TYPE_BULK,
2538 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2539 /* TODO: call stats */
2542 switch (ntohs (message->type))
2544 case GNUNET_MESSAGE_TYPE_HELLO:
2545 process_hello (plugin, message);
2547 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2548 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2550 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2551 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2556 "Received message of type %u from `%4s', sending to all clients.\n",
2557 ntohs (message->type), GNUNET_i2s (peer));
2559 /* transmit message to all clients */
2560 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2561 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2562 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2563 im->latency = GNUNET_TIME_relative_hton (n->latency);
2565 memcpy (&im[1], message, msize);
2568 while (cpos != NULL)
2570 transmit_to_client (cpos, &im->header, GNUNET_YES);
2579 * Handle START-message. This is the first message sent to us
2580 * by any client which causes us to add it to our list.
2582 * @param cls closure (always NULL)
2583 * @param client identification of the client
2584 * @param message the actual message
2587 handle_start (void *cls,
2588 struct GNUNET_SERVER_Client *client,
2589 const struct GNUNET_MessageHeader *message)
2591 struct TransportClient *c;
2592 struct ConnectInfoMessage cim;
2593 struct NeighborList *n;
2594 struct InboundMessage *im;
2595 struct GNUNET_MessageHeader *ack;
2598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599 "Received `%s' request from client\n", "START");
2604 if (c->client == client)
2606 /* client already on our list! */
2608 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2613 c = GNUNET_malloc (sizeof (struct TransportClient));
2617 if (our_hello != NULL)
2620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2621 "Sending our own `%s' to new client\n", "HELLO");
2623 transmit_to_client (c,
2624 (const struct GNUNET_MessageHeader *) our_hello,
2626 /* tell new client about all existing connections */
2627 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2628 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2630 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2631 /* FIXME: this ACK stuff is not nice! */
2632 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2633 sizeof (struct GNUNET_MessageHeader));
2634 im->header.size = htons (sizeof (struct InboundMessage) +
2635 sizeof (struct GNUNET_MessageHeader));
2636 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2637 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
2638 ack = (struct GNUNET_MessageHeader *) &im[1];
2639 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2640 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2641 for (n = neighbors; n != NULL; n = n->next)
2644 cim.latency = GNUNET_TIME_relative_hton (n->latency);
2645 transmit_to_client (c, &cim.header, GNUNET_NO);
2646 if (n->received_pong)
2649 transmit_to_client (c, &im->header, GNUNET_NO);
2656 fprintf(stderr, "Our hello is NULL!\n");
2658 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2663 * Handle HELLO-message.
2665 * @param cls closure (always NULL)
2666 * @param client identification of the client
2667 * @param message the actual message
2670 handle_hello (void *cls,
2671 struct GNUNET_SERVER_Client *client,
2672 const struct GNUNET_MessageHeader *message)
2677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2678 "Received `%s' request from client\n", "HELLO");
2680 ret = process_hello (NULL, message);
2681 GNUNET_SERVER_receive_done (client, ret);
2686 * Handle SEND-message.
2688 * @param cls closure (always NULL)
2689 * @param client identification of the client
2690 * @param message the actual message
2693 handle_send (void *cls,
2694 struct GNUNET_SERVER_Client *client,
2695 const struct GNUNET_MessageHeader *message)
2697 struct TransportClient *tc;
2698 struct NeighborList *n;
2699 const struct OutboundMessage *obm;
2700 const struct GNUNET_MessageHeader *obmm;
2704 size = ntohs (message->size);
2706 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2709 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2712 obm = (const struct OutboundMessage *) message;
2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715 "Received `%s' request from client with target `%4s'\n",
2716 "SEND", GNUNET_i2s (&obm->peer));
2718 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2719 msize = ntohs (obmm->size);
2720 if (size != msize + sizeof (struct OutboundMessage))
2723 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2726 n = find_neighbor (&obm->peer);
2728 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2730 while ((tc != NULL) && (tc->client != client))
2734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2735 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2737 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2739 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm,
2740 ntohs (obmm->size), GNUNET_NO, n);
2741 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2746 * Handle SET_QUOTA-message.
2748 * @param cls closure (always NULL)
2749 * @param client identification of the client
2750 * @param message the actual message
2753 handle_set_quota (void *cls,
2754 struct GNUNET_SERVER_Client *client,
2755 const struct GNUNET_MessageHeader *message)
2757 const struct QuotaSetMessage *qsm =
2758 (const struct QuotaSetMessage *) message;
2759 struct NeighborList *n;
2760 struct TransportPlugin *p;
2761 struct ReadyList *rl;
2763 n = find_neighbor (&qsm->peer);
2766 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2772 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2773 "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2777 if (n->quota_in < ntohl (qsm->quota_in))
2778 n->last_quota_update = GNUNET_TIME_absolute_get ();
2779 n->quota_in = ntohl (qsm->quota_in);
2784 p->api->set_receive_quota (p->api->cls,
2785 &qsm->peer, ntohl (qsm->quota_in));
2788 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2793 * Handle TRY_CONNECT-message.
2795 * @param cls closure (always NULL)
2796 * @param client identification of the client
2797 * @param message the actual message
2800 handle_try_connect (void *cls,
2801 struct GNUNET_SERVER_Client *client,
2802 const struct GNUNET_MessageHeader *message)
2804 const struct TryConnectMessage *tcm;
2805 struct NeighborList *neighbor;
2806 tcm = (const struct TryConnectMessage *) message;
2808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2809 "Received `%s' request from client %p asking to connect to `%4s'\n",
2810 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2812 neighbor = find_neighbor(&tcm->peer);
2813 if (neighbor == NULL)
2814 setup_new_neighbor (&tcm->peer);
2815 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2820 transmit_address_to_client (void *cls, const char *address)
2822 struct GNUNET_SERVER_TransmitContext *tc = cls;
2825 if (NULL == address)
2828 slen = strlen (address) + 1;
2829 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2830 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2831 if (NULL == address)
2832 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2837 * Handle AddressLookup-message.
2839 * @param cls closure (always NULL)
2840 * @param client identification of the client
2841 * @param message the actual message
2844 handle_address_lookup (void *cls,
2845 struct GNUNET_SERVER_Client *client,
2846 const struct GNUNET_MessageHeader *message)
2848 const struct AddressLookupMessage *alum;
2849 struct TransportPlugin *lsPlugin;
2850 const char *nameTransport;
2851 const char *address;
2853 struct GNUNET_SERVER_TransmitContext *tc;
2855 size = ntohs (message->size);
2856 if (size < sizeof (struct AddressLookupMessage))
2858 GNUNET_break_op (0);
2859 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2862 alum = (const struct AddressLookupMessage *) message;
2863 uint32_t addressLen = ntohl (alum->addrlen);
2864 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2866 GNUNET_break_op (0);
2867 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2870 address = (const char *) &alum[1];
2871 nameTransport = (const char *) &address[addressLen];
2873 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2875 GNUNET_break_op (0);
2876 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2879 struct GNUNET_TIME_Absolute timeout =
2880 GNUNET_TIME_absolute_ntoh (alum->timeout);
2881 struct GNUNET_TIME_Relative rtimeout =
2882 GNUNET_TIME_absolute_get_remaining (timeout);
2883 lsPlugin = find_transport (nameTransport);
2884 if (NULL == lsPlugin)
2886 tc = GNUNET_SERVER_transmit_context_create (client);
2887 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2888 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2889 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2892 tc = GNUNET_SERVER_transmit_context_create (client);
2893 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2894 address, addressLen, GNUNET_YES,
2896 &transmit_address_to_client, tc);
2900 * List of handlers for the messages understood by this
2903 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2904 {&handle_start, NULL,
2905 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2906 {&handle_hello, NULL,
2907 GNUNET_MESSAGE_TYPE_HELLO, 0},
2908 {&handle_send, NULL,
2909 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2910 {&handle_set_quota, NULL,
2911 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2912 {&handle_try_connect, NULL,
2913 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2914 sizeof (struct TryConnectMessage)},
2915 {&handle_address_lookup, NULL,
2916 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2923 * Setup the environment for this plugin.
2926 create_environment (struct TransportPlugin *plug)
2928 plug->env.cfg = cfg;
2929 plug->env.sched = sched;
2930 plug->env.my_identity = &my_identity;
2931 plug->env.cls = plug;
2932 plug->env.receive = &plugin_env_receive;
2933 plug->env.notify_address = &plugin_env_notify_address;
2934 plug->env.default_quota_in =
2935 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2936 plug->env.max_connections = max_connect_per_transport;
2941 * Start the specified transport (load the plugin).
2944 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2946 struct TransportPlugin *plug;
2949 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2950 _("Loading `%s' transport plugin\n"), name);
2951 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2952 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2953 create_environment (plug);
2954 plug->short_name = GNUNET_strdup (name);
2955 plug->lib_name = libname;
2956 plug->next = plugins;
2958 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2959 if (plug->api == NULL)
2961 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2962 _("Failed to load transport plugin for `%s'\n"), name);
2963 GNUNET_free (plug->short_name);
2964 plugins = plug->next;
2965 GNUNET_free (libname);
2972 * Called whenever a client is disconnected. Frees our
2973 * resources associated with that client.
2975 * @param cls closure
2976 * @param client identification of the client
2979 client_disconnect_notification (void *cls,
2980 struct GNUNET_SERVER_Client *client)
2982 struct TransportClient *pos;
2983 struct TransportClient *prev;
2984 struct ClientMessageQueueEntry *mqe;
2989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2990 "Client disconnected, cleaning up.\n");
2994 while ((pos != NULL) && (pos->client != client))
3001 while (NULL != (mqe = pos->message_queue_head))
3003 pos->message_queue_head = mqe->next;
3006 pos->message_queue_head = NULL;
3008 clients = pos->next;
3010 prev->next = pos->next;
3011 if (GNUNET_YES == pos->tcs_pending)
3021 * Iterator to free entries in the validation_map.
3023 * @param cls closure (unused)
3024 * @param key current key code
3025 * @param value value in the hash map (validation to abort)
3026 * @return GNUNET_YES (always)
3029 abort_validation (void *cls,
3030 const GNUNET_HashCode * key,
3033 struct ValidationEntry *va = value;
3035 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3036 GNUNET_free (va->transport_name);
3043 * Function called when the service shuts down. Unloads our plugins
3044 * and cancels pending validations.
3046 * @param cls closure, unused
3047 * @param tc task context (unused)
3050 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3052 struct TransportPlugin *plug;
3053 struct OwnAddressList *al;
3054 struct CheckHelloValidatedContext *chvc;
3057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3058 "Transport service is unloading plugins...\n");
3060 while (NULL != (plug = plugins))
3062 plugins = plug->next;
3063 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3064 GNUNET_free (plug->lib_name);
3065 GNUNET_free (plug->short_name);
3066 while (NULL != (al = plug->addresses))
3068 plug->addresses = al->next;
3073 if (my_private_key != NULL)
3074 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3075 GNUNET_free_non_null (our_hello);
3077 /* free 'chvc' data structure */
3078 while (NULL != (chvc = chvc_head))
3080 chvc_head = chvc->next;
3081 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3086 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3089 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3094 * Initiate transport service.
3096 * @param cls closure
3097 * @param s scheduler to use
3098 * @param serv the initialized server
3099 * @param c configuration to use
3103 struct GNUNET_SCHEDULER_Handle *s,
3104 struct GNUNET_SERVER_Handle *serv,
3105 const struct GNUNET_CONFIGURATION_Handle *c)
3110 unsigned long long tneigh;
3115 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3116 /* parse configuration */
3118 GNUNET_CONFIGURATION_get_value_number (c,
3123 GNUNET_CONFIGURATION_get_value_filename (c,
3125 "HOSTKEY", &keyfile)))
3127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3129 ("Transport service is lacking key configuration settings. Exiting.\n"));
3130 GNUNET_SCHEDULER_shutdown (s);
3133 max_connect_per_transport = (uint32_t) tneigh;
3134 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3135 GNUNET_free (keyfile);
3136 if (my_private_key == NULL)
3138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3140 ("Transport service could not access hostkey. Exiting.\n"));
3141 GNUNET_SCHEDULER_shutdown (s);
3144 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3145 GNUNET_CRYPTO_hash (&my_public_key,
3146 sizeof (my_public_key), &my_identity.hashPubKey);
3147 /* setup notification */
3149 GNUNET_SERVER_disconnect_notify (server,
3150 &client_disconnect_notification, NULL);
3151 /* load plugins... */
3154 GNUNET_CONFIGURATION_get_value_string (c,
3155 "TRANSPORT", "PLUGINS", &plugs))
3157 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3158 _("Starting transport plugins `%s'\n"), plugs);
3159 pos = strtok (plugs, " ");
3162 start_transport (server, pos);
3164 pos = strtok (NULL, " ");
3166 GNUNET_free (plugs);
3168 GNUNET_SCHEDULER_add_delayed (sched,
3169 GNUNET_TIME_UNIT_FOREVER_REL,
3170 &shutdown_task, NULL);
3175 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3177 /* process client requests */
3178 GNUNET_SERVER_add_handlers (server, handlers);
3183 * The main function for the transport service.
3185 * @param argc number of arguments from the command line
3186 * @param argv command line arguments
3187 * @return 0 ok, 1 on error
3190 main (int argc, char *const *argv)
3192 return (GNUNET_OK ==
3193 GNUNET_SERVICE_run (argc,
3196 GNUNET_SERVICE_OPTION_NONE,
3197 &run, NULL)) ? 0 : 1;
3200 /* end of gnunet-service-transport.c */