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 * - remove AddressValidations, incorporate them into the PeerAddressLists
30 #include "gnunet_client_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_getopt_lib.h"
33 #include "gnunet_hello_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_peerinfo_service.h"
36 #include "gnunet_plugin_lib.h"
37 #include "gnunet_protocols.h"
38 #include "gnunet_service_lib.h"
39 #include "gnunet_signatures.h"
40 #include "plugin_transport.h"
41 #include "transport.h"
44 * How many messages can we have pending for a given client process
45 * before we start to drop incoming messages? We typically should
46 * have only one client and so this would be the primary buffer for
47 * messages, so the number should be chosen rather generously.
49 * The expectation here is that most of the time the queue is large
50 * enough so that a drop is virtually never required.
52 #define MAX_PENDING 128
55 * How often should we try to reconnect to a peer using a particular
56 * transport plugin before giving up? Note that the plugin may be
57 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
59 #define MAX_CONNECT_RETRY 3
62 * How often must a peer violate bandwidth quotas before we start
63 * to simply drop its messages?
65 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
68 * How long until a HELLO verification attempt should time out?
69 * Must be rather small, otherwise a partially successful HELLO
70 * validation (some addresses working) might not be available
71 * before a client's request for a connection fails for good.
72 * Besides, if a single request to an address takes a long time,
73 * then the peer is unlikely worthwhile anyway.
75 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
78 * How long will we allow sending of a ping to be delayed?
80 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
85 #define TRANSPORT_DEFAULT_PRIORITY 4
88 * How often do we re-add (cheaper) plugins to our list of plugins
89 * to try for a given connected peer?
91 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
94 * After how long do we expire an address in a HELLO
95 * that we just validated? This value is also used
96 * for our own addresses when we create a HELLO.
98 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
102 * List of addresses of other peers
104 struct PeerAddressList
107 * This is a linked list.
109 struct PeerAddressList *next;
112 * Pointer to the validation associated with this
113 * address. May be NULL if already validated!
115 struct ValidationAddress *validation;
118 * Which of our transport plugins does this entry
121 struct TransportPlugin *plugin;
124 * Neighbor this entry belongs to.
126 struct NeighborList *neighbor;
129 * Ready list (transport) that this peer belongs to
131 struct ReadyList *ready_list;
133 * How long until we auto-expire this address (unless it is
134 * re-confirmed by the transport)?
136 struct GNUNET_TIME_Absolute expires;
149 * What was the last latency observed for this plugin
150 * and peer? Invalid if connected is GNUNET_NO.
152 struct GNUNET_TIME_Relative latency;
155 * If we did not successfully transmit a message to the given peer
156 * via this connection during the specified time, we should consider
157 * the connection to be dead. This is used in the case that a TCP
158 * transport simply stalls writing to the stream but does not
159 * formerly get a signal that the other peer died.
161 struct GNUNET_TIME_Absolute timeout;
164 * Is this plugin currently connected? The first time
165 * we transmit or send data to a peer via a particular
166 * plugin, we set this to GNUNET_YES. If we later get
167 * an error (disconnect notification or transmission
168 * failure), we set it back to GNUNET_NO. Each time the
169 * value is set to GNUNET_YES, we increment the
170 * "connect_attempts" counter. If that one reaches a
171 * particular threshold, we consider the plugin to not
172 * be working properly at this time for the given peer
173 * and remove it from the eligible list.
178 * Is this plugin ready to transmit to the specific target?
179 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
180 * transmission is in progress, "transmit_ready" is set to
186 * How often have we tried to connect using this plugin?
188 unsigned int connect_attempts;
194 * Entry in linked list of network addresses.
199 * This is a linked list.
201 struct AddressList *next;
204 * The address, actually a pointer to the end
205 * of this struct. Do not free!
210 * How long until we auto-expire this address (unless it is
211 * re-confirmed by the transport)?
213 struct GNUNET_TIME_Absolute expires;
224 * Entry in linked list of all of our plugins.
226 struct TransportPlugin
230 * This is a linked list.
232 struct TransportPlugin *next;
235 * API of the transport as returned by the plugin's
236 * initialization function.
238 struct GNUNET_TRANSPORT_PluginFunctions *api;
241 * Short name for the plugin (i.e. "tcp").
246 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
251 * List of our known addresses for this transport.
253 struct AddressList *addresses;
256 * Environment this transport service is using
259 struct GNUNET_TRANSPORT_PluginEnvironment env;
262 * ID of task that is used to clean up expired addresses.
264 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
268 * Set to GNUNET_YES if we need to scrap the existing
269 * list of "addresses" and start fresh when we receive
270 * the next address update from a transport. Set to
271 * GNUNET_NO if we should just add the new address
272 * to the list and wait for the commit call.
281 * For each neighbor we keep a list of messages
282 * that we still want to transmit to the neighbor.
288 * This is a linked list.
290 struct MessageQueue *next;
293 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
294 * stuck together in memory.
299 * Size of the message buf
301 size_t message_buf_size;
304 * Client responsible for queueing the message;
305 * used to check that a client has no two messages
306 * pending for the same target. Can be NULL.
308 struct TransportClient *client;
311 * Using which specific address should we send this message?
313 struct PeerAddressList *specific_peer;
316 * Neighbor this entry belongs to.
318 /*struct NeighborList *neighbor;*/
321 * Peer ID of the Neighbor this entry belongs to.
323 struct GNUNET_PeerIdentity *neighbor_id;
326 * Plugin that we used for the transmission.
327 * NULL until we scheduled a transmission.
329 struct TransportPlugin *plugin;
332 * Internal message of the transport system that should not be
333 * included in the usual SEND-SEND_OK transmission confirmation
334 * traffic management scheme. Typically, "internal_msg" will
335 * be set whenever "client" is NULL (but it is not strictly
341 * How important is the message?
343 unsigned int priority;
349 * For a given Neighbor, which plugins are available
350 * to talk to this peer and what are their costs?
355 * This is a linked list.
357 struct ReadyList *next;
360 * Which of our transport plugins does this entry
363 struct TransportPlugin *plugin;
366 * Neighbor this entry belongs to.
368 struct NeighborList *neighbor;
371 * Transport addresses, latency, and readiness for
372 * this particular plugin.
374 struct PeerAddressList *addresses;
377 * Is this plugin ready to transmit to the specific target?
378 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
379 * transmission is in progress, "transmit_ready" is set to
382 int plugin_transmit_ready;
385 * Are any of our PeerAddressList addresses still connected?
387 int connected; /* FIXME: dynamically check PeerAddressList addresses when asked to! */
392 * Entry in linked list of all of our current neighbors.
398 * This is a linked list.
400 struct NeighborList *next;
403 * Which of our transports is connected to this peer
404 * and what is their status?
406 struct ReadyList *plugins;
409 * List of messages we would like to send to this peer;
410 * must contain at most one message per client.
412 struct MessageQueue *messages;
415 * Identity of this neighbor.
417 struct GNUNET_PeerIdentity id;
420 * ID of task scheduled to run when this peer is about to
421 * time out (will free resources associated with the peer).
423 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
426 * How long until we should consider this peer dead
427 * (if we don't receive another message in the
430 struct GNUNET_TIME_Absolute peer_timeout;
433 * At what time did we reset last_received last?
435 struct GNUNET_TIME_Absolute last_quota_update;
438 * At what time should we try to again add plugins to
441 struct GNUNET_TIME_Absolute retry_plugins_time;
444 * The latency we have seen for this particular address for
445 * this particular peer. This latency may have been calculated
446 * over multiple transports. This value reflects how long it took
447 * us to receive a response when SENDING via this particular
448 * transport/neighbor/address combination!
449 * FIXME: why is this NBO?
451 struct GNUNET_TIME_RelativeNBO latency;
454 * How many bytes have we received since the "last_quota_update"
457 uint64_t last_received;
460 * Global quota for inbound traffic for the neighbor in bytes/ms.
465 * How often has the other peer (recently) violated the
466 * inbound traffic limit? Incremented by 10 per violation,
467 * decremented by 1 per non-violation (for each
470 unsigned int quota_violation_count;
473 * Have we seen an ACK from this neighbor in the past?
474 * (used to make up a fake ACK for clients connecting after
475 * the neighbor connected to us).
482 * Message used to ask a peer to validate receipt (to check an address
483 * from a HELLO). Followed by the address used. Note that the
484 * recipients response does not affirm that he has this address,
485 * only that he got the challenge message.
487 struct TransportPingMessage
491 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
493 struct GNUNET_MessageHeader header;
496 * Random challenge number (in network byte order).
498 uint32_t challenge GNUNET_PACKED;
501 * Who is the intended recipient?
503 struct GNUNET_PeerIdentity target;
509 * Message used to validate a HELLO. The challenge is included in the
510 * confirmation to make matching of replies to requests possible. The
511 * signature signs the original challenge number, our public key, the
512 * sender's address (so that the sender can check that the address we
513 * saw is plausible for him and possibly detect a MiM attack) and a
514 * timestamp (to limit replay).<p>
516 * This message is followed by the address of the
517 * client that we are observing (which is part of what
520 struct TransportPongMessage
524 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
526 struct GNUNET_MessageHeader header;
529 * For padding, always zero.
531 uint32_t reserved GNUNET_PACKED;
536 struct GNUNET_CRYPTO_RsaSignature signature;
539 * What are we signing and why?
541 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
544 * Random challenge number (in network byte order).
546 uint32_t challenge GNUNET_PACKED;
549 * Who signed this message?
551 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
554 * Size of address appended to this message
561 * Linked list of messages to be transmitted to
562 * the client. Each entry is followed by the
565 struct ClientMessageQueueEntry
568 * This is a linked list.
570 struct ClientMessageQueueEntry *next;
575 * Client connected to the transport service.
577 struct TransportClient
581 * This is a linked list.
583 struct TransportClient *next;
586 * Handle to the client.
588 struct GNUNET_SERVER_Client *client;
591 * Linked list of messages yet to be transmitted to
594 struct ClientMessageQueueEntry *message_queue_head;
597 * Tail of linked list of messages yet to be transmitted to the
600 struct ClientMessageQueueEntry *message_queue_tail;
603 * Is a call to "transmit_send_continuation" pending? If so, we
604 * must not free this struct (even if the corresponding client
605 * disconnects) and instead only remove it from the linked list and
606 * set the "client" field to NULL.
611 * Length of the list of messages pending for this client.
613 unsigned int message_count;
619 * For each HELLO, we may have to validate multiple addresses;
620 * each address gets its own request entry.
622 struct ValidationAddress
625 * This is a linked list.
627 struct ValidationAddress *next;
630 * What peer_address does this validation belong to?
632 struct PeerAddressList *peer_address;
635 * Name of the transport.
637 char *transport_name;
640 * When should this validated address expire?
642 struct GNUNET_TIME_Absolute expiration;
645 * At what time did we send this validation?
647 struct GNUNET_TIME_Absolute send_time;
650 * Challenge number we used.
655 * Set to GNUNET_YES if the challenge was met,
656 * GNUNET_SYSERR if we know it failed, GNUNET_NO
657 * if we are waiting on a response.
664 * Entry in linked list of all HELLOs awaiting validation.
666 struct ValidationList
670 * This is a linked list.
672 struct ValidationList *next;
675 * Linked list with one entry per address from the HELLO
676 * that needs to be validated.
678 struct ValidationAddress *addresses;
681 * The public key of the peer.
683 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
686 * When does this record time-out? (assuming the
687 * challenge goes unanswered)
689 struct GNUNET_TIME_Absolute timeout;
694 struct CheckHelloValidatedContext
697 * Plugin for which we are validating.
699 struct TransportPlugin *plugin;
702 * Hello that we are validating.
704 struct GNUNET_HELLO_Message *hello;
707 * Validation list being built.
709 struct ValidationList *e;
712 * Context for peerinfo iteration.
713 * NULL after we are done processing peerinfo's information.
715 struct GNUNET_PEERINFO_IteratorContext *piter;
722 * HELLOs awaiting validation.
724 static struct ValidationList *pending_validations;
729 static struct GNUNET_HELLO_Message *our_hello;
732 * "version" of "our_hello". Used to see if a given
733 * neighbor has already been sent the latest version
734 * of our HELLO message.
736 static unsigned int our_hello_version;
741 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
746 static struct GNUNET_PeerIdentity my_identity;
751 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
756 struct GNUNET_SCHEDULER_Handle *sched;
761 const struct GNUNET_CONFIGURATION_Handle *cfg;
764 * Linked list of all clients to this service.
766 static struct TransportClient *clients;
769 * All loaded plugins.
771 static struct TransportPlugin *plugins;
776 static struct GNUNET_SERVER_Handle *server;
779 * All known neighbors and their HELLOs.
781 static struct NeighborList *neighbors;
784 * Number of neighbors we'd like to have.
786 static uint32_t max_connect_per_transport;
789 * The peer specified by the given neighbor has timed-out or a plugin
790 * has disconnected. We may either need to do nothing (other plugins
791 * still up), or trigger a full disconnect and clean up. This
792 * function updates our state and do the necessary notifications.
793 * Also notifies our clients that the neighbor is now officially
796 * @param n the neighbor list entry for the peer
797 * @param check should we just check if all plugins
798 * disconnected or must we ask all plugins to
801 static void disconnect_neighbor (struct NeighborList *n, int check);
805 * Check the ready list for the given neighbor and
806 * if a plugin is ready for transmission (and if we
807 * have a message), do so!
809 * @param neighbor target peer for which to check the plugins
811 static ssize_t try_transmission_to_peer (struct NeighborList *neighbor);
815 * Find an entry in the neighbor list for a particular peer.
816 * if sender_address is not specified (NULL) then return the
817 * first matching entry. If sender_address is specified, then
818 * make sure that the address and address_len also matches.
820 * @return NULL if not found.
822 static struct NeighborList *
823 find_neighbor (const struct GNUNET_PeerIdentity *key)
825 struct NeighborList *head = neighbors;
827 while ((head != NULL) &&
828 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
836 * Find an entry in the transport list for a particular transport.
838 * @return NULL if not found.
840 static struct TransportPlugin *
841 find_transport (const char *short_name)
843 struct TransportPlugin *head = plugins;
844 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
851 * Update the quota values for the given neighbor now.
854 update_quota (struct NeighborList *n)
856 struct GNUNET_TIME_Relative delta;
860 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
861 if (delta.value < MIN_QUOTA_REFRESH_TIME)
862 return; /* not enough time passed for doing quota update */
863 allowed = delta.value * n->quota_in;
865 if (n->last_received < allowed)
867 remaining = allowed - n->last_received;
869 remaining /= n->quota_in;
872 if (remaining > MAX_BANDWIDTH_CARRY)
873 remaining = MAX_BANDWIDTH_CARRY;
874 n->last_received = 0;
875 n->last_quota_update = GNUNET_TIME_absolute_get ();
876 n->last_quota_update.value -= remaining;
877 if (n->quota_violation_count > 0)
878 n->quota_violation_count--;
882 n->last_received -= allowed;
883 n->last_quota_update = GNUNET_TIME_absolute_get ();
884 if (n->last_received > allowed)
886 /* more than twice the allowed rate! */
887 n->quota_violation_count += 10;
894 * Function called to notify a client about the socket
895 * being ready to queue more data. "buf" will be
896 * NULL and "size" zero if the socket was closed for
897 * writing in the meantime.
900 * @param size number of bytes available in buf
901 * @param buf where the callee should write the message
902 * @return number of bytes written to buf
905 transmit_to_client_callback (void *cls, size_t size, void *buf)
907 struct TransportClient *client = cls;
908 struct ClientMessageQueueEntry *q;
911 const struct GNUNET_MessageHeader *msg;
912 struct GNUNET_CONNECTION_TransmitHandle *th;
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
918 "Transmission to client failed, closing connection.\n");
919 /* fatal error with client, free message queue! */
920 while (NULL != (q = client->message_queue_head))
922 client->message_queue_head = q->next;
925 client->message_queue_tail = NULL;
926 client->message_count = 0;
931 while (NULL != (q = client->message_queue_head))
933 msg = (const struct GNUNET_MessageHeader *) &q[1];
934 msize = ntohs (msg->size);
935 if (msize + tsize > size)
938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939 "Transmitting message of type %u to client.\n",
942 client->message_queue_head = q->next;
944 client->message_queue_tail = NULL;
945 memcpy (&cbuf[tsize], msg, msize);
948 client->message_count--;
952 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
953 th = GNUNET_SERVER_notify_transmit_ready (client->client,
955 GNUNET_TIME_UNIT_FOREVER_REL,
956 &transmit_to_client_callback,
958 GNUNET_assert (th != NULL);
965 * Send the specified message to the specified client. Since multiple
966 * messages may be pending for the same client at a time, this code
967 * makes sure that no message is lost.
969 * @param client client to transmit the message to
970 * @param msg the message to send
971 * @param may_drop can this message be dropped if the
972 * message queue for this client is getting far too large?
975 transmit_to_client (struct TransportClient *client,
976 const struct GNUNET_MessageHeader *msg, int may_drop)
978 struct ClientMessageQueueEntry *q;
980 struct GNUNET_CONNECTION_TransmitHandle *th;
982 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
984 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
986 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
987 client->message_count, MAX_PENDING);
988 /* TODO: call to statistics... */
991 client->message_count++;
992 msize = ntohs (msg->size);
993 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
994 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
995 memcpy (&q[1], msg, msize);
996 /* append to message queue */
997 if (client->message_queue_tail == NULL)
999 client->message_queue_tail = q;
1003 client->message_queue_tail->next = q;
1004 client->message_queue_tail = q;
1006 if (client->message_queue_head == NULL)
1008 client->message_queue_head = q;
1009 th = GNUNET_SERVER_notify_transmit_ready (client->client,
1011 GNUNET_TIME_UNIT_FOREVER_REL,
1012 &transmit_to_client_callback,
1014 GNUNET_assert (th != NULL);
1020 * Find alternative plugins for communication.
1022 * @param neighbor for which neighbor should we try to find
1026 try_alternative_plugins (struct NeighborList *neighbor)
1028 struct ReadyList *rl;
1030 if ((neighbor->plugins != NULL) &&
1031 (neighbor->retry_plugins_time.value >
1032 GNUNET_TIME_absolute_get ().value))
1033 return; /* don't try right now */
1034 neighbor->retry_plugins_time
1035 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1037 rl = neighbor->plugins;
1038 #if WTF /* FIXME: What is this supposed to do? */
1041 if (rl->connect_attempts > 0)
1042 rl->connect_attempts--; /* amnesty */
1050 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1051 * upon "completion" of a send request. This tells the API
1052 * that it is now legal to send another message to the given
1055 * @param cls closure, identifies the entry on the
1056 * message queue that was transmitted and the
1057 * client responsible for queueing the message
1058 * @param target the peer receiving the message
1059 * @param result GNUNET_OK on success, if the transmission
1060 * failed, we should not tell the client to transmit
1064 transmit_send_continuation (void *cls,
1065 const struct GNUNET_PeerIdentity *target,
1068 struct MessageQueue *mq = cls;
1069 /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1070 struct SendOkMessage send_ok_msg;
1071 struct NeighborList *n;
1073 GNUNET_assert (mq != NULL);
1074 n = find_neighbor(mq->neighbor_id);
1075 if (n == NULL) /* Neighbor must have been removed asynchronously! */
1078 /* Otherwise, let's make sure we've got the right peer */
1080 memcmp (&n->id, target,
1081 sizeof (struct GNUNET_PeerIdentity)));
1083 if (result == GNUNET_OK)
1085 mq->specific_peer->timeout =
1086 GNUNET_TIME_relative_to_absolute
1087 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 "Transmission to peer `%s' failed, marking connection as down.\n",
1093 GNUNET_i2s (target));
1094 mq->specific_peer->connected = GNUNET_NO;
1096 if (!mq->internal_msg)
1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 "Setting transmit_ready on transport!\n");
1102 mq->specific_peer->transmit_ready = GNUNET_YES;
1105 if (mq->client != NULL)
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "Notifying client %p about transmission to peer `%4s'.\n",
1109 mq->client, GNUNET_i2s (target));
1110 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1111 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1112 send_ok_msg.success = htonl (result);
1113 send_ok_msg.peer = n->id;
1114 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1116 GNUNET_free (mq->message_buf);
1117 GNUNET_free (mq->neighbor_id);
1119 /* one plugin just became ready again, try transmitting
1120 another message (if available) */
1121 if (result == GNUNET_OK)
1122 try_transmission_to_peer (n);
1124 disconnect_neighbor (n, GNUNET_YES);
1130 struct PeerAddressList *
1131 find_ready_address(struct NeighborList *neighbor)
1133 struct ReadyList *head = neighbor->plugins;
1134 struct PeerAddressList *addresses;
1135 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1136 struct PeerAddressList *best_address;
1138 best_address = NULL;
1139 while (head != NULL)
1141 addresses = head->addresses;
1143 while (addresses != NULL)
1145 if ((addresses->timeout.value < now.value) && (addresses->connected == GNUNET_YES))
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Marking long-time inactive connection to `%4s' as down.\n",
1150 GNUNET_i2s (&addresses->ready_list->neighbor->id));
1152 addresses->connected = GNUNET_NO;
1154 addresses = addresses->next;
1157 addresses = head->addresses;
1158 while (addresses != NULL)
1160 if ((addresses->connected == GNUNET_YES) &&
1161 (addresses->transmit_ready == GNUNET_YES) &&
1162 ((best_address == NULL) || (addresses->latency.value < best_address->latency.value)))
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1166 "Found address with latency %llu (previous best was %llu), setting as best found yet!\n",
1167 addresses->latency.value, best_address == NULL ? -1LL : best_address->latency.value);
1169 best_address = addresses;
1171 addresses = addresses->next;
1176 if (best_address != NULL)
1178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179 "Best address found has latency of %llu!\n",
1180 best_address->latency.value);
1183 return best_address;
1188 * Check the ready list for the given neighbor and
1189 * if a plugin is ready for transmission (and if we
1190 * have a message), do so!
1193 try_transmission_to_peer (struct NeighborList *neighbor)
1195 struct GNUNET_TIME_Relative min_latency;
1196 struct ReadyList *rl;
1197 struct MessageQueue *mq;
1198 struct GNUNET_TIME_Absolute now;
1200 if (neighbor->messages == NULL)
1201 return 0; /* nothing to do */
1202 try_alternative_plugins (neighbor);
1203 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1205 mq = neighbor->messages;
1206 now = GNUNET_TIME_absolute_get ();
1208 if (mq->specific_peer == NULL)
1209 mq->specific_peer = find_ready_address(neighbor); /* Find first available (or best!) address to transmit to */
1211 if (mq->specific_peer == NULL)
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215 "No plugin ready to transmit message\n");
1217 return 0; /* nobody ready */
1220 rl = mq->specific_peer->ready_list;
1221 neighbor->messages = mq->next;
1222 mq->plugin = rl->plugin;
1223 if (!mq->internal_msg)
1224 mq->specific_peer->transmit_ready = GNUNET_NO;
1226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227 "Giving message of size %u for `%4s' to plugin `%s'\n",
1228 mq->message_buf_size,
1229 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1232 return rl->plugin->api->send (rl->plugin->api->cls,
1235 mq->message_buf_size,
1237 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1238 mq->specific_peer->addr,
1239 mq->specific_peer->addrlen,
1241 &transmit_send_continuation, mq);
1247 * Send the specified message to the specified peer.
1249 * @param client source of the transmission request (can be NULL)
1250 * @param peer_address PeerAddressList where we should send this message
1251 * @param priority how important is the message
1252 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1253 * @param message_buf_size total size of all messages in message_buf
1254 * @param is_internal is this an internal message
1255 * @param neighbor handle to the neighbor for transmission
1258 transmit_to_peer (struct TransportClient *client,
1259 struct PeerAddressList *peer_address,
1260 unsigned int priority,
1261 const char *message_buf,
1262 size_t message_buf_size,
1263 int is_internal, struct NeighborList *neighbor)
1265 struct MessageQueue *mq;
1266 struct MessageQueue *mqe;
1271 /* check for duplicate submission */
1272 mq = neighbor->messages;
1275 if (mq->client == client)
1277 /* client transmitted to same peer twice
1278 before getting SendOk! */
1285 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1286 mq->specific_peer = peer_address;
1287 mq->client = client;
1288 m = GNUNET_malloc (message_buf_size);
1289 memcpy (m, message_buf, message_buf_size);
1290 mq->message_buf = m;
1291 mq->message_buf_size = message_buf_size;
1292 mq->neighbor_id = GNUNET_malloc(sizeof (struct GNUNET_PeerIdentity));
1294 memcpy(mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1295 mq->internal_msg = is_internal;
1296 mq->priority = priority;
1299 mqe = neighbor->messages;
1301 while (mqe->next != NULL)
1306 neighbor->messages = mq;
1313 return try_transmission_to_peer (neighbor);
1320 struct GeneratorContext
1322 struct TransportPlugin *plug_pos;
1323 struct AddressList *addr_pos;
1324 struct GNUNET_TIME_Absolute expiration;
1332 address_generator (void *cls, size_t max, void *buf)
1334 struct GeneratorContext *gc = cls;
1337 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1339 gc->plug_pos = gc->plug_pos->next;
1340 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1342 if (NULL == gc->plug_pos)
1347 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1350 gc->addr_pos->addrlen, buf, max);
1351 gc->addr_pos = gc->addr_pos->next;
1357 * Construct our HELLO message from all of the addresses of
1358 * all of the transports.
1363 struct GNUNET_HELLO_Message *hello;
1364 struct TransportClient *cpos;
1365 struct NeighborList *npos;
1366 struct GeneratorContext gc;
1368 gc.plug_pos = plugins;
1369 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1370 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1371 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1374 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1377 while (cpos != NULL)
1379 transmit_to_client (cpos,
1380 (const struct GNUNET_MessageHeader *) hello,
1385 GNUNET_free_non_null (our_hello);
1387 our_hello_version++;
1388 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1390 while (npos != NULL)
1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1394 "Transmitting updated `%s' to neighbor `%4s'\n",
1395 "HELLO", GNUNET_i2s (&npos->id));
1396 #endif // FIXME: just testing
1397 //transmit_to_peer (NULL, NULL, 0,
1398 // (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1399 // GNUNET_YES, npos);
1406 * Task used to clean up expired addresses for a plugin.
1408 * @param cls closure
1412 expire_address_task (void *cls,
1413 const struct GNUNET_SCHEDULER_TaskContext *tc);
1417 * Update the list of addresses for this plugin,
1418 * expiring those that are past their expiration date.
1420 * @param plugin addresses of which plugin should be recomputed?
1421 * @param fresh set to GNUNET_YES if a new address was added
1422 * and we need to regenerate the HELLO even if nobody
1426 update_addresses (struct TransportPlugin *plugin, int fresh)
1428 struct GNUNET_TIME_Relative min_remaining;
1429 struct GNUNET_TIME_Relative remaining;
1430 struct GNUNET_TIME_Absolute now;
1431 struct AddressList *pos;
1432 struct AddressList *prev;
1433 struct AddressList *next;
1436 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1437 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1438 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1439 now = GNUNET_TIME_absolute_get ();
1440 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1441 expired = GNUNET_NO;
1443 pos = plugin->addresses;
1447 if (pos->expires.value < now.value)
1449 expired = GNUNET_YES;
1451 plugin->addresses = pos->next;
1453 prev->next = pos->next;
1458 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1459 if (remaining.value < min_remaining.value)
1460 min_remaining = remaining;
1466 if (expired || fresh)
1468 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1469 plugin->address_update_task
1470 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1472 &expire_address_task, plugin);
1478 * Task used to clean up expired addresses for a plugin.
1480 * @param cls closure
1484 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1486 struct TransportPlugin *plugin = cls;
1487 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1488 update_addresses (plugin, GNUNET_NO);
1493 * Function that must be called by each plugin to notify the
1494 * transport service about the addresses under which the transport
1495 * provided by the plugin can be reached.
1497 * @param cls closure
1498 * @param name name of the transport that generated the address
1499 * @param addr one of the addresses of the host, NULL for the last address
1500 * the specific address format depends on the transport
1501 * @param addrlen length of the address
1502 * @param expires when should this address automatically expire?
1505 plugin_env_notify_address (void *cls,
1509 struct GNUNET_TIME_Relative expires)
1511 struct TransportPlugin *p = cls;
1512 struct AddressList *al;
1513 struct GNUNET_TIME_Absolute abex;
1515 abex = GNUNET_TIME_relative_to_absolute (expires);
1516 GNUNET_assert (p == find_transport (name));
1521 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1523 if (al->expires.value < abex.value)
1530 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1532 al->next = p->addresses;
1535 al->addrlen = addrlen;
1536 memcpy (&al[1], addr, addrlen);
1537 update_addresses (p, GNUNET_YES);
1542 * Notify all of our clients about a peer connecting.
1545 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1546 struct GNUNET_TIME_Relative latency)
1548 struct ConnectInfoMessage cim;
1549 struct TransportClient *cpos;
1551 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1552 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1553 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1554 cim.latency = GNUNET_TIME_relative_hton (latency);
1555 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1557 while (cpos != NULL)
1559 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1566 * Notify all of our clients about a peer disconnecting.
1569 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1571 struct DisconnectInfoMessage dim;
1572 struct TransportClient *cpos;
1574 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1575 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1576 dim.reserved = htonl (0);
1577 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1579 while (cpos != NULL)
1581 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1588 * Copy any validated addresses to buf.
1590 * @return 0 once all addresses have been
1594 list_validated_addresses (void *cls, size_t max, void *buf)
1596 struct ValidationAddress **va = cls;
1599 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1603 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1605 (*va)->peer_address->addr, (*va)->peer_address->addrlen, buf, max);
1612 * HELLO validation cleanup task.
1615 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1617 struct ValidationAddress *va;
1618 struct ValidationList *pos;
1619 struct ValidationList *prev;
1620 struct GNUNET_TIME_Absolute now;
1621 struct GNUNET_TIME_Absolute first;
1622 struct GNUNET_HELLO_Message *hello;
1623 struct GNUNET_PeerIdentity pid;
1624 struct NeighborList *n;
1626 now = GNUNET_TIME_absolute_get ();
1628 pos = pending_validations;
1631 if (pos->timeout.value < now.value)
1634 pending_validations = pos->next;
1636 prev->next = pos->next;
1637 va = pos->addresses;
1638 hello = GNUNET_HELLO_create (&pos->publicKey,
1639 &list_validated_addresses, &va);
1640 GNUNET_CRYPTO_hash (&pos->publicKey,
1642 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1646 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1647 "HELLO", GNUNET_i2s (&pid));
1649 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1650 n = find_neighbor (&pid);
1653 try_transmission_to_peer (n);
1655 GNUNET_free (hello);
1656 while (NULL != (va = pos->addresses))
1658 pos->addresses = va->next;
1659 GNUNET_free (va->transport_name);
1664 pos = pending_validations;
1673 /* finally, reschedule cleanup if needed; list is
1674 ordered by timeout, so we need the last element... */
1675 if (NULL != pending_validations)
1677 first = pending_validations->timeout;
1678 pos = pending_validations;
1681 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1684 if (tc->reason != GNUNET_SCHEDULER_REASON_SHUTDOWN)
1686 GNUNET_SCHEDULER_add_delayed (sched,
1687 GNUNET_TIME_absolute_get_remaining
1688 (first), &cleanup_validation, NULL);
1695 * Function that will be called if we receive a validation
1696 * of an address challenge that we transmitted to another
1697 * peer. Note that the validation should only be considered
1698 * acceptable if the challenge matches AND if the sender
1699 * address is at least a plausible address for this peer
1700 * (otherwise we may be seeing a MiM attack).
1702 * @param cls closure
1703 * @param name name of the transport that generated the address
1704 * @param peer who responded to our challenge
1705 * @param challenge the challenge number we presumably used
1706 * @param sender_addr string describing our sender address (as observed
1707 * by the other peer in human-readable format)
1710 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1711 const struct GNUNET_PeerIdentity *peer,
1712 const char *sender_address,
1713 size_t sender_address_len)
1715 unsigned int not_done;
1717 struct ValidationList *pos;
1718 struct ValidationAddress *va;
1719 struct GNUNET_PeerIdentity id;
1720 const struct TransportPongMessage *pong = (const struct TransportPongMessage *)message;
1722 unsigned int challenge = ntohl(pong->challenge);
1723 pos = pending_validations;
1727 GNUNET_CRYPTO_hash (&pos->publicKey,
1729 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1731 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1738 /* TODO: call statistics (unmatched PONG) */
1739 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1741 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1742 GNUNET_i2s (peer), count);
1746 matched = GNUNET_NO;
1747 va = pos->addresses;
1750 if (va->challenge == challenge)
1753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1754 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1756 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
1757 va->peer_address->addrlen));
1759 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1761 ("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1762 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1763 ntohs(pong->addrlen)), va->transport_name);
1764 va->ok = GNUNET_YES;
1766 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1767 matched = GNUNET_YES;
1768 va->peer_address->connected = GNUNET_YES;
1769 va->peer_address->latency = GNUNET_TIME_absolute_get_difference(va->send_time, GNUNET_TIME_absolute_get());
1771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1772 "Confirmed validity of address, peer `%4s' has address `%s', latency of %llu\n",
1774 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
1775 va->peer_address->addrlen), (unsigned long long)va->peer_address->latency.value);
1777 va->peer_address->transmit_ready = GNUNET_YES;
1778 va->peer_address->expires = GNUNET_TIME_relative_to_absolute
1779 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1781 if (va->ok != GNUNET_YES)
1785 if (GNUNET_NO == matched)
1787 /* TODO: call statistics (unmatched PONG) */
1788 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1790 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1797 "All addresses validated, will now construct `%s' for `%4s'.\n",
1798 "HELLO", GNUNET_i2s (peer));
1800 pos->timeout.value = 0;
1801 GNUNET_SCHEDULER_add_with_priority (sched,
1802 GNUNET_SCHEDULER_PRIORITY_IDLE,
1803 &cleanup_validation, NULL);
1809 * Add an entry for each of our transport plugins
1810 * (that are able to send) to the list of plugins
1811 * for this neighbor.
1813 * @param neighbor to initialize
1816 add_plugins (struct NeighborList *neighbor)
1818 struct TransportPlugin *tp;
1819 struct ReadyList *rl;
1821 neighbor->retry_plugins_time
1822 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1826 if (tp->api->send != NULL)
1828 rl = GNUNET_malloc (sizeof (struct ReadyList));
1829 rl->next = neighbor->plugins;
1830 neighbor->plugins = rl;
1832 rl->neighbor = neighbor;
1833 rl->addresses = NULL;
1840 neighbor_timeout_task (void *cls,
1841 const struct GNUNET_SCHEDULER_TaskContext *tc)
1843 struct NeighborList *n = cls;
1846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1847 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1849 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1850 disconnect_neighbor (n, GNUNET_NO);
1854 * Create a fresh entry in our neighbor list for the given peer.
1855 * Will try to transmit our current HELLO to the new neighbor. Also
1856 * notifies our clients about the new "connection".
1858 * @param peer the peer for which we create the entry
1859 * @return the new neighbor list entry
1861 static struct NeighborList *
1862 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1864 struct NeighborList *n;
1866 GNUNET_assert (our_hello != NULL);
1867 n = GNUNET_malloc (sizeof (struct NeighborList));
1868 n->next = neighbors;
1871 n->last_quota_update = GNUNET_TIME_absolute_get ();
1873 GNUNET_TIME_relative_to_absolute
1874 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1875 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1877 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1878 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1879 &neighbor_timeout_task, n);
1880 transmit_to_peer (NULL, NULL, 0,
1881 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1883 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1887 static struct PeerAddressList *
1888 add_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1890 /* FIXME: should return a list of PeerAddressLists, support for multiple transports! */
1891 struct ReadyList *head = neighbor->plugins;
1892 struct PeerAddressList * new_address;
1894 GNUNET_assert(addr != NULL);
1897 while (head != NULL)
1899 new_address = GNUNET_malloc(sizeof(struct PeerAddressList));
1900 new_address->addr = GNUNET_malloc(addrlen);
1901 memcpy(new_address->addr, addr, addrlen);
1902 new_address->addrlen = addrlen;
1903 new_address->connect_attempts = 0;
1904 new_address->connected = GNUNET_YES; /* Set connected to GNUNET_YES, assuming that we're good */
1905 new_address->expires = GNUNET_TIME_relative_to_absolute
1906 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1907 new_address->latency = GNUNET_TIME_relative_get_forever();
1908 new_address->neighbor = neighbor;
1909 new_address->plugin = head->plugin;
1910 new_address->transmit_ready = GNUNET_YES;
1911 new_address->timeout = GNUNET_TIME_relative_to_absolute
1912 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); /* FIXME: Do we need this? */
1913 new_address->ready_list = head;
1914 new_address->next = head->addresses;
1915 head->addresses = new_address;
1922 static struct PeerAddressList *
1923 find_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1925 struct ReadyList *head = neighbor->plugins;
1926 struct PeerAddressList *address_head;
1927 while (head != NULL)
1929 address_head = head->addresses;
1930 while ((address_head != NULL) &&
1931 (address_head->addrlen != addrlen) &&
1932 (memcmp(address_head->addr, addr, addrlen) != 0))
1934 address_head = address_head->next;
1936 if (address_head != NULL)
1937 return address_head;
1945 * Append the given address to the list of entries
1946 * that need to be validated.
1949 run_validation (void *cls,
1951 struct GNUNET_TIME_Absolute expiration,
1952 const void *addr, size_t addrlen)
1954 struct ValidationList *e = cls;
1955 struct TransportPlugin *tp;
1956 struct ValidationAddress *va;
1957 struct GNUNET_PeerIdentity id;
1958 struct NeighborList *neighbor;
1959 struct PeerAddressList *peer_address;
1961 struct TransportPingMessage *ping;
1963 uint16_t hello_size;
1966 tp = find_transport (tname);
1969 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1970 GNUNET_ERROR_TYPE_BULK,
1972 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1976 GNUNET_CRYPTO_hash (&e->publicKey,
1978 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1982 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1983 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1985 va = GNUNET_malloc (sizeof (struct ValidationAddress));
1986 va->next = e->addresses;
1988 va->transport_name = GNUNET_strdup (tname);
1989 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1991 va->send_time = GNUNET_TIME_absolute_get();
1993 neighbor = find_neighbor(&id);
1995 if (neighbor == NULL)
1996 neighbor = setup_new_neighbor(&id);
1998 peer_address = find_peer_address(neighbor, addr, addrlen);
1999 if (peer_address == NULL)
2001 peer_address = add_peer_address(neighbor, addr, addrlen);
2004 GNUNET_assert(peer_address != NULL);
2006 va->peer_address = peer_address; /* Back pointer FIXME: remove this nonsense! */
2007 peer_address->validation = va;
2009 hello_size = GNUNET_HELLO_size(our_hello);
2010 tsize = sizeof(struct TransportPingMessage) + hello_size;
2012 message_buf = GNUNET_malloc(tsize);
2014 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
2015 ping->challenge = htonl(va->challenge);
2016 ping->header.size = htons(sizeof(struct TransportPingMessage));
2017 ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2018 memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
2021 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2022 "`%s' message size is %u, ping size is %u, total size is %u\n",
2025 sizeof(struct TransportPingMessage),
2028 memcpy(message_buf, our_hello, hello_size);
2029 memcpy(&message_buf[hello_size],
2031 sizeof(struct TransportPingMessage));
2034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2035 "Sending `%s' message of size %u to address `%s' via `%s' for `%4s'\n",
2037 tsize, GNUNET_a2s (addr, addrlen),
2038 tname, GNUNET_i2s (&id));
2040 sent = transmit_to_peer(NULL, peer_address,
2041 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2042 message_buf, tsize, GNUNET_NO, neighbor);
2045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2046 "Transport returned %d from send!\n", sent);
2050 GNUNET_free(message_buf);
2056 * Check if addresses in validated hello "h" overlap with
2057 * those in "chvc->hello" and update "chvc->hello" accordingly,
2058 * removing those addresses that have already been validated.
2061 check_hello_validated (void *cls,
2062 const struct GNUNET_PeerIdentity *peer,
2063 const struct GNUNET_HELLO_Message *h, uint32_t trust)
2065 struct CheckHelloValidatedContext *chvc = cls;
2066 struct ValidationAddress *va;
2067 struct TransportPlugin *tp;
2070 struct GNUNET_PeerIdentity apeer;
2072 first_call = GNUNET_NO;
2073 if (chvc->e == NULL)
2076 first_call = GNUNET_YES;
2077 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
2078 GNUNET_assert (GNUNET_OK ==
2079 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
2080 &chvc->e->publicKey));
2082 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
2083 chvc->e->next = pending_validations;
2084 pending_validations = chvc->e;
2089 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2091 GNUNET_TIME_absolute_get (),
2092 &run_validation, chvc->e);
2094 else if (GNUNET_YES == first_call)
2096 /* no existing HELLO, all addresses are new */
2097 GNUNET_HELLO_iterate_addresses (chvc->hello,
2098 GNUNET_NO, &run_validation, chvc->e);
2102 return; /* wait for next call */
2103 /* finally, transmit validation attempts */
2104 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
2106 va = chvc->e->addresses;
2111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2112 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
2115 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
2116 va->peer_address->addrlen), GNUNET_i2s (&apeer));
2118 tp = find_transport (va->transport_name);
2119 GNUNET_assert (tp != NULL);
2120 /* This validation should happen inside the transport, not from the plugin! */
2121 va->ok = GNUNET_SYSERR;
2126 GNUNET_SCHEDULER_add_delayed (sched,
2127 GNUNET_TIME_absolute_get_remaining (chvc->
2129 &cleanup_validation, NULL);
2135 * Process HELLO-message.
2137 * @param plugin transport involved, may be NULL
2138 * @param message the actual message
2139 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2142 process_hello (struct TransportPlugin *plugin,
2143 const struct GNUNET_MessageHeader *message)
2145 struct ValidationList *e;
2147 struct GNUNET_PeerIdentity target;
2148 const struct GNUNET_HELLO_Message *hello;
2149 struct CheckHelloValidatedContext *chvc;
2150 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2152 hsize = ntohs (message->size);
2153 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2154 (hsize < sizeof (struct GNUNET_MessageHeader)))
2157 return GNUNET_SYSERR;
2159 /* first, check if load is too high */
2160 if (GNUNET_OS_load_cpu_get (cfg) > 100)
2162 /* TODO: call to stats? */
2165 hello = (const struct GNUNET_HELLO_Message *) message;
2166 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2168 GNUNET_break_op (0);
2169 return GNUNET_SYSERR;
2171 GNUNET_CRYPTO_hash (&publicKey,
2172 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2173 &target.hashPubKey);
2175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2176 "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
2177 "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
2181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2182 "Notifying peerinfo about peer %s\n",
2183 GNUNET_i2s (&target));
2186 /* check if a HELLO for this peer is already on the validation list */
2187 e = pending_validations;
2190 if (0 == memcmp (&e->publicKey,
2193 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
2195 /* TODO: call to stats? */
2197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2198 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
2199 "HELLO", GNUNET_i2s (&target));
2205 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2206 chvc->plugin = plugin;
2207 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
2209 memcpy (chvc->hello, hello, hsize);
2210 /* finally, check if HELLO was previously validated
2211 (continuation will then schedule actual validation) */
2212 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2216 HELLO_VERIFICATION_TIMEOUT,
2217 &check_hello_validated, chvc);
2223 * The peer specified by the given neighbor has timed-out or a plugin
2224 * has disconnected. We may either need to do nothing (other plugins
2225 * still up), or trigger a full disconnect and clean up. This
2226 * function updates our state and does the necessary notifications.
2227 * Also notifies our clients that the neighbor is now officially
2230 * @param n the neighbor list entry for the peer
2231 * @param check should we just check if all plugins
2232 * disconnected or must we ask all plugins to
2236 disconnect_neighbor (struct NeighborList *current_handle, int check)
2238 struct ReadyList *rpos;
2239 struct NeighborList *npos;
2240 struct NeighborList *nprev;
2241 struct NeighborList *n;
2242 struct MessageQueue *mq;
2243 struct PeerAddressList *peer_addresses;
2244 struct PeerAddressList *peer_pos;
2246 if (neighbors == NULL)
2247 return; /* We don't have any neighbors, so client has an already removed handle! */
2250 while ((npos != NULL) && (current_handle != npos))
2254 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2258 if (GNUNET_YES == check)
2261 while (NULL != rpos)
2263 peer_addresses = rpos->addresses;
2264 while (peer_addresses != NULL)
2266 if (GNUNET_YES == peer_addresses->connected)
2267 return; /* still connected */
2268 peer_addresses = peer_addresses->next;
2275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2276 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2278 /* remove n from neighbors list */
2281 while ((npos != NULL) && (npos != n))
2286 GNUNET_assert (npos != NULL);
2288 neighbors = n->next;
2290 nprev->next = n->next;
2292 /* notify all clients about disconnect */
2293 notify_clients_disconnect (&n->id);
2295 /* clean up all plugins, cancel connections and pending transmissions */
2296 while (NULL != (rpos = n->plugins))
2298 n->plugins = rpos->next;
2299 GNUNET_assert (rpos->neighbor == n);
2300 if (GNUNET_YES == rpos->connected)
2301 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2303 while (rpos->addresses != NULL)
2305 peer_pos = rpos->addresses;
2306 rpos->addresses = peer_pos->next;
2307 GNUNET_free(peer_pos->addr);
2308 GNUNET_free(peer_pos);
2313 /* free all messages on the queue */
2314 while (NULL != (mq = n->messages))
2316 n->messages = mq->next;
2317 GNUNET_assert (0 == memcmp(mq->neighbor_id, &n->id, sizeof(struct GNUNET_PeerIdentity)));
2318 GNUNET_free (mq->neighbor_id);
2321 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2322 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2323 /* finally, free n itself */
2329 * We have received a PING message from someone. Need to send a PONG message
2330 * in response to the peer by any means necessary. Of course, with something
2331 * like TCP where a connection exists, we may want to send it that way. But
2332 * we may not be able to make that distinction...
2334 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2335 const struct GNUNET_PeerIdentity *peer,
2336 const char *sender_address,
2337 size_t sender_address_len)
2339 struct TransportPlugin *plugin = cls;
2340 struct TransportPingMessage *ping;
2341 struct TransportPongMessage *pong;
2342 struct PeerAddressList *peer_address;
2344 struct NeighborList *n;
2347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2348 "Processing `%s' from `%s'\n",
2349 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2352 msize = ntohs (message->size);
2353 if (msize < sizeof (struct TransportPingMessage))
2355 GNUNET_break_op (0);
2356 return GNUNET_SYSERR;
2358 ping = (struct TransportPingMessage *) message;
2359 if (0 != memcmp (&ping->target,
2360 plugin->env.my_identity,
2361 sizeof (struct GNUNET_PeerIdentity)))
2363 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2364 _("Received `%s' message not destined for me!\n"), "PING");
2365 return GNUNET_SYSERR;
2368 msize -= sizeof (struct TransportPingMessage);
2370 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2371 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2372 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2373 pong->purpose.size =
2374 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2376 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2377 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2378 pong->challenge = ping->challenge;
2379 pong->addrlen = htons(sender_address_len);
2381 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2382 memcpy (&pong[1], sender_address, sender_address_len);
2383 GNUNET_assert (GNUNET_OK ==
2384 GNUNET_CRYPTO_rsa_sign (my_private_key,
2385 &pong->purpose, &pong->signature));
2387 n = find_neighbor(peer);
2389 n = setup_new_neighbor(peer);
2391 peer_address = find_peer_address(n, sender_address, sender_address_len);
2392 if (peer_address == NULL)
2393 peer_address = add_peer_address(n, sender_address, sender_address_len);
2395 peer_address->timeout = GNUNET_TIME_relative_to_absolute(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2397 /* We don't use the peer_address because the address we received the message from may not
2398 * be a reliable way to send it back! We add it to the list which should queue up a separate
2399 * ping to determine if the address is viable.
2401 transmit_to_peer(NULL, NULL, TRANSPORT_DEFAULT_PRIORITY, (char *)pong, ntohs(pong->header.size), GNUNET_NO, n);
2408 * Function called by the plugin for each received message.
2409 * Update data volumes, possibly notify plugins about
2410 * reducing the rate at which they read from the socket
2411 * and generally forward to our receive callback.
2413 * @param cls the "struct TransportPlugin *" we gave to the plugin
2414 * @param message the message, NULL if peer was disconnected
2415 * @param distance the transport cost to this peer (not latency!)
2416 * @param sender_address the address that the sender reported
2417 * (opaque to transport service)
2418 * @param sender_address_len the length of the sender address
2419 * @param peer (claimed) identity of the other peer
2420 * @return the new service_context that the plugin should use
2421 * for future receive calls for messages from this
2426 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2427 const struct GNUNET_MessageHeader *message,
2428 unsigned int distance, const char *sender_address,
2429 size_t sender_address_len)
2431 struct ReadyList *service_context;
2432 struct TransportPlugin *plugin = cls;
2433 struct TransportClient *cpos;
2434 struct InboundMessage *im;
2435 struct PeerAddressList *peer_address;
2437 struct NeighborList *n;
2439 n = find_neighbor (peer);
2442 if (message == NULL)
2443 return; /* disconnect of peer already marked down */
2444 n = setup_new_neighbor (peer);
2448 peer_address = find_peer_address(n, sender_address, sender_address_len);
2449 if (peer_address == NULL)
2450 peer_address = add_peer_address(n, sender_address, sender_address_len);
2452 service_context = n->plugins;
2453 while ((service_context != NULL) && (plugin != service_context->plugin))
2454 service_context = service_context->next;
2455 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2456 if (message == NULL)
2459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2460 "Receive failed from `%4s', triggering disconnect\n",
2461 GNUNET_i2s (&n->id));
2463 /* TODO: call stats */
2464 if (service_context != NULL)
2465 service_context->connected = GNUNET_NO;
2466 disconnect_neighbor (n, GNUNET_YES);
2470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2471 "Processing message of type %u received by plugin...\n",
2472 ntohs (message->type));
2474 if (service_context != NULL)
2476 if (service_context->connected == GNUNET_NO)
2478 /*service_context->connected = GNUNET_YES;*/
2479 /* FIXME: What to do here? Should we use these as well, to specify some Address
2480 * in the AddressList should be available?
2482 peer_address->transmit_ready = GNUNET_YES;
2483 peer_address->connect_attempts++;
2485 peer_address->timeout
2487 GNUNET_TIME_relative_to_absolute
2488 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2490 /* update traffic received amount ... */
2491 msize = ntohs (message->size);
2492 n->last_received += msize;
2493 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2495 GNUNET_TIME_relative_to_absolute
2496 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2498 GNUNET_SCHEDULER_add_delayed (sched,
2499 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2500 &neighbor_timeout_task, n);
2502 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2504 /* dropping message due to frequent inbound volume violations! */
2505 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2506 GNUNET_ERROR_TYPE_BULK,
2508 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2509 /* TODO: call stats */
2510 GNUNET_assert ((service_context == NULL) ||
2511 (NULL != service_context->neighbor));
2515 switch (ntohs (message->type))
2517 case GNUNET_MESSAGE_TYPE_HELLO:
2519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2520 "Receiving `%s' message from `%4s'.\n", "HELLO",
2523 process_hello (plugin, message);
2525 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2528 "Receiving `%s' message from `%4s'.\n", "PING",
2531 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2533 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2536 "Receiving `%s' message from `%4s'.\n", "PONG",
2539 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2544 "Received REAL MESSAGE type %u from `%4s', sending to all clients.\n",
2545 ntohs (message->type), GNUNET_i2s (peer));
2547 /* transmit message to all clients */
2548 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2549 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2550 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2551 im->latency = n->latency;
2553 memcpy (&im[1], message, msize);
2556 while (cpos != NULL)
2558 transmit_to_client (cpos, &im->header, GNUNET_YES);
2563 GNUNET_assert ((service_context == NULL) ||
2564 (NULL != service_context->neighbor));
2569 * Handle START-message. This is the first message sent to us
2570 * by any client which causes us to add it to our list.
2572 * @param cls closure (always NULL)
2573 * @param client identification of the client
2574 * @param message the actual message
2577 handle_start (void *cls,
2578 struct GNUNET_SERVER_Client *client,
2579 const struct GNUNET_MessageHeader *message)
2581 struct TransportClient *c;
2582 struct ConnectInfoMessage cim;
2583 struct NeighborList *n;
2584 struct InboundMessage *im;
2585 struct GNUNET_MessageHeader *ack;
2588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2589 "Received `%s' request from client\n", "START");
2594 if (c->client == client)
2596 /* client already on our list! */
2598 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2603 c = GNUNET_malloc (sizeof (struct TransportClient));
2607 if (our_hello != NULL)
2610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2611 "Sending our own `%s' to new client\n", "HELLO");
2613 transmit_to_client (c,
2614 (const struct GNUNET_MessageHeader *) our_hello,
2616 /* tell new client about all existing connections */
2617 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2618 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2620 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2621 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2622 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2623 sizeof (struct GNUNET_MessageHeader));
2624 im->header.size = htons (sizeof (struct InboundMessage) +
2625 sizeof (struct GNUNET_MessageHeader));
2626 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2627 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2628 ack = (struct GNUNET_MessageHeader *) &im[1];
2629 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2630 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2631 for (n = neighbors; n != NULL; n = n->next)
2634 transmit_to_client (c, &cim.header, GNUNET_NO);
2635 if (n->received_pong)
2638 transmit_to_client (c, &im->header, GNUNET_NO);
2645 fprintf(stderr, "Our hello is NULL!\n");
2647 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2652 * Handle HELLO-message.
2654 * @param cls closure (always NULL)
2655 * @param client identification of the client
2656 * @param message the actual message
2659 handle_hello (void *cls,
2660 struct GNUNET_SERVER_Client *client,
2661 const struct GNUNET_MessageHeader *message)
2666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2667 "Received `%s' request from client\n", "HELLO");
2669 ret = process_hello (NULL, message);
2670 GNUNET_SERVER_receive_done (client, ret);
2675 * Handle SEND-message.
2677 * @param cls closure (always NULL)
2678 * @param client identification of the client
2679 * @param message the actual message
2682 handle_send (void *cls,
2683 struct GNUNET_SERVER_Client *client,
2684 const struct GNUNET_MessageHeader *message)
2686 struct TransportClient *tc;
2687 struct NeighborList *n;
2688 const struct OutboundMessage *obm;
2689 const struct GNUNET_MessageHeader *obmm;
2693 size = ntohs (message->size);
2695 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2698 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2701 obm = (const struct OutboundMessage *) message;
2703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2704 "Received `%s' request from client with target `%4s'\n",
2705 "SEND", GNUNET_i2s (&obm->peer));
2707 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2708 msize = ntohs (obmm->size);
2709 if (size != msize + sizeof (struct OutboundMessage))
2712 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2715 n = find_neighbor (&obm->peer);
2717 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2719 while ((tc != NULL) && (tc->client != client))
2723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2724 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2726 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2728 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, ntohs (obmm->size), GNUNET_NO, n);
2729 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2734 * Handle SET_QUOTA-message.
2736 * @param cls closure (always NULL)
2737 * @param client identification of the client
2738 * @param message the actual message
2741 handle_set_quota (void *cls,
2742 struct GNUNET_SERVER_Client *client,
2743 const struct GNUNET_MessageHeader *message)
2745 const struct QuotaSetMessage *qsm =
2746 (const struct QuotaSetMessage *) message;
2747 struct NeighborList *n;
2748 struct TransportPlugin *p;
2749 struct ReadyList *rl;
2751 n = find_neighbor (&qsm->peer);
2754 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2760 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2761 "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2765 if (n->quota_in < ntohl (qsm->quota_in))
2766 n->last_quota_update = GNUNET_TIME_absolute_get ();
2767 n->quota_in = ntohl (qsm->quota_in);
2772 p->api->set_receive_quota (p->api->cls,
2773 &qsm->peer, ntohl (qsm->quota_in));
2776 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2781 * Handle TRY_CONNECT-message.
2783 * @param cls closure (always NULL)
2784 * @param client identification of the client
2785 * @param message the actual message
2788 handle_try_connect (void *cls,
2789 struct GNUNET_SERVER_Client *client,
2790 const struct GNUNET_MessageHeader *message)
2792 const struct TryConnectMessage *tcm;
2793 struct NeighborList *neighbor;
2794 tcm = (const struct TryConnectMessage *) message;
2796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2797 "Received `%s' request from client %p asking to connect to `%4s'\n",
2798 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2800 neighbor = find_neighbor(&tcm->peer);
2802 if (neighbor == NULL)
2803 setup_new_neighbor (&tcm->peer);
2807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2808 "Client asked to connect to `%4s', but connection already exists\n",
2809 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2811 transmit_to_peer (NULL, NULL, 0,
2812 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2813 GNUNET_YES, neighbor);
2814 notify_clients_connect (&tcm->peer, GNUNET_TIME_UNIT_FOREVER_REL);
2816 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);
2836 * Handle AddressLookup-message.
2838 * @param cls closure (always NULL)
2839 * @param client identification of the client
2840 * @param message the actual message
2843 handle_address_lookup (void *cls,
2844 struct GNUNET_SERVER_Client *client,
2845 const struct GNUNET_MessageHeader *message)
2847 const struct AddressLookupMessage *alum;
2848 struct TransportPlugin *lsPlugin;
2849 const char *nameTransport;
2850 const char *address;
2852 struct GNUNET_SERVER_TransmitContext *tc;
2854 size = ntohs (message->size);
2855 if (size < sizeof (struct AddressLookupMessage))
2857 GNUNET_break_op (0);
2858 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2861 alum = (const struct AddressLookupMessage *) message;
2862 uint32_t addressLen = ntohl (alum->addrlen);
2863 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2865 GNUNET_break_op (0);
2866 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2869 address = (const char *) &alum[1];
2870 nameTransport = (const char *) &address[addressLen];
2872 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2874 GNUNET_break_op (0);
2875 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2878 struct GNUNET_TIME_Absolute timeout =
2879 GNUNET_TIME_absolute_ntoh (alum->timeout);
2880 struct GNUNET_TIME_Relative rtimeout =
2881 GNUNET_TIME_absolute_get_remaining (timeout);
2882 lsPlugin = find_transport (nameTransport);
2883 if (NULL == lsPlugin)
2885 tc = GNUNET_SERVER_transmit_context_create (client);
2886 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2887 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2888 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2891 tc = GNUNET_SERVER_transmit_context_create (client);
2892 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2893 address, addressLen, GNUNET_YES,
2895 &transmit_address_to_client, tc);
2899 * List of handlers for the messages understood by this
2902 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2903 {&handle_start, NULL,
2904 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2905 {&handle_hello, NULL,
2906 GNUNET_MESSAGE_TYPE_HELLO, 0},
2907 {&handle_send, NULL,
2908 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2909 {&handle_set_quota, NULL,
2910 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2911 {&handle_try_connect, NULL,
2912 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2913 sizeof (struct TryConnectMessage)},
2914 {&handle_address_lookup, NULL,
2915 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2922 * Setup the environment for this plugin.
2925 create_environment (struct TransportPlugin *plug)
2927 plug->env.cfg = cfg;
2928 plug->env.sched = sched;
2929 plug->env.my_identity = &my_identity;
2930 plug->env.cls = plug;
2931 plug->env.receive = &plugin_env_receive;
2932 plug->env.notify_address = &plugin_env_notify_address;
2933 plug->env.default_quota_in =
2934 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2935 plug->env.max_connections = max_connect_per_transport;
2940 * Start the specified transport (load the plugin).
2943 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2945 struct TransportPlugin *plug;
2948 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2949 _("Loading `%s' transport plugin\n"), name);
2950 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2951 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2952 create_environment (plug);
2953 plug->short_name = GNUNET_strdup (name);
2954 plug->lib_name = libname;
2955 plug->next = plugins;
2957 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2958 if (plug->api == NULL)
2960 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2961 _("Failed to load transport plugin for `%s'\n"), name);
2962 GNUNET_free (plug->short_name);
2963 plugins = plug->next;
2964 GNUNET_free (libname);
2971 * Called whenever a client is disconnected. Frees our
2972 * resources associated with that client.
2974 * @param cls closure
2975 * @param client identification of the client
2978 client_disconnect_notification (void *cls,
2979 struct GNUNET_SERVER_Client *client)
2981 struct TransportClient *pos;
2982 struct TransportClient *prev;
2983 struct ClientMessageQueueEntry *mqe;
2988 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2989 "Client disconnected, cleaning up.\n");
2993 while ((pos != NULL) && (pos->client != client))
3000 while (NULL != (mqe = pos->message_queue_head))
3002 pos->message_queue_head = mqe->next;
3005 pos->message_queue_head = NULL;
3007 clients = pos->next;
3009 prev->next = pos->next;
3010 if (GNUNET_YES == pos->tcs_pending)
3020 * Function called when the service shuts down. Unloads our plugins.
3022 * @param cls closure, unused
3023 * @param tc task context (unused)
3026 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3028 struct TransportPlugin *plug;
3029 struct AddressList *al;
3032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3033 "Transport service is unloading plugins...\n");
3035 while (NULL != (plug = plugins))
3037 plugins = plug->next;
3038 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3039 GNUNET_free (plug->lib_name);
3040 GNUNET_free (plug->short_name);
3041 while (NULL != (al = plug->addresses))
3043 plug->addresses = al->next;
3048 if (my_private_key != NULL)
3049 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3050 GNUNET_free_non_null (our_hello);
3055 * Initiate transport service.
3057 * @param cls closure
3058 * @param s scheduler to use
3059 * @param serv the initialized server
3060 * @param c configuration to use
3064 struct GNUNET_SCHEDULER_Handle *s,
3065 struct GNUNET_SERVER_Handle *serv,
3066 const struct GNUNET_CONFIGURATION_Handle *c)
3071 unsigned long long tneigh;
3076 /* parse configuration */
3078 GNUNET_CONFIGURATION_get_value_number (c,
3083 GNUNET_CONFIGURATION_get_value_filename (c,
3085 "HOSTKEY", &keyfile)))
3087 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3089 ("Transport service is lacking key configuration settings. Exiting.\n"));
3090 GNUNET_SCHEDULER_shutdown (s);
3093 max_connect_per_transport = (uint32_t) tneigh;
3094 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3095 GNUNET_free (keyfile);
3096 if (my_private_key == NULL)
3098 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3100 ("Transport service could not access hostkey. Exiting.\n"));
3101 GNUNET_SCHEDULER_shutdown (s);
3104 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3105 GNUNET_CRYPTO_hash (&my_public_key,
3106 sizeof (my_public_key), &my_identity.hashPubKey);
3107 /* setup notification */
3109 GNUNET_SERVER_disconnect_notify (server,
3110 &client_disconnect_notification, NULL);
3111 /* load plugins... */
3114 GNUNET_CONFIGURATION_get_value_string (c,
3115 "TRANSPORT", "PLUGINS", &plugs))
3117 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3118 _("Starting transport plugins `%s'\n"), plugs);
3119 pos = strtok (plugs, " ");
3122 start_transport (server, pos);
3124 pos = strtok (NULL, " ");
3126 GNUNET_free (plugs);
3128 GNUNET_SCHEDULER_add_delayed (sched,
3129 GNUNET_TIME_UNIT_FOREVER_REL,
3130 &unload_plugins, NULL);
3135 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3137 /* process client requests */
3138 GNUNET_SERVER_add_handlers (server, handlers);
3143 * The main function for the transport service.
3145 * @param argc number of arguments from the command line
3146 * @param argv command line arguments
3147 * @return 0 ok, 1 on error
3150 main (int argc, char *const *argv)
3152 return (GNUNET_OK ==
3153 GNUNET_SERVICE_run (argc,
3156 GNUNET_SERVICE_OPTION_NONE,
3157 &run, NULL)) ? 0 : 1;
3160 /* end of gnunet-service-transport.c */