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)
94 * Priority to use for PONG messages.
96 #define TRANSPORT_PONG_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 * How long before an existing address expires should we again try to
114 * validate it? Must be (significantly) smaller than
115 * HELLO_ADDRESS_EXPIRATION.
117 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
121 * List of addresses of other peers
123 struct ForeignAddressList
126 * This is a linked list.
128 struct ForeignAddressList *next;
131 * Which ready list does this entry belong to.
133 struct ReadyList *ready_list;
136 * How long until we auto-expire this address (unless it is
137 * re-confirmed by the transport)?
139 struct GNUNET_TIME_Absolute expires;
152 * What was the last latency observed for this plugin
153 * and peer? Invalid if connected is GNUNET_NO.
155 struct GNUNET_TIME_Relative latency;
158 * If we did not successfully transmit a message to the given peer
159 * via this connection during the specified time, we should consider
160 * the connection to be dead. This is used in the case that a TCP
161 * transport simply stalls writing to the stream but does not
162 * formerly get a signal that the other peer died.
164 /* FIXME: Do we need this? */
165 struct GNUNET_TIME_Absolute timeout;
168 * Is this plugin currently connected? The first time we transmit
169 * or send data to a peer via a particular plugin, we set this to
170 * GNUNET_YES. If we later get an error (disconnect notification or
171 * transmission failure), we set it back to GNUNET_NO. Each time
172 * the value is set to GNUNET_YES, we increment the
173 * "connect_attempts" counter. If that one reaches a particular
174 * threshold, we consider the address to not be working properly at
175 * this time and remove it from the eligible list.
180 * Is this plugin ready to transmit to the specific target?
181 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
182 * transmission is in progress, "transmit_ready" is set to
188 * Has this address been validated yet?
193 * How often have we tried to connect using this plugin?
195 unsigned int connect_attempts;
201 * Entry in linked list of network addresses for ourselves.
203 struct OwnAddressList
206 * This is a linked list.
208 struct OwnAddressList *next;
211 * The address, actually a pointer to the end
212 * of this struct. Do not free!
217 * How long until we auto-expire this address (unless it is
218 * re-confirmed by the transport)?
220 struct GNUNET_TIME_Absolute expires;
231 * Entry in linked list of all of our plugins.
233 struct TransportPlugin
237 * This is a linked list.
239 struct TransportPlugin *next;
242 * API of the transport as returned by the plugin's
243 * initialization function.
245 struct GNUNET_TRANSPORT_PluginFunctions *api;
248 * Short name for the plugin (i.e. "tcp").
253 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
258 * List of our known addresses for this transport.
260 struct OwnAddressList *addresses;
263 * Environment this transport service is using
266 struct GNUNET_TRANSPORT_PluginEnvironment env;
269 * ID of task that is used to clean up expired addresses.
271 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
274 * Set to GNUNET_YES if we need to scrap the existing
275 * list of "addresses" and start fresh when we receive
276 * the next address update from a transport. Set to
277 * GNUNET_NO if we should just add the new address
278 * to the list and wait for the commit call.
287 * For each neighbor we keep a list of messages
288 * that we still want to transmit to the neighbor.
294 * This is a linked list.
296 struct MessageQueue *next;
299 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
300 * stuck together in memory. Allocated at the end of this struct.
302 const char *message_buf;
305 * Size of the message buf
307 size_t message_buf_size;
310 * Client responsible for queueing the message;
311 * used to check that a client has no two messages
312 * pending for the same target. Can be NULL.
314 struct TransportClient *client;
317 * Using which specific address should we send this message?
319 struct ForeignAddressList *specific_address;
322 * Peer ID of the Neighbor this entry belongs to.
324 struct GNUNET_PeerIdentity neighbor_id;
327 * Plugin that we used for the transmission.
328 * NULL until we scheduled a transmission.
330 struct TransportPlugin *plugin;
333 * Internal message of the transport system that should not be
334 * included in the usual SEND-SEND_OK transmission confirmation
335 * traffic management scheme. Typically, "internal_msg" will
336 * be set whenever "client" is NULL (but it is not strictly
342 * How important is the message?
344 unsigned int priority;
350 * For a given Neighbor, which plugins are available
351 * to talk to this peer and what are their costs?
356 * This is a linked list.
358 struct ReadyList *next;
361 * Which of our transport plugins does this entry
364 struct TransportPlugin *plugin;
367 * Transport addresses, latency, and readiness for
368 * this particular plugin.
370 struct ForeignAddressList *addresses;
373 * Is this plugin ready to transmit to the specific target?
374 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
375 * transmission is in progress, "transmit_ready" is set to
378 // FIXME: is this dead?
379 int plugin_transmit_ready;
382 * Is the plugin represented by this entry currently connected to
383 * the respective peer?
391 * Entry in linked list of all of our current neighbors.
397 * This is a linked list.
399 struct NeighborList *next;
402 * Which of our transports is connected to this peer
403 * and what is their status?
405 struct ReadyList *plugins;
408 * List of messages we would like to send to this peer;
409 * must contain at most one message per client.
411 struct MessageQueue *messages;
414 * Identity of this neighbor.
416 struct GNUNET_PeerIdentity id;
419 * ID of task scheduled to run when this peer is about to
420 * time out (will free resources associated with the peer).
422 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
425 * How long until we should consider this peer dead
426 * (if we don't receive another message in the
429 struct GNUNET_TIME_Absolute peer_timeout;
432 * At what time did we reset last_received last?
434 struct GNUNET_TIME_Absolute last_quota_update;
437 * The latency we have seen for this particular address for
438 * this particular peer. This latency may have been calculated
439 * over multiple transports. This value reflects how long it took
440 * us to receive a response when SENDING via this particular
441 * transport/neighbor/address combination!
442 * FIXME: why is this NBO?
444 struct GNUNET_TIME_RelativeNBO latency;
447 * How many bytes have we received since the "last_quota_update"
450 uint64_t last_received;
453 * Global quota for inbound traffic for the neighbor in bytes/ms.
458 * How often has the other peer (recently) violated the
459 * inbound traffic limit? Incremented by 10 per violation,
460 * decremented by 1 per non-violation (for each
463 unsigned int quota_violation_count;
466 * Have we seen an ACK from this neighbor in the past?
467 * (used to make up a fake ACK for clients connecting after
468 * the neighbor connected to us).
475 * Message used to ask a peer to validate receipt (to check an address
476 * from a HELLO). Followed by the address used. Note that the
477 * recipients response does not affirm that he has this address,
478 * only that he got the challenge message.
480 struct TransportPingMessage
484 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
486 struct GNUNET_MessageHeader header;
489 * Random challenge number (in network byte order).
491 uint32_t challenge GNUNET_PACKED;
494 * Who is the intended recipient?
496 struct GNUNET_PeerIdentity target;
502 * Message used to validate a HELLO. The challenge is included in the
503 * confirmation to make matching of replies to requests possible. The
504 * signature signs the original challenge number, our public key, the
505 * sender's address (so that the sender can check that the address we
506 * saw is plausible for him and possibly detect a MiM attack) and a
507 * timestamp (to limit replay).<p>
509 * This message is followed by the address of the
510 * client that we are observing (which is part of what
513 struct TransportPongMessage
517 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
519 struct GNUNET_MessageHeader header;
522 * For padding, always zero.
524 uint32_t reserved GNUNET_PACKED;
529 struct GNUNET_CRYPTO_RsaSignature signature;
532 * What are we signing and why?
534 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
537 * Random challenge number (in network byte order).
539 uint32_t challenge GNUNET_PACKED;
542 * Who signed this message?
544 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
547 * Size of address appended to this message
554 * Linked list of messages to be transmitted to
555 * the client. Each entry is followed by the
558 struct ClientMessageQueueEntry
561 * This is a linked list.
563 struct ClientMessageQueueEntry *next;
568 * Client connected to the transport service.
570 struct TransportClient
574 * This is a linked list.
576 struct TransportClient *next;
579 * Handle to the client.
581 struct GNUNET_SERVER_Client *client;
584 * Linked list of messages yet to be transmitted to
587 struct ClientMessageQueueEntry *message_queue_head;
590 * Tail of linked list of messages yet to be transmitted to the
593 struct ClientMessageQueueEntry *message_queue_tail;
596 * Is a call to "transmit_send_continuation" pending? If so, we
597 * must not free this struct (even if the corresponding client
598 * disconnects) and instead only remove it from the linked list and
599 * set the "client" field to NULL.
604 * Length of the list of messages pending for this client.
606 unsigned int message_count;
612 * Entry in map of all HELLOs awaiting validation.
614 struct ValidationEntry
618 * The address, actually a pointer to the end
619 * of this struct. Do not free!
624 * Name of the transport.
626 char *transport_name;
629 * The public key of the peer.
631 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
634 * ID of task that will clean up this entry if we don't succeed
635 * with the validation first.
637 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
640 * At what time did we send this validation?
642 struct GNUNET_TIME_Absolute send_time;
650 * Challenge number we used.
658 * Context of currently active requests to peerinfo
659 * for validation of HELLOs.
661 struct CheckHelloValidatedContext
665 * This is a doubly-linked list.
667 struct CheckHelloValidatedContext *next;
670 * This is a doubly-linked list.
672 struct CheckHelloValidatedContext *prev;
675 * Hello that we are validating.
677 const struct GNUNET_HELLO_Message *hello;
680 * Context for peerinfo iteration.
681 * NULL after we are done processing peerinfo's information.
683 struct GNUNET_PEERINFO_IteratorContext *piter;
686 * Was a HELLO known for this peer to peerinfo?
696 static struct GNUNET_HELLO_Message *our_hello;
699 * "version" of "our_hello". Used to see if a given neighbor has
700 * already been sent the latest version of our HELLO message.
702 static unsigned int our_hello_version;
707 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
712 static struct GNUNET_PeerIdentity my_identity;
717 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
722 struct GNUNET_SCHEDULER_Handle *sched;
727 const struct GNUNET_CONFIGURATION_Handle *cfg;
730 * Linked list of all clients to this service.
732 static struct TransportClient *clients;
735 * All loaded plugins.
737 static struct TransportPlugin *plugins;
742 static struct GNUNET_SERVER_Handle *server;
745 * All known neighbors and their HELLOs.
747 static struct NeighborList *neighbors;
750 * Number of neighbors we'd like to have.
752 static uint32_t max_connect_per_transport;
755 * Head of linked list.
757 static struct CheckHelloValidatedContext *chvc_head;
760 * Tail of linked list.
762 static struct CheckHelloValidatedContext *chvc_tail;
766 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
767 * of the given peer that we are currently validating).
769 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
774 * The peer specified by the given neighbor has timed-out or a plugin
775 * has disconnected. We may either need to do nothing (other plugins
776 * still up), or trigger a full disconnect and clean up. This
777 * function updates our state and do the necessary notifications.
778 * Also notifies our clients that the neighbor is now officially
781 * @param n the neighbor list entry for the peer
782 * @param check should we just check if all plugins
783 * disconnected or must we ask all plugins to
786 static void disconnect_neighbor (struct NeighborList *n, int check);
789 * Check the ready list for the given neighbor and if a plugin is
790 * ready for transmission (and if we have a message), do so!
792 * @param neighbor target peer for which to transmit
794 static void try_transmission_to_peer (struct NeighborList *neighbor);
798 * Find an entry in the neighbor list for a particular peer.
799 * if sender_address is not specified (NULL) then return the
800 * first matching entry. If sender_address is specified, then
801 * make sure that the address and address_len also matches.
803 * @return NULL if not found.
805 static struct NeighborList *
806 find_neighbor (const struct GNUNET_PeerIdentity *key)
808 struct NeighborList *head = neighbors;
810 while ((head != NULL) &&
811 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
818 * Find an entry in the transport list for a particular transport.
820 * @return NULL if not found.
822 static struct TransportPlugin *
823 find_transport (const char *short_name)
825 struct TransportPlugin *head = plugins;
826 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
833 * Update the quota values for the given neighbor now.
836 update_quota (struct NeighborList *n)
838 struct GNUNET_TIME_Relative delta;
842 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
843 if (delta.value < MIN_QUOTA_REFRESH_TIME)
844 return; /* not enough time passed for doing quota update */
845 allowed = delta.value * n->quota_in;
847 if (n->last_received < allowed)
849 remaining = allowed - n->last_received;
851 remaining /= n->quota_in;
854 if (remaining > MAX_BANDWIDTH_CARRY)
855 remaining = MAX_BANDWIDTH_CARRY;
856 n->last_received = 0;
857 n->last_quota_update = GNUNET_TIME_absolute_get ();
858 n->last_quota_update.value -= remaining;
859 if (n->quota_violation_count > 0)
860 n->quota_violation_count--;
864 n->last_received -= allowed;
865 n->last_quota_update = GNUNET_TIME_absolute_get ();
866 if (n->last_received > allowed)
868 /* more than twice the allowed rate! */
869 n->quota_violation_count += 10;
876 * Function called to notify a client about the socket being ready to
877 * queue more data. "buf" will be NULL and "size" zero if the socket
878 * was closed for writing in the meantime.
881 * @param size number of bytes available in buf
882 * @param buf where the callee should write the message
883 * @return number of bytes written to buf
886 transmit_to_client_callback (void *cls, size_t size, void *buf)
888 struct TransportClient *client = cls;
889 struct ClientMessageQueueEntry *q;
892 const struct GNUNET_MessageHeader *msg;
893 struct GNUNET_CONNECTION_TransmitHandle *th;
898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
899 "Transmission to client failed, closing connection.\n");
900 /* fatal error with client, free message queue! */
901 while (NULL != (q = client->message_queue_head))
903 client->message_queue_head = q->next;
906 client->message_queue_tail = NULL;
907 client->message_count = 0;
912 while (NULL != (q = client->message_queue_head))
914 msg = (const struct GNUNET_MessageHeader *) &q[1];
915 msize = ntohs (msg->size);
916 if (msize + tsize > size)
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Transmitting message of type %u to client.\n",
923 client->message_queue_head = q->next;
925 client->message_queue_tail = NULL;
926 memcpy (&cbuf[tsize], msg, msize);
929 client->message_count--;
933 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
934 th = GNUNET_SERVER_notify_transmit_ready (client->client,
936 GNUNET_TIME_UNIT_FOREVER_REL,
937 &transmit_to_client_callback,
939 GNUNET_assert (th != NULL);
946 * Send the specified message to the specified client. Since multiple
947 * messages may be pending for the same client at a time, this code
948 * makes sure that no message is lost.
950 * @param client client to transmit the message to
951 * @param msg the message to send
952 * @param may_drop can this message be dropped if the
953 * message queue for this client is getting far too large?
956 transmit_to_client (struct TransportClient *client,
957 const struct GNUNET_MessageHeader *msg, int may_drop)
959 struct ClientMessageQueueEntry *q;
961 struct GNUNET_CONNECTION_TransmitHandle *th;
963 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
965 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
967 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
968 client->message_count, MAX_PENDING);
969 /* TODO: call to statistics... */
972 client->message_count++;
973 msize = ntohs (msg->size);
974 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
975 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
976 memcpy (&q[1], msg, msize);
977 /* append to message queue */
978 if (client->message_queue_tail == NULL)
980 client->message_queue_tail = q;
984 client->message_queue_tail->next = q;
985 client->message_queue_tail = q;
987 if (client->message_queue_head == NULL)
989 client->message_queue_head = q;
990 th = GNUNET_SERVER_notify_transmit_ready (client->client,
992 GNUNET_TIME_UNIT_FOREVER_REL,
993 &transmit_to_client_callback,
995 GNUNET_assert (th != NULL);
1001 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1002 * upon "completion" of a send request. This tells the API
1003 * that it is now legal to send another message to the given
1006 * @param cls closure, identifies the entry on the
1007 * message queue that was transmitted and the
1008 * client responsible for queueing the message
1009 * @param target the peer receiving the message
1010 * @param result GNUNET_OK on success, if the transmission
1011 * failed, we should not tell the client to transmit
1015 transmit_send_continuation (void *cls,
1016 const struct GNUNET_PeerIdentity *target,
1019 struct MessageQueue *mq = cls;
1020 /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1021 struct SendOkMessage send_ok_msg;
1022 struct NeighborList *n;
1024 GNUNET_assert (mq != NULL);
1025 n = find_neighbor(&mq->neighbor_id);
1026 if (n == NULL) /* Neighbor must have been removed asynchronously! */
1029 /* Otherwise, let's make sure we've got the right peer */
1031 memcmp (&n->id, target,
1032 sizeof (struct GNUNET_PeerIdentity)));
1034 if (result == GNUNET_OK)
1036 mq->specific_address->timeout =
1037 GNUNET_TIME_relative_to_absolute
1038 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043 "Transmission to peer `%s' failed, marking connection as down.\n",
1044 GNUNET_i2s (target));
1045 mq->specific_address->connected = GNUNET_NO;
1047 if (!mq->internal_msg)
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Setting transmit_ready on transport!\n");
1053 mq->specific_address->transmit_ready = GNUNET_YES;
1056 if (mq->client != NULL)
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "Notifying client %p about transmission to peer `%4s'.\n",
1060 mq->client, GNUNET_i2s (target));
1061 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1062 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1063 send_ok_msg.success = htonl (result);
1064 send_ok_msg.peer = n->id;
1065 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1068 /* one plugin just became ready again, try transmitting
1069 another message (if available) */
1070 if (result == GNUNET_OK)
1071 try_transmission_to_peer (n);
1073 disconnect_neighbor (n, GNUNET_YES);
1078 * Find an address in any of the available transports for
1079 * the given neighbor that would be good for message
1080 * transmission. This is essentially the transport selection
1083 * @param neighbor for whom to select an address
1084 * @return selected address, NULL if we have none
1086 struct ForeignAddressList *
1087 find_ready_address(struct NeighborList *neighbor)
1089 struct ReadyList *head = neighbor->plugins;
1090 struct ForeignAddressList *addresses;
1091 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1092 struct ForeignAddressList *best_address;
1094 best_address = NULL;
1095 while (head != NULL)
1097 addresses = head->addresses;
1098 while (addresses != NULL)
1100 if ( (addresses->timeout.value < now.value) &&
1101 (addresses->connected == GNUNET_YES) )
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "Marking long-time inactive connection to `%4s' as down.\n",
1106 GNUNET_i2s (&neighbor->id));
1108 addresses->connected = GNUNET_NO;
1110 addresses = addresses->next;
1113 addresses = head->addresses;
1114 while (addresses != NULL)
1116 if ( ( (best_address == NULL) ||
1117 (addresses->connected == GNUNET_YES) ||
1118 (best_address->connected == GNUNET_NO) ) &&
1119 (addresses->transmit_ready == GNUNET_YES) &&
1120 ( (best_address == NULL) ||
1121 (addresses->latency.value < best_address->latency.value)) )
1122 best_address = addresses;
1123 /* FIXME: also give lower-latency addresses that are not
1124 connected a chance some times... */
1125 addresses = addresses->next;
1130 if (best_address != NULL)
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Best address found has latency of %llu ms.\n",
1134 best_address->latency.value);
1137 return best_address;
1143 * Check the ready list for the given neighbor and if a plugin is
1144 * ready for transmission (and if we have a message), do so!
1146 * @param neighbor target peer for which to transmit
1149 try_transmission_to_peer (struct NeighborList *neighbor)
1151 struct GNUNET_TIME_Relative min_latency;
1152 struct ReadyList *rl;
1153 struct MessageQueue *mq;
1155 if (neighbor->messages == NULL)
1156 return; /* nothing to do */
1157 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1159 mq = neighbor->messages;
1160 if (mq->specific_address == NULL)
1161 mq->specific_address = find_ready_address(neighbor);
1162 if (mq->specific_address == NULL)
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1166 "No destination address available to transmit message of size %u to peer `%4s'\n",
1167 mq->message_buf_size,
1168 GNUNET_i2s (&mq->neighbor_id));
1170 return; /* nobody ready */
1172 rl = mq->specific_address->ready_list;
1173 neighbor->messages = mq->next;
1174 mq->plugin = rl->plugin;
1175 if (!mq->internal_msg)
1176 mq->specific_address->transmit_ready = GNUNET_NO;
1178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1180 mq->message_buf_size,
1181 GNUNET_i2s (&neighbor->id),
1182 GNUNET_a2s (mq->specific_address->addr,
1183 mq->specific_address->addrlen),
1184 rl->plugin->short_name);
1186 rl->plugin->api->send (rl->plugin->api->cls,
1189 mq->message_buf_size,
1191 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1192 mq->specific_address->addr,
1193 mq->specific_address->addrlen,
1194 GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1195 &transmit_send_continuation, mq);
1200 * Send the specified message to the specified peer.
1202 * @param client source of the transmission request (can be NULL)
1203 * @param peer_address ForeignAddressList where we should send this message
1204 * @param priority how important is the message
1205 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1206 * @param message_buf_size total size of all messages in message_buf
1207 * @param is_internal is this an internal message
1208 * @param neighbor handle to the neighbor for transmission
1211 transmit_to_peer (struct TransportClient *client,
1212 struct ForeignAddressList *peer_address,
1213 unsigned int priority,
1214 const char *message_buf,
1215 size_t message_buf_size,
1216 int is_internal, struct NeighborList *neighbor)
1218 struct MessageQueue *mq;
1219 struct MessageQueue *mqe;
1223 /* check for duplicate submission */
1224 mq = neighbor->messages;
1227 if (mq->client == client)
1229 /* client transmitted to same peer twice
1230 before getting SendOk! */
1237 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1238 mq->specific_address = peer_address;
1239 mq->client = client;
1240 memcpy (&mq[1], message_buf, message_buf_size);
1241 mq->message_buf = (const char*) &mq[1];
1242 mq->message_buf_size = message_buf_size;
1243 memcpy(&mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1244 mq->internal_msg = is_internal;
1245 mq->priority = priority;
1249 /* append at head */
1250 mq->next = neighbor->messages;
1251 neighbor->messages = mq;
1256 mqe = neighbor->messages;
1258 while (mqe->next != NULL)
1263 neighbor->messages = mq;
1271 try_transmission_to_peer (neighbor);
1278 struct GeneratorContext
1280 struct TransportPlugin *plug_pos;
1281 struct OwnAddressList *addr_pos;
1282 struct GNUNET_TIME_Absolute expiration;
1290 address_generator (void *cls, size_t max, void *buf)
1292 struct GeneratorContext *gc = cls;
1295 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1297 gc->plug_pos = gc->plug_pos->next;
1298 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1300 if (NULL == gc->plug_pos)
1305 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1308 gc->addr_pos->addrlen, buf, max);
1309 gc->addr_pos = gc->addr_pos->next;
1315 * Construct our HELLO message from all of the addresses of
1316 * all of the transports.
1321 struct GNUNET_HELLO_Message *hello;
1322 struct TransportClient *cpos;
1323 struct NeighborList *npos;
1324 struct GeneratorContext gc;
1326 gc.plug_pos = plugins;
1327 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1328 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1329 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1332 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1335 while (cpos != NULL)
1337 transmit_to_client (cpos,
1338 (const struct GNUNET_MessageHeader *) hello,
1343 GNUNET_free_non_null (our_hello);
1345 our_hello_version++;
1346 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1348 while (npos != NULL)
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1352 "Transmitting updated `%s' to neighbor `%4s'\n",
1353 "HELLO", GNUNET_i2s (&npos->id));
1355 transmit_to_peer (NULL, NULL, 0,
1356 (const char *) our_hello,
1357 GNUNET_HELLO_size(our_hello),
1365 * Task used to clean up expired addresses for a plugin.
1367 * @param cls closure
1371 expire_address_task (void *cls,
1372 const struct GNUNET_SCHEDULER_TaskContext *tc);
1376 * Update the list of addresses for this plugin,
1377 * expiring those that are past their expiration date.
1379 * @param plugin addresses of which plugin should be recomputed?
1380 * @param fresh set to GNUNET_YES if a new address was added
1381 * and we need to regenerate the HELLO even if nobody
1385 update_addresses (struct TransportPlugin *plugin, int fresh)
1387 struct GNUNET_TIME_Relative min_remaining;
1388 struct GNUNET_TIME_Relative remaining;
1389 struct GNUNET_TIME_Absolute now;
1390 struct OwnAddressList *pos;
1391 struct OwnAddressList *prev;
1392 struct OwnAddressList *next;
1395 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1396 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1397 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1398 now = GNUNET_TIME_absolute_get ();
1399 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1400 expired = GNUNET_NO;
1402 pos = plugin->addresses;
1406 if (pos->expires.value < now.value)
1408 expired = GNUNET_YES;
1410 plugin->addresses = pos->next;
1412 prev->next = pos->next;
1417 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1418 if (remaining.value < min_remaining.value)
1419 min_remaining = remaining;
1425 if (expired || fresh)
1427 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1428 plugin->address_update_task
1429 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1431 &expire_address_task, plugin);
1437 * Task used to clean up expired addresses for a plugin.
1439 * @param cls closure
1443 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1445 struct TransportPlugin *plugin = cls;
1446 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1447 update_addresses (plugin, GNUNET_NO);
1452 * Function that must be called by each plugin to notify the
1453 * transport service about the addresses under which the transport
1454 * provided by the plugin can be reached.
1456 * @param cls closure
1457 * @param name name of the transport that generated the address
1458 * @param addr one of the addresses of the host, NULL for the last address
1459 * the specific address format depends on the transport
1460 * @param addrlen length of the address
1461 * @param expires when should this address automatically expire?
1464 plugin_env_notify_address (void *cls,
1468 struct GNUNET_TIME_Relative expires)
1470 struct TransportPlugin *p = cls;
1471 struct OwnAddressList *al;
1472 struct GNUNET_TIME_Absolute abex;
1474 abex = GNUNET_TIME_relative_to_absolute (expires);
1475 GNUNET_assert (p == find_transport (name));
1480 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1482 if (al->expires.value < abex.value)
1489 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1491 al->next = p->addresses;
1494 al->addrlen = addrlen;
1495 memcpy (&al[1], addr, addrlen);
1496 update_addresses (p, GNUNET_YES);
1501 * Notify all of our clients about a peer connecting.
1504 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1505 struct GNUNET_TIME_Relative latency)
1507 struct ConnectInfoMessage cim;
1508 struct TransportClient *cpos;
1510 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1511 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1512 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1513 cim.latency = GNUNET_TIME_relative_hton (latency);
1514 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1516 while (cpos != NULL)
1518 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1525 * Notify all of our clients about a peer disconnecting.
1528 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1530 struct DisconnectInfoMessage dim;
1531 struct TransportClient *cpos;
1533 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1534 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1535 dim.reserved = htonl (0);
1536 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1538 while (cpos != NULL)
1540 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1547 * Find a ForeignAddressList entry for the given neighbour
1548 * that matches the given address and transport.
1550 * @param neighbor which peer we care about
1551 * @param tname name of the transport plugin
1552 * @param addr binary address
1553 * @param addrlen length of addr
1554 * @return NULL if no such entry exists
1556 static struct ForeignAddressList *
1557 find_peer_address(struct NeighborList *neighbor,
1562 struct ReadyList *head;
1563 struct ForeignAddressList *address_head;
1565 head = neighbor->plugins;
1566 while (head != NULL)
1568 if (0 == strcmp (tname, head->plugin->short_name))
1575 address_head = head->addresses;
1576 while ( (address_head != NULL) &&
1577 ( (address_head->addrlen != addrlen) ||
1578 (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1579 address_head = address_head->next;
1580 return address_head;
1585 * Get the peer address struct for the given neighbor and
1586 * address. If it doesn't yet exist, create it.
1588 * @param neighbor which peer we care about
1589 * @param tname name of the transport plugin
1590 * @param addr binary address
1591 * @param addrlen length of addr
1592 * @return NULL if we do not have a transport plugin for 'tname'
1594 static struct ForeignAddressList *
1595 add_peer_address(struct NeighborList *neighbor,
1600 struct ReadyList *head;
1601 struct ForeignAddressList *ret;
1603 ret = find_peer_address (neighbor, tname, addr, addrlen);
1606 head = neighbor->plugins;
1607 while (head != NULL)
1609 if (0 == strcmp (tname, head->plugin->short_name))
1615 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1616 ret->addr = (const char*) &ret[1];
1617 memcpy (&ret[1], addr, addrlen);
1618 ret->addrlen = addrlen;
1619 ret->expires = GNUNET_TIME_relative_to_absolute
1620 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1621 ret->latency = GNUNET_TIME_relative_get_forever();
1622 ret->transmit_ready = GNUNET_YES;
1623 ret->timeout = GNUNET_TIME_relative_to_absolute
1624 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1625 ret->ready_list = head;
1626 ret->next = head->addresses;
1627 head->addresses = ret;
1633 * Closure for 'add_validated_address'.
1635 struct AddValidatedAddressContext
1638 * Entry that has been validated.
1640 const struct ValidationEntry *ve;
1643 * Flag set after we have added the address so
1644 * that we terminate the iteration next time.
1651 * Callback function used to fill a buffer of max bytes with a list of
1652 * addresses in the format used by HELLOs. Should use
1653 * "GNUNET_HELLO_add_address" as a helper function.
1655 * @param cls the 'struct AddValidatedAddressContext' with the validated address
1656 * @param max maximum number of bytes that can be written to buf
1657 * @param buf where to write the address information
1658 * @return number of bytes written, 0 to signal the
1659 * end of the iteration.
1662 add_validated_address (void *cls,
1663 size_t max, void *buf)
1665 struct AddValidatedAddressContext *avac = cls;
1666 const struct ValidationEntry *ve = avac->ve;
1668 if (GNUNET_YES == avac->done)
1670 avac->done = GNUNET_YES;
1671 return GNUNET_HELLO_add_address (ve->transport_name,
1672 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1681 * Iterator over hash map entries. Checks if the given
1682 * validation entry is for the same challenge as what
1683 * is given in the PONG.
1685 * @param cls the 'struct TransportPongMessage*'
1686 * @param key peer identity
1687 * @param value value in the hash map ('struct ValidationEntry')
1688 * @return GNUNET_YES if we should continue to
1689 * iterate (mismatch), GNUNET_NO if not (entry matched)
1692 check_pending_validation (void *cls,
1693 const GNUNET_HashCode * key,
1696 const struct TransportPongMessage *pong = cls;
1697 struct ValidationEntry *ve = value;
1698 struct AddValidatedAddressContext avac;
1699 unsigned int challenge = ntohl(pong->challenge);
1700 struct GNUNET_HELLO_Message *hello;
1701 struct GNUNET_PeerIdentity target;
1702 struct NeighborList *n;
1703 struct ForeignAddressList *fal;
1705 if (ve->challenge != challenge)
1709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1710 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
1712 GNUNET_a2s ((const struct sockaddr *) ve->addr,
1714 ve->transport_name);
1716 /* create the updated HELLO */
1717 GNUNET_CRYPTO_hash (&ve->publicKey,
1718 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1719 &target.hashPubKey);
1720 avac.done = GNUNET_NO;
1722 hello = GNUNET_HELLO_create (&ve->publicKey,
1723 &add_validated_address,
1725 GNUNET_PEERINFO_add_peer (cfg, sched,
1728 GNUNET_free (hello);
1729 n = find_neighbor (&target);
1732 fal = add_peer_address (n, ve->transport_name,
1735 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1736 fal->validated = GNUNET_YES;
1737 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
1740 /* clean up validation entry */
1741 GNUNET_assert (GNUNET_YES ==
1742 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1745 GNUNET_SCHEDULER_cancel (sched,
1747 GNUNET_free (ve->transport_name);
1754 * Function that will be called if we receive a validation
1755 * of an address challenge that we transmitted to another
1756 * peer. Note that the validation should only be considered
1757 * acceptable if the challenge matches AND if the sender
1758 * address is at least a plausible address for this peer
1759 * (otherwise we may be seeing a MiM attack).
1761 * @param cls closure
1762 * @param name name of the transport that generated the address
1763 * @param peer who responded to our challenge
1764 * @param challenge the challenge number we presumably used
1765 * @param sender_addr string describing our sender address (as observed
1766 * by the other peer in human-readable format)
1769 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1770 const struct GNUNET_PeerIdentity *peer,
1771 const char *sender_address,
1772 size_t sender_address_len)
1774 #if DEBUG_TRANSPORT > 1
1775 /* we get tons of these that just get discarded, only log
1776 if we are quite verbose */
1777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1778 "Receiving `%s' message from `%4s'.\n", "PONG",
1781 if (GNUNET_SYSERR !=
1782 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1784 &check_pending_validation,
1787 /* This is *expected* to happen a lot since we send
1788 PONGs to *all* known addresses of the sender of
1789 the PING, so most likely we get multiple PONGs
1790 per PING, and all but the first PONG will end up
1791 here. So really we should not print anything here
1792 unless we want to be very, very verbose... */
1793 #if DEBUG_TRANSPORT > 2
1794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1795 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
1803 /* FIXME: add given address to potential pool of our addresses
1805 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1806 _("Another peer saw us using the address `%s' via `%s'.\n"),
1807 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1808 ntohs(pong->addrlen)),
1809 va->transport_name);
1815 neighbor_timeout_task (void *cls,
1816 const struct GNUNET_SCHEDULER_TaskContext *tc)
1818 struct NeighborList *n = cls;
1821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1822 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1824 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1825 disconnect_neighbor (n, GNUNET_NO);
1830 * Create a fresh entry in our neighbor list for the given peer.
1831 * Will try to transmit our current HELLO to the new neighbor. Also
1832 * notifies our clients about the new "connection".
1834 * @param peer the peer for which we create the entry
1835 * @return the new neighbor list entry
1837 static struct NeighborList *
1838 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1840 struct NeighborList *n;
1841 struct TransportPlugin *tp;
1842 struct ReadyList *rl;
1844 GNUNET_assert (our_hello != NULL);
1845 n = GNUNET_malloc (sizeof (struct NeighborList));
1846 n->next = neighbors;
1849 n->last_quota_update = GNUNET_TIME_absolute_get ();
1851 GNUNET_TIME_relative_to_absolute
1852 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1853 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1857 if (tp->api->send != NULL)
1859 rl = GNUNET_malloc (sizeof (struct ReadyList));
1860 rl->next = n->plugins;
1863 rl->addresses = NULL;
1867 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1868 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1869 &neighbor_timeout_task, n);
1870 transmit_to_peer (NULL, NULL, 0,
1871 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1873 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1879 * Closure for 'check_address_exists'.
1881 struct CheckAddressExistsClosure
1884 * Address to check for.
1889 * Name of the transport.
1899 * Set to GNUNET_YES if the address exists.
1906 * Iterator over hash map entries. Checks if the given
1907 * validation entry is for the same address as what is given
1910 * @param cls the 'struct CheckAddressExistsClosure*'
1911 * @param key current key code (ignored)
1912 * @param value value in the hash map ('struct ValidationEntry')
1913 * @return GNUNET_YES if we should continue to
1914 * iterate (mismatch), GNUNET_NO if not (entry matched)
1917 check_address_exists (void *cls,
1918 const GNUNET_HashCode * key,
1921 struct CheckAddressExistsClosure *caec = cls;
1922 struct ValidationEntry *ve = value;
1923 if ( (0 == strcmp (caec->tname,
1924 ve->transport_name)) &&
1925 (caec->addrlen == ve->addrlen) &&
1926 (0 == memcmp (caec->addr,
1930 caec->exists = GNUNET_YES;
1938 * HELLO validation cleanup task (validation failed).
1940 * @param cls the 'struct ValidationEntry' that failed
1941 * @param tc scheduler context (unused)
1944 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1946 struct ValidationEntry *va = cls;
1947 struct GNUNET_PeerIdentity pid;
1949 GNUNET_CRYPTO_hash (&va->publicKey,
1951 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1953 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1956 GNUNET_free (va->transport_name);
1962 * Check if the given address is already being validated; if not,
1963 * append the given address to the list of entries that are being be
1964 * validated and initiate validation.
1966 * @param cls closure ('struct CheckHelloValidatedContext *')
1967 * @param tname name of the transport
1968 * @param expiration expiration time
1969 * @param addr the address
1970 * @param addrlen length of the address
1971 * @return GNUNET_OK (always)
1974 run_validation (void *cls,
1976 struct GNUNET_TIME_Absolute expiration,
1977 const void *addr, size_t addrlen)
1979 struct CheckHelloValidatedContext *chvc = cls;
1980 struct GNUNET_PeerIdentity id;
1981 struct TransportPlugin *tp;
1982 struct ValidationEntry *va;
1983 struct NeighborList *neighbor;
1984 struct ForeignAddressList *peer_address;
1985 struct TransportPingMessage ping;
1986 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
1987 struct CheckAddressExistsClosure caec;
1989 uint16_t hello_size;
1992 tp = find_transport (tname);
1995 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1996 GNUNET_ERROR_TYPE_BULK,
1998 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2002 GNUNET_HELLO_get_key (chvc->hello, &pk);
2003 GNUNET_CRYPTO_hash (&pk,
2005 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2008 caec.addrlen = addrlen;
2010 caec.exists = GNUNET_NO;
2011 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2012 &check_address_exists,
2014 if (caec.exists == GNUNET_YES)
2016 /* During validation attempts we will likely trigger the other
2017 peer trying to validate our address which in turn will cause
2018 it to send us its HELLO, so we expect to hit this case rather
2019 frequently. Only print something if we are very verbose. */
2020 #if DEBUG_TRANSPORT > 1
2021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2022 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2023 GNUNET_a2s (addr, addrlen),
2029 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2030 va->transport_name = GNUNET_strdup (tname);
2031 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2033 va->send_time = GNUNET_TIME_absolute_get();
2034 va->addr = (const void*) &va[1];
2035 memcpy (&va[1], addr, addrlen);
2036 va->addrlen = addrlen;
2037 GNUNET_HELLO_get_key (chvc->hello,
2039 va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2040 HELLO_VERIFICATION_TIMEOUT,
2041 &timeout_hello_validation,
2043 GNUNET_CONTAINER_multihashmap_put (validation_map,
2046 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2047 neighbor = find_neighbor(&id);
2048 if (neighbor == NULL)
2049 neighbor = setup_new_neighbor(&id);
2050 peer_address = add_peer_address(neighbor, tname, addr, addrlen);
2051 GNUNET_assert(peer_address != NULL);
2052 hello_size = GNUNET_HELLO_size(our_hello);
2053 tsize = sizeof(struct TransportPingMessage) + hello_size;
2054 message_buf = GNUNET_malloc(tsize);
2055 ping.challenge = htonl(va->challenge);
2056 ping.header.size = htons(sizeof(struct TransportPingMessage));
2057 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2058 memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2059 memcpy(message_buf, our_hello, hello_size);
2060 memcpy(&message_buf[hello_size],
2062 sizeof(struct TransportPingMessage));
2064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2065 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2066 GNUNET_a2s (addr, addrlen),
2069 "HELLO", hello_size,
2070 "PING", sizeof (struct TransportPingMessage));
2072 transmit_to_peer(NULL, peer_address,
2073 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2075 GNUNET_YES, neighbor);
2076 GNUNET_free(message_buf);
2082 * Add the given address to the list of foreign addresses
2083 * available for the given peer (check for duplicates).
2085 * @param cls the respective 'struct NeighborList' to update
2086 * @param tname name of the transport
2087 * @param expiration expiration time
2088 * @param addr the address
2089 * @param addrlen length of the address
2090 * @return GNUNET_OK (always)
2093 add_to_foreign_address_list (void *cls,
2095 struct GNUNET_TIME_Absolute expiration,
2096 const void *addr, size_t addrlen)
2098 struct NeighborList *n = cls;
2099 struct ForeignAddressList *fal;
2101 fal = find_peer_address (n, tname, addr, addrlen);
2105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2106 "Adding address `%s' (%s) for peer `%4s' due to peerinfo data.\n",
2107 GNUNET_a2s (addr, addrlen),
2109 GNUNET_i2s (&n->id));
2111 fal = add_peer_address (n, tname, addr, addrlen);
2113 fal->expires = GNUNET_TIME_absolute_max (expiration,
2115 fal->validated = GNUNET_YES;
2121 * Check if addresses in validated hello "h" overlap with
2122 * those in "chvc->hello" and validate the rest.
2124 * @param cls closure
2125 * @param peer id of the peer, NULL for last call
2126 * @param hello hello message for the peer (can be NULL)
2127 * @param trust amount of trust we have in the peer (not used)
2130 check_hello_validated (void *cls,
2131 const struct GNUNET_PeerIdentity *peer,
2132 const struct GNUNET_HELLO_Message *h,
2135 struct CheckHelloValidatedContext *chvc = cls;
2136 struct GNUNET_HELLO_Message *plain_hello;
2137 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2138 struct GNUNET_PeerIdentity target;
2139 struct NeighborList *n;
2144 GNUNET_CONTAINER_DLL_remove (chvc_head,
2147 if (GNUNET_NO == chvc->hello_known)
2149 /* notify PEERINFO about the peer now, so that we at least
2150 have the public key if some other component needs it */
2151 GNUNET_HELLO_get_key (chvc->hello, &pk);
2152 GNUNET_CRYPTO_hash (&pk,
2153 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2154 &target.hashPubKey);
2155 plain_hello = GNUNET_HELLO_create (&pk,
2158 GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2159 GNUNET_free (plain_hello);
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2162 "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2164 GNUNET_i2s (&target));
2166 GNUNET_HELLO_iterate_addresses (chvc->hello,
2176 chvc->hello_known = GNUNET_YES;
2177 n = find_neighbor (peer);
2179 GNUNET_HELLO_iterate_addresses (h,
2181 &add_to_foreign_address_list,
2183 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2185 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2191 * Process HELLO-message.
2193 * @param plugin transport involved, may be NULL
2194 * @param message the actual message
2195 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2198 process_hello (struct TransportPlugin *plugin,
2199 const struct GNUNET_MessageHeader *message)
2202 struct GNUNET_PeerIdentity target;
2203 const struct GNUNET_HELLO_Message *hello;
2204 struct CheckHelloValidatedContext *chvc;
2205 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2207 hsize = ntohs (message->size);
2208 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2209 (hsize < sizeof (struct GNUNET_MessageHeader)))
2212 return GNUNET_SYSERR;
2214 /* first, check if load is too high */
2215 if (GNUNET_SCHEDULER_get_load (sched,
2216 GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2218 /* TODO: call to stats? */
2221 hello = (const struct GNUNET_HELLO_Message *) message;
2222 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2224 GNUNET_break_op (0);
2225 return GNUNET_SYSERR;
2227 GNUNET_CRYPTO_hash (&publicKey,
2228 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2229 &target.hashPubKey);
2231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2232 "Processing `%s' message for `%4s' of size %u\n",
2234 GNUNET_i2s (&target),
2235 GNUNET_HELLO_size(hello));
2238 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2239 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2240 memcpy (&chvc[1], hello, hsize);
2241 GNUNET_CONTAINER_DLL_insert (chvc_head,
2244 /* finally, check if HELLO was previously validated
2245 (continuation will then schedule actual validation) */
2246 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2250 HELLO_VERIFICATION_TIMEOUT,
2251 &check_hello_validated, chvc);
2257 * The peer specified by the given neighbor has timed-out or a plugin
2258 * has disconnected. We may either need to do nothing (other plugins
2259 * still up), or trigger a full disconnect and clean up. This
2260 * function updates our state and does the necessary notifications.
2261 * Also notifies our clients that the neighbor is now officially
2264 * @param n the neighbor list entry for the peer
2265 * @param check should we just check if all plugins
2266 * disconnected or must we ask all plugins to
2270 disconnect_neighbor (struct NeighborList *current_handle, int check)
2272 struct ReadyList *rpos;
2273 struct NeighborList *npos;
2274 struct NeighborList *nprev;
2275 struct NeighborList *n;
2276 struct MessageQueue *mq;
2277 struct ForeignAddressList *peer_addresses;
2278 struct ForeignAddressList *peer_pos;
2280 if (neighbors == NULL)
2281 return; /* We don't have any neighbors, so client has an already removed handle! */
2284 while ((npos != NULL) && (current_handle != npos))
2288 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2292 if (GNUNET_YES == check)
2295 while (NULL != rpos)
2297 peer_addresses = rpos->addresses;
2298 while (peer_addresses != NULL)
2300 if (GNUNET_YES == peer_addresses->connected)
2301 return; /* still connected */
2302 peer_addresses = peer_addresses->next;
2309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2310 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2312 /* remove n from neighbors list */
2315 while ((npos != NULL) && (npos != n))
2320 GNUNET_assert (npos != NULL);
2322 neighbors = n->next;
2324 nprev->next = n->next;
2326 /* notify all clients about disconnect */
2327 notify_clients_disconnect (&n->id);
2329 /* clean up all plugins, cancel connections and pending transmissions */
2330 while (NULL != (rpos = n->plugins))
2332 n->plugins = rpos->next;
2333 if (GNUNET_YES == rpos->connected)
2334 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2336 while (rpos->addresses != NULL)
2338 peer_pos = rpos->addresses;
2339 rpos->addresses = peer_pos->next;
2340 GNUNET_free(peer_pos);
2345 /* free all messages on the queue */
2346 while (NULL != (mq = n->messages))
2348 n->messages = mq->next;
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);
2490 service_context = n->plugins;
2491 while ((service_context != NULL) && (plugin != service_context->plugin))
2492 service_context = service_context->next;
2493 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2494 if (message == NULL)
2497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2498 "Receive failed from `%4s', triggering disconnect\n",
2499 GNUNET_i2s (&n->id));
2501 /* TODO: call stats */
2502 if (service_context != NULL)
2503 service_context->connected = GNUNET_NO;
2504 disconnect_neighbor (n, GNUNET_YES);
2507 peer_address = add_peer_address(n,
2510 sender_address_len);
2511 if (service_context != NULL)
2513 if (service_context->connected == GNUNET_NO)
2515 service_context->connected = GNUNET_YES;
2516 /* FIXME: What to do here? Should we use these as well,
2517 to specify some Address in the AddressList should be
2519 peer_address->transmit_ready = GNUNET_YES;
2520 peer_address->connect_attempts++;
2522 peer_address->timeout
2524 GNUNET_TIME_relative_to_absolute
2525 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2527 /* update traffic received amount ... */
2528 msize = ntohs (message->size);
2529 n->last_received += msize;
2530 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2532 GNUNET_TIME_relative_to_absolute
2533 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2535 GNUNET_SCHEDULER_add_delayed (sched,
2536 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2537 &neighbor_timeout_task, n);
2539 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2541 /* dropping message due to frequent inbound volume violations! */
2542 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2543 GNUNET_ERROR_TYPE_BULK,
2545 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2546 /* TODO: call stats */
2549 switch (ntohs (message->type))
2551 case GNUNET_MESSAGE_TYPE_HELLO:
2552 process_hello (plugin, message);
2554 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2555 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2557 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2558 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2563 "Received message of type %u from `%4s', sending to all clients.\n",
2564 ntohs (message->type), GNUNET_i2s (peer));
2566 /* transmit message to all clients */
2567 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2568 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2569 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2570 im->latency = n->latency;
2572 memcpy (&im[1], message, msize);
2575 while (cpos != NULL)
2577 transmit_to_client (cpos, &im->header, GNUNET_YES);
2586 * Handle START-message. This is the first message sent to us
2587 * by any client which causes us to add it to our list.
2589 * @param cls closure (always NULL)
2590 * @param client identification of the client
2591 * @param message the actual message
2594 handle_start (void *cls,
2595 struct GNUNET_SERVER_Client *client,
2596 const struct GNUNET_MessageHeader *message)
2598 struct TransportClient *c;
2599 struct ConnectInfoMessage cim;
2600 struct NeighborList *n;
2601 struct InboundMessage *im;
2602 struct GNUNET_MessageHeader *ack;
2605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606 "Received `%s' request from client\n", "START");
2611 if (c->client == client)
2613 /* client already on our list! */
2615 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2620 c = GNUNET_malloc (sizeof (struct TransportClient));
2624 if (our_hello != NULL)
2627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2628 "Sending our own `%s' to new client\n", "HELLO");
2630 transmit_to_client (c,
2631 (const struct GNUNET_MessageHeader *) our_hello,
2633 /* tell new client about all existing connections */
2634 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2635 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2637 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2638 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2639 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2640 sizeof (struct GNUNET_MessageHeader));
2641 im->header.size = htons (sizeof (struct InboundMessage) +
2642 sizeof (struct GNUNET_MessageHeader));
2643 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2644 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2645 ack = (struct GNUNET_MessageHeader *) &im[1];
2646 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2647 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2648 for (n = neighbors; n != NULL; n = n->next)
2651 transmit_to_client (c, &cim.header, GNUNET_NO);
2652 if (n->received_pong)
2655 transmit_to_client (c, &im->header, GNUNET_NO);
2662 fprintf(stderr, "Our hello is NULL!\n");
2664 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2669 * Handle HELLO-message.
2671 * @param cls closure (always NULL)
2672 * @param client identification of the client
2673 * @param message the actual message
2676 handle_hello (void *cls,
2677 struct GNUNET_SERVER_Client *client,
2678 const struct GNUNET_MessageHeader *message)
2683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2684 "Received `%s' request from client\n", "HELLO");
2686 ret = process_hello (NULL, message);
2687 GNUNET_SERVER_receive_done (client, ret);
2692 * Handle SEND-message.
2694 * @param cls closure (always NULL)
2695 * @param client identification of the client
2696 * @param message the actual message
2699 handle_send (void *cls,
2700 struct GNUNET_SERVER_Client *client,
2701 const struct GNUNET_MessageHeader *message)
2703 struct TransportClient *tc;
2704 struct NeighborList *n;
2705 const struct OutboundMessage *obm;
2706 const struct GNUNET_MessageHeader *obmm;
2710 size = ntohs (message->size);
2712 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2715 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2718 obm = (const struct OutboundMessage *) message;
2720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2721 "Received `%s' request from client with target `%4s'\n",
2722 "SEND", GNUNET_i2s (&obm->peer));
2724 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2725 msize = ntohs (obmm->size);
2726 if (size != msize + sizeof (struct OutboundMessage))
2729 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2732 n = find_neighbor (&obm->peer);
2734 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2736 while ((tc != NULL) && (tc->client != client))
2740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2741 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2743 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2745 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm,
2746 ntohs (obmm->size), GNUNET_NO, n);
2747 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2752 * Handle SET_QUOTA-message.
2754 * @param cls closure (always NULL)
2755 * @param client identification of the client
2756 * @param message the actual message
2759 handle_set_quota (void *cls,
2760 struct GNUNET_SERVER_Client *client,
2761 const struct GNUNET_MessageHeader *message)
2763 const struct QuotaSetMessage *qsm =
2764 (const struct QuotaSetMessage *) message;
2765 struct NeighborList *n;
2766 struct TransportPlugin *p;
2767 struct ReadyList *rl;
2769 n = find_neighbor (&qsm->peer);
2772 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2778 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2779 "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2783 if (n->quota_in < ntohl (qsm->quota_in))
2784 n->last_quota_update = GNUNET_TIME_absolute_get ();
2785 n->quota_in = ntohl (qsm->quota_in);
2790 p->api->set_receive_quota (p->api->cls,
2791 &qsm->peer, ntohl (qsm->quota_in));
2794 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2799 * Handle TRY_CONNECT-message.
2801 * @param cls closure (always NULL)
2802 * @param client identification of the client
2803 * @param message the actual message
2806 handle_try_connect (void *cls,
2807 struct GNUNET_SERVER_Client *client,
2808 const struct GNUNET_MessageHeader *message)
2810 const struct TryConnectMessage *tcm;
2811 struct NeighborList *neighbor;
2812 tcm = (const struct TryConnectMessage *) message;
2814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2815 "Received `%s' request from client %p asking to connect to `%4s'\n",
2816 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2818 neighbor = find_neighbor(&tcm->peer);
2819 if (neighbor == NULL)
2820 setup_new_neighbor (&tcm->peer);
2821 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2826 transmit_address_to_client (void *cls, const char *address)
2828 struct GNUNET_SERVER_TransmitContext *tc = cls;
2831 if (NULL == address)
2834 slen = strlen (address) + 1;
2835 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2836 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2837 if (NULL == address)
2838 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2843 * Handle AddressLookup-message.
2845 * @param cls closure (always NULL)
2846 * @param client identification of the client
2847 * @param message the actual message
2850 handle_address_lookup (void *cls,
2851 struct GNUNET_SERVER_Client *client,
2852 const struct GNUNET_MessageHeader *message)
2854 const struct AddressLookupMessage *alum;
2855 struct TransportPlugin *lsPlugin;
2856 const char *nameTransport;
2857 const char *address;
2859 struct GNUNET_SERVER_TransmitContext *tc;
2861 size = ntohs (message->size);
2862 if (size < sizeof (struct AddressLookupMessage))
2864 GNUNET_break_op (0);
2865 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2868 alum = (const struct AddressLookupMessage *) message;
2869 uint32_t addressLen = ntohl (alum->addrlen);
2870 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2872 GNUNET_break_op (0);
2873 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2876 address = (const char *) &alum[1];
2877 nameTransport = (const char *) &address[addressLen];
2879 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2881 GNUNET_break_op (0);
2882 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2885 struct GNUNET_TIME_Absolute timeout =
2886 GNUNET_TIME_absolute_ntoh (alum->timeout);
2887 struct GNUNET_TIME_Relative rtimeout =
2888 GNUNET_TIME_absolute_get_remaining (timeout);
2889 lsPlugin = find_transport (nameTransport);
2890 if (NULL == lsPlugin)
2892 tc = GNUNET_SERVER_transmit_context_create (client);
2893 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2894 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2895 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2898 tc = GNUNET_SERVER_transmit_context_create (client);
2899 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2900 address, addressLen, GNUNET_YES,
2902 &transmit_address_to_client, tc);
2906 * List of handlers for the messages understood by this
2909 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2910 {&handle_start, NULL,
2911 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2912 {&handle_hello, NULL,
2913 GNUNET_MESSAGE_TYPE_HELLO, 0},
2914 {&handle_send, NULL,
2915 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2916 {&handle_set_quota, NULL,
2917 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2918 {&handle_try_connect, NULL,
2919 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2920 sizeof (struct TryConnectMessage)},
2921 {&handle_address_lookup, NULL,
2922 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2929 * Setup the environment for this plugin.
2932 create_environment (struct TransportPlugin *plug)
2934 plug->env.cfg = cfg;
2935 plug->env.sched = sched;
2936 plug->env.my_identity = &my_identity;
2937 plug->env.cls = plug;
2938 plug->env.receive = &plugin_env_receive;
2939 plug->env.notify_address = &plugin_env_notify_address;
2940 plug->env.default_quota_in =
2941 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2942 plug->env.max_connections = max_connect_per_transport;
2947 * Start the specified transport (load the plugin).
2950 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2952 struct TransportPlugin *plug;
2955 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2956 _("Loading `%s' transport plugin\n"), name);
2957 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2958 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2959 create_environment (plug);
2960 plug->short_name = GNUNET_strdup (name);
2961 plug->lib_name = libname;
2962 plug->next = plugins;
2964 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2965 if (plug->api == NULL)
2967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2968 _("Failed to load transport plugin for `%s'\n"), name);
2969 GNUNET_free (plug->short_name);
2970 plugins = plug->next;
2971 GNUNET_free (libname);
2978 * Called whenever a client is disconnected. Frees our
2979 * resources associated with that client.
2981 * @param cls closure
2982 * @param client identification of the client
2985 client_disconnect_notification (void *cls,
2986 struct GNUNET_SERVER_Client *client)
2988 struct TransportClient *pos;
2989 struct TransportClient *prev;
2990 struct ClientMessageQueueEntry *mqe;
2995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2996 "Client disconnected, cleaning up.\n");
3000 while ((pos != NULL) && (pos->client != client))
3007 while (NULL != (mqe = pos->message_queue_head))
3009 pos->message_queue_head = mqe->next;
3012 pos->message_queue_head = NULL;
3014 clients = pos->next;
3016 prev->next = pos->next;
3017 if (GNUNET_YES == pos->tcs_pending)
3027 * Iterator to free entries in the validation_map.
3029 * @param cls closure (unused)
3030 * @param key current key code
3031 * @param value value in the hash map (validation to abort)
3032 * @return GNUNET_YES (always)
3035 abort_validation (void *cls,
3036 const GNUNET_HashCode * key,
3039 struct ValidationEntry *va = value;
3041 GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3042 GNUNET_free (va->transport_name);
3049 * Function called when the service shuts down. Unloads our plugins
3050 * and cancels pending validations.
3052 * @param cls closure, unused
3053 * @param tc task context (unused)
3056 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3058 struct TransportPlugin *plug;
3059 struct OwnAddressList *al;
3060 struct CheckHelloValidatedContext *chvc;
3063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3064 "Transport service is unloading plugins...\n");
3066 while (NULL != (plug = plugins))
3068 plugins = plug->next;
3069 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3070 GNUNET_free (plug->lib_name);
3071 GNUNET_free (plug->short_name);
3072 while (NULL != (al = plug->addresses))
3074 plug->addresses = al->next;
3079 if (my_private_key != NULL)
3080 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3081 GNUNET_free_non_null (our_hello);
3083 /* free 'chvc' data structure */
3084 while (NULL != (chvc = chvc_head))
3086 chvc_head = chvc->next;
3087 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3092 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3095 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3100 * Initiate transport service.
3102 * @param cls closure
3103 * @param s scheduler to use
3104 * @param serv the initialized server
3105 * @param c configuration to use
3109 struct GNUNET_SCHEDULER_Handle *s,
3110 struct GNUNET_SERVER_Handle *serv,
3111 const struct GNUNET_CONFIGURATION_Handle *c)
3116 unsigned long long tneigh;
3121 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3122 /* parse configuration */
3124 GNUNET_CONFIGURATION_get_value_number (c,
3129 GNUNET_CONFIGURATION_get_value_filename (c,
3131 "HOSTKEY", &keyfile)))
3133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3135 ("Transport service is lacking key configuration settings. Exiting.\n"));
3136 GNUNET_SCHEDULER_shutdown (s);
3139 max_connect_per_transport = (uint32_t) tneigh;
3140 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3141 GNUNET_free (keyfile);
3142 if (my_private_key == NULL)
3144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3146 ("Transport service could not access hostkey. Exiting.\n"));
3147 GNUNET_SCHEDULER_shutdown (s);
3150 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3151 GNUNET_CRYPTO_hash (&my_public_key,
3152 sizeof (my_public_key), &my_identity.hashPubKey);
3153 /* setup notification */
3155 GNUNET_SERVER_disconnect_notify (server,
3156 &client_disconnect_notification, NULL);
3157 /* load plugins... */
3160 GNUNET_CONFIGURATION_get_value_string (c,
3161 "TRANSPORT", "PLUGINS", &plugs))
3163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3164 _("Starting transport plugins `%s'\n"), plugs);
3165 pos = strtok (plugs, " ");
3168 start_transport (server, pos);
3170 pos = strtok (NULL, " ");
3172 GNUNET_free (plugs);
3174 GNUNET_SCHEDULER_add_delayed (sched,
3175 GNUNET_TIME_UNIT_FOREVER_REL,
3176 &shutdown_task, NULL);
3181 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3183 /* process client requests */
3184 GNUNET_SERVER_add_handlers (server, handlers);
3189 * The main function for the transport service.
3191 * @param argc number of arguments from the command line
3192 * @param argv command line arguments
3193 * @return 0 ok, 1 on error
3196 main (int argc, char *const *argv)
3198 return (GNUNET_OK ==
3199 GNUNET_SERVICE_run (argc,
3202 GNUNET_SERVICE_OPTION_NONE,
3203 &run, NULL)) ? 0 : 1;
3206 /* end of gnunet-service-transport.c */