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 * - if we do not receive an ACK in response to our
28 * HELLO, retransmit HELLO!
31 #include "gnunet_client_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_getopt_lib.h"
34 #include "gnunet_hello_lib.h"
35 #include "gnunet_os_lib.h"
36 #include "gnunet_peerinfo_service.h"
37 #include "gnunet_plugin_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_service_lib.h"
40 #include "gnunet_signatures.h"
41 #include "plugin_transport.h"
42 #include "transport.h"
45 * How many messages can we have pending for a given client process
46 * before we start to drop incoming messages? We typically should
47 * have only one client and so this would be the primary buffer for
48 * messages, so the number should be chosen rather generously.
50 * The expectation here is that most of the time the queue is large
51 * enough so that a drop is virtually never required.
53 #define MAX_PENDING 128
56 * How often should we try to reconnect to a peer using a particular
57 * transport plugin before giving up? Note that the plugin may be
58 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
60 #define MAX_CONNECT_RETRY 3
63 * How often must a peer violate bandwidth quotas before we start
64 * to simply drop its messages?
66 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
69 * How long until a HELLO verification attempt should time out?
70 * Must be rather small, otherwise a partially successful HELLO
71 * validation (some addresses working) might not be available
72 * before a client's request for a connection fails for good.
73 * Besides, if a single request to an address takes a long time,
74 * then the peer is unlikely worthwhile anyway.
76 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
79 * How long will we allow sending of a ping to be delayed?
81 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
83 #define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */
86 * How often do we re-add (cheaper) plugins to our list of plugins
87 * to try for a given connected peer?
89 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
92 * After how long do we expire an address in a HELLO
93 * that we just validated? This value is also used
94 * for our own addresses when we create a HELLO.
96 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
100 * Entry in linked list of network addresses.
105 * This is a linked list.
107 struct AddressList *next;
110 * The address, actually a pointer to the end
111 * of this struct. Do not free!
116 * How long until we auto-expire this address (unless it is
117 * re-confirmed by the transport)?
119 struct GNUNET_TIME_Absolute expires;
130 * Entry in linked list of all of our plugins.
132 struct TransportPlugin
136 * This is a linked list.
138 struct TransportPlugin *next;
141 * API of the transport as returned by the plugin's
142 * initialization function.
144 struct GNUNET_TRANSPORT_PluginFunctions *api;
147 * Short name for the plugin (i.e. "tcp").
152 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
157 * List of our known addresses for this transport.
159 struct AddressList *addresses;
162 * Environment this transport service is using
165 struct GNUNET_TRANSPORT_PluginEnvironment env;
168 * ID of task that is used to clean up expired addresses.
170 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
174 * Set to GNUNET_YES if we need to scrap the existing
175 * list of "addresses" and start fresh when we receive
176 * the next address update from a transport. Set to
177 * GNUNET_NO if we should just add the new address
178 * to the list and wait for the commit call.
186 * For each neighbor we keep a list of messages
187 * that we still want to transmit to the neighbor.
193 * This is a linked list.
195 struct MessageQueue *next;
198 * The message we want to transmit.
200 struct GNUNET_MessageHeader *message;
203 * Client responsible for queueing the message;
204 * used to check that a client has not two messages
205 * pending for the same target. Can be NULL.
207 struct TransportClient *client;
210 * Neighbor this entry belongs to.
212 struct NeighborList *neighbor;
215 * Plugin that we used for the transmission.
216 * NULL until we scheduled a transmission.
218 struct TransportPlugin *plugin;
221 * Internal message of the transport system that should not be
222 * included in the usual SEND-SEND_OK transmission confirmation
223 * traffic management scheme. Typically, "internal_msg" will
224 * be set whenever "client" is NULL (but it is not strictly
230 * How important is the message?
232 unsigned int priority;
238 * For a given Neighbor, which plugins are available
239 * to talk to this peer and what are their costs?
245 * This is a linked list.
247 struct ReadyList *next;
250 * Which of our transport plugins does this entry
253 struct TransportPlugin *plugin;
256 * Neighbor this entry belongs to.
258 struct NeighborList *neighbor;
261 * What was the last latency observed for this plugin
262 * and peer? Invalid if connected is GNUNET_NO.
264 struct GNUNET_TIME_Relative latency;
267 * If we did not successfully transmit a message to the given peer
268 * via this connection during the specified time, we should consider
269 * the connection to be dead. This is used in the case that a TCP
270 * transport simply stalls writing to the stream but does not
271 * formerly get a signal that the other peer died.
273 struct GNUNET_TIME_Absolute timeout;
276 * Is this plugin currently connected? The first time
277 * we transmit or send data to a peer via a particular
278 * plugin, we set this to GNUNET_YES. If we later get
279 * an error (disconnect notification or transmission
280 * failure), we set it back to GNUNET_NO. Each time the
281 * value is set to GNUNET_YES, we increment the
282 * "connect_attempts" counter. If that one reaches a
283 * particular threshold, we consider the plugin to not
284 * be working properly at this time for the given peer
285 * and remove it from the eligible list.
290 * How often have we tried to connect using this plugin?
292 unsigned int connect_attempts;
295 * Is this plugin ready to transmit to the specific target?
296 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
297 * transmission is in progress, "transmit_ready" is set to
306 * Entry in linked list of all of our current neighbors.
312 * This is a linked list.
314 struct NeighborList *next;
317 * Which of our transports is connected to this peer
318 * and what is their status?
320 struct ReadyList *plugins;
323 * List of messages we would like to send to this peer;
324 * must contain at most one message per client.
326 struct MessageQueue *messages;
329 * Identity of this neighbor.
331 struct GNUNET_PeerIdentity id;
334 * Opaque addr of this peer, only known to the plugin
344 * ID of task scheduled to run when this peer is about to
345 * time out (will free resources associated with the peer).
347 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
350 * How long until we should consider this peer dead
351 * (if we don't receive another message in the
354 struct GNUNET_TIME_Absolute peer_timeout;
357 * At what time did we reset last_received last?
359 struct GNUNET_TIME_Absolute last_quota_update;
362 * At what time should we try to again add plugins to
365 struct GNUNET_TIME_Absolute retry_plugins_time;
368 * How many bytes have we received since the "last_quota_update"
371 uint64_t last_received;
374 * Global quota for inbound traffic for the neighbor in bytes/ms.
379 * How often has the other peer (recently) violated the
380 * inbound traffic limit? Incremented by 10 per violation,
381 * decremented by 1 per non-violation (for each
384 unsigned int quota_violation_count;
387 * Have we seen an ACK from this neighbor in the past?
388 * (used to make up a fake ACK for clients connecting after
389 * the neighbor connected to us).
393 /* The latency we have seen for this particular address for
394 * this particular peer. This latency may have been calculated
395 * over multiple transports. This value reflects how long it took
396 * us to receive a response when SENDING via this particular
397 * transport/neighbor/address combination!
399 struct GNUNET_TIME_RelativeNBO latency;
404 * Message used to ask a peer to validate receipt (to check an address
405 * from a HELLO). Followed by the address used. Note that the
406 * recipients response does not affirm that he has this address,
407 * only that he got the challenge message.
409 struct TransportPingMessage
413 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
415 struct GNUNET_MessageHeader header;
418 * Random challenge number (in network byte order).
420 uint32_t challenge GNUNET_PACKED;
423 * Who is the intended recipient?
425 struct GNUNET_PeerIdentity target;
431 * Message used to validate a HELLO. The challenge is included in the
432 * confirmation to make matching of replies to requests possible. The
433 * signature signs the original challenge number, our public key, the
434 * sender's address (so that the sender can check that the address we
435 * saw is plausible for him and possibly detect a MiM attack) and a
436 * timestamp (to limit replay).<p>
438 * This message is followed by the address of the
439 * client that we are observing (which is part of what
442 struct TransportPongMessage
446 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
448 struct GNUNET_MessageHeader header;
451 * For padding, always zero.
453 uint32_t reserved GNUNET_PACKED;
458 struct GNUNET_CRYPTO_RsaSignature signature;
461 * What are we signing and why?
463 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
466 * Random challenge number (in network byte order).
468 uint32_t challenge GNUNET_PACKED;
471 * Who signed this message?
473 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
478 * Linked list of messages to be transmitted to
479 * the client. Each entry is followed by the
482 struct ClientMessageQueueEntry
485 * This is a linked list.
487 struct ClientMessageQueueEntry *next;
492 * Client connected to the transport service.
494 struct TransportClient
498 * This is a linked list.
500 struct TransportClient *next;
503 * Handle to the client.
505 struct GNUNET_SERVER_Client *client;
508 * Linked list of messages yet to be transmitted to
511 struct ClientMessageQueueEntry *message_queue_head;
514 * Tail of linked list of messages yet to be transmitted to the
517 struct ClientMessageQueueEntry *message_queue_tail;
520 * Is a call to "transmit_send_continuation" pending? If so, we
521 * must not free this struct (even if the corresponding client
522 * disconnects) and instead only remove it from the linked list and
523 * set the "client" field to NULL.
528 * Length of the list of messages pending for this client.
530 unsigned int message_count;
536 * For each HELLO, we may have to validate multiple addresses;
537 * each address gets its own request entry.
539 struct ValidationAddress
542 * This is a linked list.
544 struct ValidationAddress *next;
547 * Name of the transport.
549 char *transport_name;
552 * When should this validated address expire?
554 struct GNUNET_TIME_Absolute expiration;
557 * Length of the address we are validating.
562 * Challenge number we used.
567 * Set to GNUNET_YES if the challenge was met,
568 * GNUNET_SYSERR if we know it failed, GNUNET_NO
569 * if we are waiting on a response.
576 * Entry in linked list of all HELLOs awaiting validation.
578 struct ValidationList
582 * This is a linked list.
584 struct ValidationList *next;
587 * Linked list with one entry per address from the HELLO
588 * that needs to be validated.
590 struct ValidationAddress *addresses;
593 * The public key of the peer.
595 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
598 * When does this record time-out? (assuming the
599 * challenge goes unanswered)
601 struct GNUNET_TIME_Absolute timeout;
607 * HELLOs awaiting validation.
609 static struct ValidationList *pending_validations;
614 static struct GNUNET_HELLO_Message *our_hello;
617 * "version" of "our_hello". Used to see if a given
618 * neighbor has already been sent the latest version
619 * of our HELLO message.
621 static unsigned int our_hello_version;
626 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
631 static struct GNUNET_PeerIdentity my_identity;
636 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
641 struct GNUNET_SCHEDULER_Handle *sched;
646 const struct GNUNET_CONFIGURATION_Handle *cfg;
649 * Linked list of all clients to this service.
651 static struct TransportClient *clients;
654 * All loaded plugins.
656 static struct TransportPlugin *plugins;
661 static struct GNUNET_SERVER_Handle *server;
664 * All known neighbors and their HELLOs.
666 static struct NeighborList *neighbors;
669 * Number of neighbors we'd like to have.
671 static uint32_t max_connect_per_transport;
675 * Find an entry in the neighbor list for a particular peer.
676 * if sender_address is not specified (NULL) then return the
677 * first matching entry. If sender_address is specified, then
678 * make sure that the address and address_len also matches.
680 * @return NULL if not found.
682 static struct NeighborList *
683 find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
684 size_t sender_address_len)
686 struct NeighborList *head = neighbors;
687 if (sender_address == NULL)
689 while ((head != NULL) &&
690 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
695 while ((head != NULL) &&
696 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
697 (sender_address_len != head->addr_len) &&
698 (0 != memcmp (sender_address, &head->addr, head->addr_len)))
706 * Find an entry in the transport list for a particular transport.
708 * @return NULL if not found.
710 static struct TransportPlugin *
711 find_transport (const char *short_name)
713 struct TransportPlugin *head = plugins;
714 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
721 * Update the quota values for the given neighbor now.
724 update_quota (struct NeighborList *n)
726 struct GNUNET_TIME_Relative delta;
730 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
731 if (delta.value < MIN_QUOTA_REFRESH_TIME)
732 return; /* not enough time passed for doing quota update */
733 allowed = delta.value * n->quota_in;
734 if (n->last_received < allowed)
736 remaining = allowed - n->last_received;
738 remaining /= n->quota_in;
741 if (remaining > MAX_BANDWIDTH_CARRY)
742 remaining = MAX_BANDWIDTH_CARRY;
743 n->last_received = 0;
744 n->last_quota_update = GNUNET_TIME_absolute_get ();
745 n->last_quota_update.value -= remaining;
746 if (n->quota_violation_count > 0)
747 n->quota_violation_count--;
751 n->last_received -= allowed;
752 n->last_quota_update = GNUNET_TIME_absolute_get ();
753 if (n->last_received > allowed)
755 /* more than twice the allowed rate! */
756 n->quota_violation_count += 10;
763 * Function called to notify a client about the socket
764 * being ready to queue more data. "buf" will be
765 * NULL and "size" zero if the socket was closed for
766 * writing in the meantime.
769 * @param size number of bytes available in buf
770 * @param buf where the callee should write the message
771 * @return number of bytes written to buf
774 transmit_to_client_callback (void *cls, size_t size, void *buf)
776 struct TransportClient *client = cls;
777 struct ClientMessageQueueEntry *q;
780 const struct GNUNET_MessageHeader *msg;
781 struct GNUNET_CONNECTION_TransmitHandle *th;
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787 "Transmission to client failed, closing connection.\n");
788 /* fatal error with client, free message queue! */
789 while (NULL != (q = client->message_queue_head))
791 client->message_queue_head = q->next;
794 client->message_queue_tail = NULL;
795 client->message_count = 0;
800 while (NULL != (q = client->message_queue_head))
802 msg = (const struct GNUNET_MessageHeader *) &q[1];
803 msize = ntohs (msg->size);
804 if (msize + tsize > size)
807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
808 "Transmitting message of type %u to client.\n",
811 client->message_queue_head = q->next;
813 client->message_queue_tail = NULL;
814 memcpy (&cbuf[tsize], msg, msize);
817 client->message_count--;
821 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
822 th = GNUNET_SERVER_notify_transmit_ready (client->client,
824 GNUNET_TIME_UNIT_FOREVER_REL,
825 &transmit_to_client_callback,
827 GNUNET_assert (th != NULL);
834 * Send the specified message to the specified client. Since multiple
835 * messages may be pending for the same client at a time, this code
836 * makes sure that no message is lost.
838 * @param client client to transmit the message to
839 * @param msg the message to send
840 * @param may_drop can this message be dropped if the
841 * message queue for this client is getting far too large?
844 transmit_to_client (struct TransportClient *client,
845 const struct GNUNET_MessageHeader *msg, int may_drop)
847 struct ClientMessageQueueEntry *q;
849 struct GNUNET_CONNECTION_TransmitHandle *th;
851 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
853 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
855 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
856 client->message_count, MAX_PENDING);
857 /* TODO: call to statistics... */
860 client->message_count++;
861 msize = ntohs (msg->size);
862 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
863 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
864 memcpy (&q[1], msg, msize);
865 /* append to message queue */
866 if (client->message_queue_tail == NULL)
868 client->message_queue_tail = q;
872 client->message_queue_tail->next = q;
873 client->message_queue_tail = q;
875 if (client->message_queue_head == NULL)
877 client->message_queue_head = q;
878 th = GNUNET_SERVER_notify_transmit_ready (client->client,
880 GNUNET_TIME_UNIT_FOREVER_REL,
881 &transmit_to_client_callback,
883 GNUNET_assert (th != NULL);
889 * Find alternative plugins for communication.
891 * @param neighbor for which neighbor should we try to find
895 try_alternative_plugins (struct NeighborList *neighbor)
897 struct ReadyList *rl;
899 if ((neighbor->plugins != NULL) &&
900 (neighbor->retry_plugins_time.value >
901 GNUNET_TIME_absolute_get ().value))
902 return; /* don't try right now */
903 neighbor->retry_plugins_time
904 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
906 rl = neighbor->plugins;
909 if (rl->connect_attempts > 0)
910 rl->connect_attempts--; /* amnesty */
918 * The peer specified by the given neighbor has timed-out or a plugin
919 * has disconnected. We may either need to do nothing (other plugins
920 * still up), or trigger a full disconnect and clean up. This
921 * function updates our state and do the necessary notifications.
922 * Also notifies our clients that the neighbor is now officially
925 * @param n the neighbor list entry for the peer
926 * @param check should we just check if all plugins
927 * disconnected or must we ask all plugins to
930 static void disconnect_neighbor (struct NeighborList *n, int check);
934 * Check the ready list for the given neighbor and
935 * if a plugin is ready for transmission (and if we
936 * have a message), do so!
938 * @param neighbor target peer for which to check the plugins
940 static void try_transmission_to_peer (struct NeighborList *neighbor);
944 * Function called by the GNUNET_TRANSPORT_TransmitFunction
945 * upon "completion" of a send request. This tells the API
946 * that it is now legal to send another message to the given
949 * @param cls closure, identifies the entry on the
950 * message queue that was transmitted and the
951 * client responsible for queueing the message
952 * @param target the peer receiving the message
953 * @param result GNUNET_OK on success, if the transmission
954 * failed, we should not tell the client to transmit
958 transmit_send_continuation (void *cls,
959 const struct GNUNET_PeerIdentity *target,
962 struct MessageQueue *mq = cls;
963 struct ReadyList *rl;
964 struct SendOkMessage send_ok_msg;
965 struct NeighborList *n;
967 GNUNET_assert (mq != NULL);
969 GNUNET_assert (n != NULL);
971 memcmp (&n->id, target,
972 sizeof (struct GNUNET_PeerIdentity)));
974 while ((rl != NULL) && (rl->plugin != mq->plugin))
976 GNUNET_assert (rl != NULL);
977 if (result == GNUNET_OK)
980 GNUNET_TIME_relative_to_absolute
981 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
986 "Transmission to peer `%s' failed, marking connection as down.\n",
987 GNUNET_i2s (target));
988 rl->connected = GNUNET_NO;
990 if (!mq->internal_msg)
992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
993 "Setting transmit_ready on transport!\n");
994 rl->transmit_ready = GNUNET_YES;
997 if (mq->client != NULL)
999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1000 "Notifying client %p about failed transission to peer `%4s'.\n",
1001 mq->client, GNUNET_i2s (target));
1002 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1003 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1004 send_ok_msg.success = htonl (result);
1005 send_ok_msg.peer = n->id;
1006 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1008 GNUNET_free (mq->message);
1010 /* one plugin just became ready again, try transmitting
1011 another message (if available) */
1012 if (result == GNUNET_OK)
1013 try_transmission_to_peer (n);
1015 disconnect_neighbor (n, GNUNET_YES);
1020 * Check the ready list for the given neighbor and
1021 * if a plugin is ready for transmission (and if we
1022 * have a message), do so!
1025 try_transmission_to_peer (struct NeighborList *neighbor)
1027 struct ReadyList *pos;
1028 struct GNUNET_TIME_Relative min_latency;
1029 struct ReadyList *rl;
1030 struct MessageQueue *mq;
1031 struct GNUNET_TIME_Absolute now;
1033 if (neighbor->addr != NULL)
1035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036 _("try_transmission_to_peer entry: at this point neighbor->addr is NOT NULL\n"));
1040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("try_transmission_to_peer entry: at this point neighbor->addr is NULL\n"));
1043 if (neighbor->messages == NULL)
1044 return; /* nothing to do */
1045 try_alternative_plugins (neighbor);
1046 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1048 mq = neighbor->messages;
1049 now = GNUNET_TIME_absolute_get ();
1050 pos = neighbor->plugins;
1053 /* set plugins that are inactive for a long time back to disconnected */
1054 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1058 "Marking long-time inactive connection to `%4s' as down.\n",
1059 GNUNET_i2s (&neighbor->id));
1061 pos->connected = GNUNET_NO;
1063 if (GNUNET_YES == pos->transmit_ready)
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Found transmit_ready flag...\n");
1070 if (((GNUNET_YES == pos->transmit_ready) ||
1071 (mq->internal_msg)) &&
1072 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1073 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1076 min_latency = pos->latency;
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084 "No plugin ready to transmit message\n");
1086 return; /* nobody ready */
1088 if (GNUNET_NO == rl->connected)
1090 rl->connect_attempts++;
1091 rl->connected = GNUNET_YES;
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "Establishing fresh connection with `%4s' via plugin `%s'\n",
1095 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1098 neighbor->messages = mq->next;
1099 mq->plugin = rl->plugin;
1100 if (!mq->internal_msg)
1101 rl->transmit_ready = GNUNET_NO;
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1105 ntohs (mq->message->type),
1106 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1109 if (rl->neighbor->addr != NULL)
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("try_transmission_to_peer pre-send: at this point rl->neighbor->addr is NOT NULL, addrlen is %d\n"), rl->neighbor->addr_len);
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("try_transmission_to_peer pre-send: at this point rl->neighbor->addr is NULL\n"));
1113 /* FIXME: Change MessageQueue to hold message buffer and size? */
1114 rl->plugin->api->send (rl->plugin->api->cls,
1116 (char *)mq->message,
1117 ntohs(mq->message->size),
1119 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1121 rl->neighbor->addr_len,
1123 &transmit_send_continuation, mq);
1128 * Send the specified message to the specified peer.
1130 * @param client source of the transmission request (can be NULL)
1131 * @param priority how important is the message
1132 * @param msg message to send
1133 * @param is_internal is this an internal message
1134 * @param neighbor handle to the neighbor for transmission
1137 transmit_to_peer (struct TransportClient *client,
1138 unsigned int priority,
1139 const struct GNUNET_MessageHeader *msg,
1140 int is_internal, struct NeighborList *neighbor)
1142 struct MessageQueue *mq;
1143 struct MessageQueue *mqe;
1144 struct GNUNET_MessageHeader *m;
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 _("Sending message of type %u to peer `%4s'\n"),
1149 ntohs (msg->type), GNUNET_i2s (&neighbor->id));
1150 if (neighbor->addr != NULL)
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("transmit_to_peer: at this point neighbor->addr is NOT NULL\n"));
1155 /* check for duplicate submission */
1156 mq = neighbor->messages;
1159 if (mq->client == client)
1161 /* client transmitted to same peer twice
1162 before getting SendOk! */
1169 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1170 mq->client = client;
1171 m = GNUNET_malloc (ntohs (msg->size));
1172 memcpy (m, msg, ntohs (msg->size));
1174 mq->neighbor = neighbor;
1175 mq->internal_msg = is_internal;
1176 mq->priority = priority;
1179 mqe = neighbor->messages;
1181 while (mqe->next != NULL)
1186 neighbor->messages = mq;
1193 try_transmission_to_peer (neighbor);
1200 struct GeneratorContext
1202 struct TransportPlugin *plug_pos;
1203 struct AddressList *addr_pos;
1204 struct GNUNET_TIME_Absolute expiration;
1212 address_generator (void *cls, size_t max, void *buf)
1214 struct GeneratorContext *gc = cls;
1217 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1219 gc->plug_pos = gc->plug_pos->next;
1220 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1222 if (NULL == gc->plug_pos)
1225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1226 "In address_generator, gc->plug_pos is NULL!\n");
1231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1232 "Should be adding an address...\n");
1234 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1237 gc->addr_pos->addrlen, buf, max);
1238 gc->addr_pos = gc->addr_pos->next;
1244 * Construct our HELLO message from all of the addresses of
1245 * all of the transports.
1250 struct GNUNET_HELLO_Message *hello;
1251 struct TransportClient *cpos;
1252 struct NeighborList *npos;
1253 struct GeneratorContext gc;
1256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1257 "Refreshing my `%s'\n", "HELLO");
1259 gc.plug_pos = plugins;
1260 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1261 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1262 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1265 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1268 while (cpos != NULL)
1270 transmit_to_client (cpos,
1271 (const struct GNUNET_MessageHeader *) hello,
1276 GNUNET_free_non_null (our_hello);
1278 our_hello_version++;
1279 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1281 while (npos != NULL)
1284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1285 "Transmitting updated `%s' to neighbor `%4s'\n",
1286 "HELLO", GNUNET_i2s (&npos->id));
1288 transmit_to_peer (NULL, 0,
1289 (const struct GNUNET_MessageHeader *) our_hello,
1297 * Task used to clean up expired addresses for a plugin.
1299 * @param cls closure
1303 expire_address_task (void *cls,
1304 const struct GNUNET_SCHEDULER_TaskContext *tc);
1308 * Update the list of addresses for this plugin,
1309 * expiring those that are past their expiration date.
1311 * @param plugin addresses of which plugin should be recomputed?
1312 * @param fresh set to GNUNET_YES if a new address was added
1313 * and we need to regenerate the HELLO even if nobody
1317 update_addresses (struct TransportPlugin *plugin, int fresh)
1319 struct GNUNET_TIME_Relative min_remaining;
1320 struct GNUNET_TIME_Relative remaining;
1321 struct GNUNET_TIME_Absolute now;
1322 struct AddressList *pos;
1323 struct AddressList *prev;
1324 struct AddressList *next;
1327 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1328 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1329 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1330 now = GNUNET_TIME_absolute_get ();
1331 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1332 expired = GNUNET_NO;
1334 pos = plugin->addresses;
1338 if (pos->expires.value < now.value)
1340 expired = GNUNET_YES;
1342 plugin->addresses = pos->next;
1344 prev->next = pos->next;
1349 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1350 if (remaining.value < min_remaining.value)
1351 min_remaining = remaining;
1357 if (expired || fresh)
1359 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1360 plugin->address_update_task
1361 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1363 &expire_address_task, plugin);
1369 * Task used to clean up expired addresses for a plugin.
1371 * @param cls closure
1375 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1377 struct TransportPlugin *plugin = cls;
1378 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1379 update_addresses (plugin, GNUNET_NO);
1384 * Function that must be called by each plugin to notify the
1385 * transport service about the addresses under which the transport
1386 * provided by the plugin can be reached.
1388 * @param cls closure
1389 * @param name name of the transport that generated the address
1390 * @param addr one of the addresses of the host, NULL for the last address
1391 * the specific address format depends on the transport
1392 * @param addrlen length of the address
1393 * @param expires when should this address automatically expire?
1396 plugin_env_notify_address (void *cls,
1400 struct GNUNET_TIME_Relative expires)
1402 struct TransportPlugin *p = cls;
1403 struct AddressList *al;
1404 struct GNUNET_TIME_Absolute abex;
1406 abex = GNUNET_TIME_relative_to_absolute (expires);
1407 GNUNET_assert (p == find_transport (name));
1412 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1414 if (al->expires.value < abex.value)
1421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1422 "Plugin `%s' informs us about a new address `%s'\n", name,
1423 GNUNET_a2s (addr, addrlen));
1425 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1427 al->next = p->addresses;
1430 al->addrlen = addrlen;
1431 memcpy (&al[1], addr, addrlen);
1432 update_addresses (p, GNUNET_YES);
1437 * Notify all of our clients about a peer connecting.
1440 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1441 struct GNUNET_TIME_Relative latency)
1443 struct ConnectInfoMessage cim;
1444 struct TransportClient *cpos;
1447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448 "Informing clients about peer `%4s' connecting to us\n",
1451 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1452 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1453 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1454 cim.latency = GNUNET_TIME_relative_hton (latency);
1455 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1457 while (cpos != NULL)
1459 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1466 * Notify all of our clients about a peer disconnecting.
1469 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1471 struct DisconnectInfoMessage dim;
1472 struct TransportClient *cpos;
1475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1476 "Informing clients about peer `%4s' disconnecting\n",
1479 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1480 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1481 dim.reserved = htonl (0);
1482 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1484 while (cpos != NULL)
1486 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1493 * Copy any validated addresses to buf.
1495 * @return 0 once all addresses have been
1499 list_validated_addresses (void *cls, size_t max, void *buf)
1501 struct ValidationAddress **va = cls;
1504 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1508 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1510 &(*va)[1], (*va)->addr_len, buf, max);
1517 * HELLO validation cleanup task.
1520 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1522 struct ValidationAddress *va;
1523 struct ValidationList *pos;
1524 struct ValidationList *prev;
1525 struct GNUNET_TIME_Absolute now;
1526 struct GNUNET_TIME_Absolute first;
1527 struct GNUNET_HELLO_Message *hello;
1528 struct GNUNET_PeerIdentity pid;
1529 struct NeighborList *n;
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1533 "HELLO validation cleanup background task running...\n");
1535 now = GNUNET_TIME_absolute_get ();
1537 pos = pending_validations;
1540 if (pos->timeout.value < now.value)
1543 pending_validations = pos->next;
1545 prev->next = pos->next;
1546 va = pos->addresses;
1547 hello = GNUNET_HELLO_create (&pos->publicKey,
1548 &list_validated_addresses, &va);
1549 GNUNET_CRYPTO_hash (&pos->publicKey,
1551 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1555 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1556 "HELLO", GNUNET_i2s (&pid));
1558 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1559 n = find_neighbor (&pid, NULL, 0);
1562 try_transmission_to_peer (n);
1564 GNUNET_free (hello);
1565 while (NULL != (va = pos->addresses))
1567 pos->addresses = va->next;
1568 GNUNET_free (va->transport_name);
1573 pos = pending_validations;
1582 /* finally, reschedule cleanup if needed; list is
1583 ordered by timeout, so we need the last element... */
1584 if (NULL != pending_validations)
1586 first = pending_validations->timeout;
1587 pos = pending_validations;
1590 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1593 GNUNET_SCHEDULER_add_delayed (sched,
1594 GNUNET_TIME_absolute_get_remaining
1595 (first), &cleanup_validation, NULL);
1601 * Function that will be called if we receive a validation
1602 * of an address challenge that we transmitted to another
1603 * peer. Note that the validation should only be considered
1604 * acceptable if the challenge matches AND if the sender
1605 * address is at least a plausible address for this peer
1606 * (otherwise we may be seeing a MiM attack).
1608 * @param cls closure
1609 * @param name name of the transport that generated the address
1610 * @param peer who responded to our challenge
1611 * @param challenge the challenge number we presumably used
1612 * @param sender_addr string describing our sender address (as observed
1613 * by the other peer in human-readable format)
1616 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1617 const struct GNUNET_PeerIdentity *peer,
1618 const char *sender_address,
1619 size_t sender_address_len)
1621 unsigned int not_done;
1623 struct ValidationList *pos;
1624 struct ValidationAddress *va;
1625 struct GNUNET_PeerIdentity id;
1626 struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
1628 unsigned int challenge = ntohl(pong->challenge);
1629 pos = pending_validations;
1632 GNUNET_CRYPTO_hash (&pos->publicKey,
1634 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1636 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1643 /* TODO: call statistics (unmatched PONG) */
1644 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1646 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1647 GNUNET_i2s (peer), count);
1651 matched = GNUNET_NO;
1652 va = pos->addresses;
1655 if (va->challenge == challenge)
1658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1659 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1661 GNUNET_a2s ((const struct sockaddr *) sender_address,
1662 sender_address_len));
1664 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1666 ("Another peer saw us using the address `%s' via `FIXME'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1667 GNUNET_a2s ((const struct sockaddr *) &va[1],
1669 va->ok = GNUNET_YES;
1671 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1672 matched = GNUNET_YES;
1674 if (va->ok != GNUNET_YES)
1678 if (GNUNET_NO == matched)
1680 /* TODO: call statistics (unmatched PONG) */
1681 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1683 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1690 "All addresses validated, will now construct `%s' for `%4s'.\n",
1691 "HELLO", GNUNET_i2s (peer));
1693 pos->timeout.value = 0;
1694 GNUNET_SCHEDULER_add_with_priority (sched,
1695 GNUNET_SCHEDULER_PRIORITY_IDLE,
1696 &cleanup_validation, NULL);
1701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1703 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1709 struct CheckHelloValidatedContext
1712 * Plugin for which we are validating.
1714 struct TransportPlugin *plugin;
1717 * Hello that we are validating.
1719 struct GNUNET_HELLO_Message *hello;
1722 * Validation list being build.
1724 struct ValidationList *e;
1727 * Context for peerinfo iteration.
1728 * NULL after we are done processing peerinfo's information.
1730 struct GNUNET_PEERINFO_IteratorContext *piter;
1736 * Append the given address to the list of entries
1737 * that need to be validated.
1740 run_validation (void *cls,
1742 struct GNUNET_TIME_Absolute expiration,
1743 const void *addr, size_t addrlen)
1745 struct ValidationList *e = cls;
1746 struct TransportPlugin *tp;
1747 struct ValidationAddress *va;
1748 struct GNUNET_PeerIdentity id;
1750 struct TransportPingMessage *ping;
1755 tp = find_transport (tname);
1758 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1759 GNUNET_ERROR_TYPE_BULK,
1761 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1765 GNUNET_CRYPTO_hash (&e->publicKey,
1767 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1770 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1771 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1773 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1774 va->next = e->addresses;
1776 va->transport_name = GNUNET_strdup (tname);
1777 va->addr_len = addrlen;
1778 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1780 memcpy (&va[1], addr, addrlen);
1782 hello_size = GNUNET_HELLO_size(our_hello);
1783 tsize = sizeof(struct TransportPingMessage) + hello_size;
1785 message_buf = GNUNET_malloc(tsize);
1787 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
1788 ping->challenge = htonl(va->challenge);
1789 ping->header.size = htons(sizeof(struct TransportPingMessage));
1790 ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1791 memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
1793 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "hello size is %d, ping size is %d, total size is %d", hello_size, sizeof(struct TransportPingMessage), tsize);
1795 memcpy(message_buf, our_hello, hello_size);
1796 memcpy(&message_buf[hello_size], ping, sizeof(struct TransportPingMessage));
1800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message to address `%s' via `%s' for `%4s'\n",
1801 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1804 sent = tp->api->send(tp->api->cls, &id, message_buf, tsize, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1805 TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
1807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
1810 GNUNET_free(message_buf);
1815 * @param cls handle to the plugin (for sending)
1816 * @param target the peer identity of the peer we are sending to
1817 * @param challenge the challenge number
1818 * @param timeout how long to await validation?
1819 * @param addr the address to validate
1820 * @param addrlen the length of the address
1822 * Perform address validation, which means sending a PING PONG to
1823 * the address via the transport plugin. If not validated, then
1824 * do not count this as a good peer/address...
1826 * Currently this function is not used, ping/pongs get sent from the
1827 * run_validation function. Haven't decided yet how to do this.
1830 validate_address (void *cls, struct ValidationAddress *va,
1831 const struct GNUNET_PeerIdentity *target,
1832 struct GNUNET_TIME_Relative timeout,
1833 const void *addr, size_t addrlen)
1835 /* struct Plugin *plugin = cls;
1836 int challenge = va->challenge; */
1844 * Check if addresses in validated hello "h" overlap with
1845 * those in "chvc->hello" and update "chvc->hello" accordingly,
1846 * removing those addresses that have already been validated.
1849 check_hello_validated (void *cls,
1850 const struct GNUNET_PeerIdentity *peer,
1851 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1853 struct CheckHelloValidatedContext *chvc = cls;
1854 struct ValidationAddress *va;
1855 struct TransportPlugin *tp;
1858 struct GNUNET_PeerIdentity apeer;
1860 first_call = GNUNET_NO;
1861 if (chvc->e == NULL)
1864 first_call = GNUNET_YES;
1865 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1866 GNUNET_assert (GNUNET_OK ==
1867 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1868 &chvc->e->publicKey));
1870 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1871 chvc->e->next = pending_validations;
1872 pending_validations = chvc->e;
1874 /* no existing HELLO, all addresses are new */
1875 GNUNET_HELLO_iterate_addresses (chvc->hello,
1876 GNUNET_NO, &run_validation, chvc->e);
1880 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1882 GNUNET_TIME_absolute_get (),
1883 &run_validation, chvc->e);
1885 else if (GNUNET_YES == first_call)
1887 /* no existing HELLO, all addresses are new */
1888 GNUNET_HELLO_iterate_addresses (chvc->hello,
1889 GNUNET_NO, &run_validation, chvc->e);
1893 return; /* wait for next call */
1894 /* finally, transmit validation attempts */
1895 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1898 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1899 "HELLO", GNUNET_i2s (&apeer));
1901 va = chvc->e->addresses;
1906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1907 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1910 GNUNET_a2s ((const struct sockaddr *) &va[1],
1911 va->addr_len), GNUNET_i2s (&apeer));
1913 tp = find_transport (va->transport_name);
1914 GNUNET_assert (tp != NULL);
1915 /* This validation should happen inside the transport, not from the plugin! */
1916 validate_address (tp->api->cls, va, &apeer,
1917 HELLO_VERIFICATION_TIMEOUT,
1918 &va[1], va->addr_len);
1919 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1926 "Found %d addresses in hello of size %d\n", count, GNUNET_HELLO_size(chvc->hello));
1928 GNUNET_SCHEDULER_add_delayed (sched,
1929 GNUNET_TIME_absolute_get_remaining (chvc->
1931 &cleanup_validation, NULL);
1937 * Process HELLO-message.
1939 * @param plugin transport involved, may be NULL
1940 * @param message the actual message
1941 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1944 process_hello (struct TransportPlugin *plugin,
1945 const struct GNUNET_MessageHeader *message)
1947 struct ValidationList *e;
1949 struct GNUNET_PeerIdentity target;
1950 const struct GNUNET_HELLO_Message *hello;
1951 struct CheckHelloValidatedContext *chvc;
1952 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1954 hsize = ntohs (message->size);
1955 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1956 (hsize < sizeof (struct GNUNET_MessageHeader)))
1959 return GNUNET_SYSERR;
1961 /* first, check if load is too high */
1962 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1964 /* TODO: call to stats? */
1967 hello = (const struct GNUNET_HELLO_Message *) message;
1968 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1970 GNUNET_break_op (0);
1971 return GNUNET_SYSERR;
1973 GNUNET_CRYPTO_hash (&publicKey,
1974 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1975 &target.hashPubKey);
1977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1978 "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
1979 "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
1981 /* check if a HELLO for this peer is already on the validation list */
1982 e = pending_validations;
1985 if (0 == memcmp (&e->publicKey,
1988 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1990 /* TODO: call to stats? */
1992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1993 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1994 "HELLO", GNUNET_i2s (&target));
2000 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2001 chvc->plugin = plugin;
2002 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
2003 memcpy (chvc->hello, hello, hsize);
2004 /* finally, check if HELLO was previously validated
2005 (continuation will then schedule actual validation) */
2006 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2010 HELLO_VERIFICATION_TIMEOUT,
2011 &check_hello_validated, chvc);
2017 * The peer specified by the given neighbor has timed-out or a plugin
2018 * has disconnected. We may either need to do nothing (other plugins
2019 * still up), or trigger a full disconnect and clean up. This
2020 * function updates our state and do the necessary notifications.
2021 * Also notifies our clients that the neighbor is now officially
2024 * @param n the neighbor list entry for the peer
2025 * @param check should we just check if all plugins
2026 * disconnected or must we ask all plugins to
2030 disconnect_neighbor (struct NeighborList *n, int check)
2032 struct ReadyList *rpos;
2033 struct NeighborList *npos;
2034 struct NeighborList *nprev;
2035 struct MessageQueue *mq;
2037 if (GNUNET_YES == check)
2040 while (NULL != rpos)
2042 if (GNUNET_YES == rpos->connected)
2043 return; /* still connected */
2049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2050 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2052 /* remove n from neighbors list */
2055 while ((npos != NULL) && (npos != n))
2060 GNUNET_assert (npos != NULL);
2062 neighbors = n->next;
2064 nprev->next = n->next;
2066 /* notify all clients about disconnect */
2067 notify_clients_disconnect (&n->id);
2069 /* clean up all plugins, cancel connections and pending transmissions */
2070 while (NULL != (rpos = n->plugins))
2072 n->plugins = rpos->next;
2073 GNUNET_assert (rpos->neighbor == n);
2074 if (GNUNET_YES == rpos->connected)
2075 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2079 /* free all messages on the queue */
2080 while (NULL != (mq = n->messages))
2082 n->messages = mq->next;
2083 GNUNET_assert (mq->neighbor == n);
2086 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2087 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2088 /* finally, free n itself */
2094 * Add an entry for each of our transport plugins
2095 * (that are able to send) to the list of plugins
2096 * for this neighbor.
2098 * @param neighbor to initialize
2101 add_plugins (struct NeighborList *neighbor)
2103 struct TransportPlugin *tp;
2104 struct ReadyList *rl;
2106 neighbor->retry_plugins_time
2107 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2111 if (tp->api->send != NULL)
2113 rl = GNUNET_malloc (sizeof (struct ReadyList));
2114 rl->next = neighbor->plugins;
2115 neighbor->plugins = rl;
2117 rl->neighbor = neighbor;
2118 rl->transmit_ready = GNUNET_YES;
2126 neighbor_timeout_task (void *cls,
2127 const struct GNUNET_SCHEDULER_TaskContext *tc)
2129 struct NeighborList *n = cls;
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2133 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2135 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2136 disconnect_neighbor (n, GNUNET_NO);
2141 * Create a fresh entry in our neighbor list for the given peer.
2142 * Will try to transmit our current HELLO to the new neighbor. Also
2143 * notifies our clients about the new "connection".
2145 * @param peer the peer for which we create the entry
2146 * @return the new neighbor list entry
2148 static struct NeighborList *
2149 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
2151 struct NeighborList *n;
2154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2155 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
2158 GNUNET_assert (our_hello != NULL);
2159 n = GNUNET_malloc (sizeof (struct NeighborList));
2160 n->next = neighbors;
2163 n->last_quota_update = GNUNET_TIME_absolute_get ();
2165 GNUNET_TIME_relative_to_absolute
2166 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2167 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2169 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2170 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2171 &neighbor_timeout_task, n);
2172 transmit_to_peer (NULL, 0,
2173 (const struct GNUNET_MessageHeader *) our_hello,
2175 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2180 * We have received a PING message from someone. Need to send a PONG message
2181 * in response to the peer by any means necessary. Of course, with something
2182 * like TCP where a connection exists, we may want to send it that way. But
2183 * we may not be able to make that distinction...
2185 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2186 const struct GNUNET_PeerIdentity *peer,
2187 const char *sender_address,
2188 size_t sender_address_len)
2190 struct TransportPlugin *plugin = cls;
2191 struct TransportPingMessage *ping;
2192 struct TransportPongMessage *pong;
2194 struct NeighborList *n;
2195 pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2199 "Processing `%s' from `%s'\n",
2200 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2203 msize = ntohs (message->size);
2204 if (msize < sizeof (struct TransportPingMessage))
2206 GNUNET_break_op (0);
2207 return GNUNET_SYSERR;
2209 ping = (struct TransportPingMessage *) message;
2210 if (0 != memcmp (&ping->target,
2211 plugin->env.my_identity,
2212 sizeof (struct GNUNET_PeerIdentity)))
2214 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2215 _("Received `%s' message not destined for me!\n"), "PING");
2216 return GNUNET_SYSERR;
2219 msize -= sizeof (struct TransportPingMessage);
2221 * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
2223 GNUNET_break_op (0);
2224 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2228 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
2231 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2235 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2236 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2237 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2238 pong->purpose.size =
2239 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2241 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2242 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2243 pong->challenge = ping->challenge;
2245 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2246 memcpy (&pong[1], sender_address, sender_address_len);
2247 GNUNET_assert (GNUNET_OK ==
2248 GNUNET_CRYPTO_rsa_sign (my_private_key,
2249 &pong->purpose, &pong->signature));
2250 /* Will this nonsense work, even for UDP?
2251 * The idea is that we need an address to send to for UDP, but we may not know
2252 * this peer yet. So in that case, we need to create a new neighbor with the
2253 * current address, but is this address going to be correct, or will it have a
2254 * random high port or something? Another question is, why didn't we get a WELCOME
2255 * from this peer with its advertised addresses already? We don't want to
2256 * differentiate based on transport... */
2257 n = find_neighbor(peer, NULL, 0);
2261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2262 "Didn't find peer in list, adding...\n");
2264 setup_new_neighbor(peer, sender_address, sender_address_len);
2265 n = find_neighbor(peer, sender_address, sender_address_len);
2266 GNUNET_assert(n != NULL);
2268 else if (n->addr == NULL)
2271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2272 "Found peer in list, but without address, adding!\n");
2274 n->addr = GNUNET_malloc(sender_address_len);
2275 memcpy(n->addr, sender_address, sender_address_len);
2276 n->addr_len = sender_address_len;
2279 transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, n);
2286 * Function called by the plugin for each received message.
2287 * Update data volumes, possibly notify plugins about
2288 * reducing the rate at which they read from the socket
2289 * and generally forward to our receive callback.
2291 * @param cls the "struct TransportPlugin *" we gave to the plugin
2292 * @param message the message, NULL if peer was disconnected
2293 * @param distance the transport cost to this peer (not latency!)
2294 * @param sender_address the address that the sender reported
2295 * (opaque to transport service)
2296 * @param sender_address_len the length of the sender address
2297 * @param peer (claimed) identity of the other peer
2298 * @return the new service_context that the plugin should use
2299 * for future receive calls for messages from this
2304 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2305 const struct GNUNET_MessageHeader *message,
2306 unsigned int distance, const char *sender_address,
2307 size_t sender_address_len)
2309 const struct GNUNET_MessageHeader ack = {
2310 htons (sizeof (struct GNUNET_MessageHeader)),
2311 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2313 struct ReadyList *service_context;
2314 struct TransportPlugin *plugin = cls;
2315 struct TransportClient *cpos;
2316 struct InboundMessage *im;
2318 struct NeighborList *n;
2320 n = find_neighbor (peer, sender_address, sender_address_len);
2323 if (message == NULL)
2324 return; /* disconnect of peer already marked down */
2325 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2327 service_context = n->plugins;
2328 while ((service_context != NULL) && (plugin != service_context->plugin))
2329 service_context = service_context->next;
2330 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2331 if (message == NULL)
2334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2335 "Receive failed from `%4s', triggering disconnect\n",
2336 GNUNET_i2s (&n->id));
2338 /* TODO: call stats */
2339 if (service_context != NULL)
2340 service_context->connected = GNUNET_NO;
2341 disconnect_neighbor (n, GNUNET_YES);
2345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2346 "Processing message of type `%u' received by plugin...\n",
2347 ntohs (message->type));
2349 if (service_context != NULL)
2351 if (service_context->connected == GNUNET_NO)
2353 service_context->connected = GNUNET_YES;
2354 service_context->transmit_ready = GNUNET_YES;
2355 service_context->connect_attempts++;
2357 service_context->timeout
2359 GNUNET_TIME_relative_to_absolute
2360 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2361 /* service_context->latency = latency; */ /* This value should be set by us! */
2363 /* update traffic received amount ... */
2364 msize = ntohs (message->size);
2365 n->last_received += msize;
2366 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2368 GNUNET_TIME_relative_to_absolute
2369 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2371 GNUNET_SCHEDULER_add_delayed (sched,
2372 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2373 &neighbor_timeout_task, n);
2375 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2377 /* dropping message due to frequent inbound volume violations! */
2378 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2379 GNUNET_ERROR_TYPE_BULK,
2381 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2382 /* TODO: call stats */
2383 GNUNET_assert ((service_context == NULL) ||
2384 (NULL != service_context->neighbor));
2387 switch (ntohs (message->type))
2389 case GNUNET_MESSAGE_TYPE_HELLO:
2391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2392 "Receiving `%s' message from `%4s'.\n", "HELLO",
2395 process_hello (plugin, message);
2397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2398 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2401 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2403 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2404 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2406 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2407 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2409 //plugin_env_notify_validation();
2410 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2411 n->saw_ack = GNUNET_YES;
2412 /* intentional fall-through! */
2415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2416 "Received message of type %u from `%4s', sending to all clients.\n",
2417 ntohs (message->type), GNUNET_i2s (peer));
2419 /* transmit message to all clients */
2420 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2421 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2422 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2423 im->latency = n->latency;
2425 memcpy (&im[1], message, msize);
2428 while (cpos != NULL)
2430 transmit_to_client (cpos, &im->header, GNUNET_YES);
2435 GNUNET_assert ((service_context == NULL) ||
2436 (NULL != service_context->neighbor));
2441 * Handle START-message. This is the first message sent to us
2442 * by any client which causes us to add it to our list.
2444 * @param cls closure (always NULL)
2445 * @param client identification of the client
2446 * @param message the actual message
2449 handle_start (void *cls,
2450 struct GNUNET_SERVER_Client *client,
2451 const struct GNUNET_MessageHeader *message)
2453 struct TransportClient *c;
2454 struct ConnectInfoMessage cim;
2455 struct NeighborList *n;
2456 struct InboundMessage *im;
2457 struct GNUNET_MessageHeader *ack;
2460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2461 "Received `%s' request from client\n", "START");
2466 if (c->client == client)
2468 /* client already on our list! */
2470 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2475 c = GNUNET_malloc (sizeof (struct TransportClient));
2479 if (our_hello != NULL)
2482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2483 "Sending our own `%s' to new client\n", "HELLO");
2485 transmit_to_client (c,
2486 (const struct GNUNET_MessageHeader *) our_hello,
2488 /* tell new client about all existing connections */
2489 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2490 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2492 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2493 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2494 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2495 sizeof (struct GNUNET_MessageHeader));
2496 im->header.size = htons (sizeof (struct InboundMessage) +
2497 sizeof (struct GNUNET_MessageHeader));
2498 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2499 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2500 ack = (struct GNUNET_MessageHeader *) &im[1];
2501 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2502 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2503 for (n = neighbors; n != NULL; n = n->next)
2506 transmit_to_client (c, &cim.header, GNUNET_NO);
2510 transmit_to_client (c, &im->header, GNUNET_NO);
2517 fprintf(stderr, "Our hello is NULL!\n");
2519 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2524 * Handle HELLO-message.
2526 * @param cls closure (always NULL)
2527 * @param client identification of the client
2528 * @param message the actual message
2531 handle_hello (void *cls,
2532 struct GNUNET_SERVER_Client *client,
2533 const struct GNUNET_MessageHeader *message)
2538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2539 "Received `%s' request from client\n", "HELLO");
2541 ret = process_hello (NULL, message);
2542 GNUNET_SERVER_receive_done (client, ret);
2547 * Handle SEND-message.
2549 * @param cls closure (always NULL)
2550 * @param client identification of the client
2551 * @param message the actual message
2554 handle_send (void *cls,
2555 struct GNUNET_SERVER_Client *client,
2556 const struct GNUNET_MessageHeader *message)
2558 struct TransportClient *tc;
2559 struct NeighborList *n;
2560 const struct OutboundMessage *obm;
2561 const struct GNUNET_MessageHeader *obmm;
2565 size = ntohs (message->size);
2567 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2570 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2573 obm = (const struct OutboundMessage *) message;
2575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2576 "Received `%s' request from client with target `%4s'\n",
2577 "SEND", GNUNET_i2s (&obm->peer));
2579 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2580 msize = ntohs (obmm->size);
2581 if (size != msize + sizeof (struct OutboundMessage))
2584 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2587 n = find_neighbor (&obm->peer, NULL, 0);
2589 n = setup_new_neighbor (&obm->peer, NULL, 0);
2591 while ((tc != NULL) && (tc->client != client))
2595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2596 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2598 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2600 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2601 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2606 * Handle SET_QUOTA-message.
2608 * @param cls closure (always NULL)
2609 * @param client identification of the client
2610 * @param message the actual message
2613 handle_set_quota (void *cls,
2614 struct GNUNET_SERVER_Client *client,
2615 const struct GNUNET_MessageHeader *message)
2617 const struct QuotaSetMessage *qsm =
2618 (const struct QuotaSetMessage *) message;
2619 struct NeighborList *n;
2620 struct TransportPlugin *p;
2621 struct ReadyList *rl;
2624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2625 "Received `%s' request from client for peer `%4s'\n",
2626 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2628 n = find_neighbor (&qsm->peer, NULL, 0);
2631 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2635 if (n->quota_in < ntohl (qsm->quota_in))
2636 n->last_quota_update = GNUNET_TIME_absolute_get ();
2637 n->quota_in = ntohl (qsm->quota_in);
2642 p->api->set_receive_quota (p->api->cls,
2643 &qsm->peer, ntohl (qsm->quota_in));
2646 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2651 * Handle TRY_CONNECT-message.
2653 * @param cls closure (always NULL)
2654 * @param client identification of the client
2655 * @param message the actual message
2658 handle_try_connect (void *cls,
2659 struct GNUNET_SERVER_Client *client,
2660 const struct GNUNET_MessageHeader *message)
2662 const struct TryConnectMessage *tcm;
2664 tcm = (const struct TryConnectMessage *) message;
2666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2667 "Received `%s' request from client %p asking to connect to `%4s'\n",
2668 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2670 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2671 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2672 knowing its address? Should we ask the plugin
2673 for more information about this peer? I don't
2674 think we can... Or set up new peer should only
2675 happen when transport notifies us of an address,
2676 and this setup should check for an address in
2677 the existing list only */
2680 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2681 "Client asked to connect to `%4s', but connection already exists\n",
2682 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2684 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2688 transmit_address_to_client (void *cls, const char *address)
2690 struct GNUNET_SERVER_TransmitContext *tc = cls;
2693 if (NULL == address)
2696 slen = strlen (address) + 1;
2697 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2698 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2699 if (NULL == address)
2700 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2704 * Handle AddressLookup-message.
2706 * @param cls closure (always NULL)
2707 * @param client identification of the client
2708 * @param message the actual message
2711 handle_address_lookup (void *cls,
2712 struct GNUNET_SERVER_Client *client,
2713 const struct GNUNET_MessageHeader *message)
2715 const struct AddressLookupMessage *alum;
2716 struct TransportPlugin *lsPlugin;
2717 const char *nameTransport;
2718 const char *address;
2720 struct GNUNET_SERVER_TransmitContext *tc;
2722 size = ntohs (message->size);
2723 if (size < sizeof (struct AddressLookupMessage))
2725 GNUNET_break_op (0);
2726 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2729 alum = (const struct AddressLookupMessage *) message;
2730 uint32_t addressLen = ntohl (alum->addrlen);
2731 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2733 GNUNET_break_op (0);
2734 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2737 address = (const char *) &alum[1];
2738 nameTransport = (const char *) &address[addressLen];
2740 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2742 GNUNET_break_op (0);
2743 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2746 struct GNUNET_TIME_Absolute timeout =
2747 GNUNET_TIME_absolute_ntoh (alum->timeout);
2748 struct GNUNET_TIME_Relative rtimeout =
2749 GNUNET_TIME_absolute_get_remaining (timeout);
2750 lsPlugin = find_transport (nameTransport);
2751 if (NULL == lsPlugin)
2753 tc = GNUNET_SERVER_transmit_context_create (client);
2754 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2755 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2756 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2759 tc = GNUNET_SERVER_transmit_context_create (client);
2760 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2761 address, addressLen, GNUNET_YES,
2763 &transmit_address_to_client, tc);
2767 * List of handlers for the messages understood by this
2770 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2771 {&handle_start, NULL,
2772 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2773 {&handle_hello, NULL,
2774 GNUNET_MESSAGE_TYPE_HELLO, 0},
2775 {&handle_send, NULL,
2776 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2777 {&handle_set_quota, NULL,
2778 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2779 {&handle_try_connect, NULL,
2780 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2781 sizeof (struct TryConnectMessage)},
2782 {&handle_address_lookup, NULL,
2783 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2790 * Setup the environment for this plugin.
2793 create_environment (struct TransportPlugin *plug)
2795 plug->env.cfg = cfg;
2796 plug->env.sched = sched;
2797 plug->env.my_identity = &my_identity;
2798 plug->env.cls = plug;
2799 plug->env.receive = &plugin_env_receive;
2800 plug->env.notify_address = &plugin_env_notify_address;
2801 plug->env.default_quota_in =
2802 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2803 plug->env.max_connections = max_connect_per_transport;
2808 * Start the specified transport (load the plugin).
2811 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2813 struct TransportPlugin *plug;
2816 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2817 _("Loading `%s' transport plugin\n"), name);
2818 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2819 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2820 create_environment (plug);
2821 plug->short_name = GNUNET_strdup (name);
2822 plug->lib_name = libname;
2823 plug->next = plugins;
2825 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2826 if (plug->api == NULL)
2828 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2829 _("Failed to load transport plugin for `%s'\n"), name);
2830 GNUNET_free (plug->short_name);
2831 plugins = plug->next;
2832 GNUNET_free (libname);
2839 * Called whenever a client is disconnected. Frees our
2840 * resources associated with that client.
2842 * @param cls closure
2843 * @param client identification of the client
2846 client_disconnect_notification (void *cls,
2847 struct GNUNET_SERVER_Client *client)
2849 struct TransportClient *pos;
2850 struct TransportClient *prev;
2851 struct ClientMessageQueueEntry *mqe;
2856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2857 "Client disconnected, cleaning up.\n");
2861 while ((pos != NULL) && (pos->client != client))
2868 while (NULL != (mqe = pos->message_queue_head))
2870 pos->message_queue_head = mqe->next;
2873 pos->message_queue_head = NULL;
2875 clients = pos->next;
2877 prev->next = pos->next;
2878 if (GNUNET_YES == pos->tcs_pending)
2888 * Function called when the service shuts down. Unloads our plugins.
2890 * @param cls closure, unused
2891 * @param tc task context (unused)
2894 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2896 struct TransportPlugin *plug;
2897 struct AddressList *al;
2900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2901 "Transport service is unloading plugins...\n");
2903 while (NULL != (plug = plugins))
2905 plugins = plug->next;
2906 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2907 GNUNET_free (plug->lib_name);
2908 GNUNET_free (plug->short_name);
2909 while (NULL != (al = plug->addresses))
2911 plug->addresses = al->next;
2916 if (my_private_key != NULL)
2917 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2918 GNUNET_free_non_null (our_hello);
2923 * Initiate transport service.
2925 * @param cls closure
2926 * @param s scheduler to use
2927 * @param serv the initialized server
2928 * @param c configuration to use
2932 struct GNUNET_SCHEDULER_Handle *s,
2933 struct GNUNET_SERVER_Handle *serv,
2934 const struct GNUNET_CONFIGURATION_Handle *c)
2939 unsigned long long tneigh;
2944 /* parse configuration */
2946 GNUNET_CONFIGURATION_get_value_number (c,
2951 GNUNET_CONFIGURATION_get_value_filename (c,
2953 "HOSTKEY", &keyfile)))
2955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2957 ("Transport service is lacking key configuration settings. Exiting.\n"));
2958 GNUNET_SCHEDULER_shutdown (s);
2961 max_connect_per_transport = (uint32_t) tneigh;
2962 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2963 GNUNET_free (keyfile);
2964 if (my_private_key == NULL)
2966 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2968 ("Transport service could not access hostkey. Exiting.\n"));
2969 GNUNET_SCHEDULER_shutdown (s);
2972 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2973 GNUNET_CRYPTO_hash (&my_public_key,
2974 sizeof (my_public_key), &my_identity.hashPubKey);
2975 /* setup notification */
2977 GNUNET_SERVER_disconnect_notify (server,
2978 &client_disconnect_notification, NULL);
2979 /* load plugins... */
2982 GNUNET_CONFIGURATION_get_value_string (c,
2983 "TRANSPORT", "PLUGINS", &plugs))
2985 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2986 _("Starting transport plugins `%s'\n"), plugs);
2987 pos = strtok (plugs, " ");
2990 start_transport (server, pos);
2992 pos = strtok (NULL, " ");
2994 GNUNET_free (plugs);
2996 GNUNET_SCHEDULER_add_delayed (sched,
2997 GNUNET_TIME_UNIT_FOREVER_REL,
2998 &unload_plugins, NULL);
3003 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3005 /* process client requests */
3006 GNUNET_SERVER_add_handlers (server, handlers);
3011 * The main function for the transport service.
3013 * @param argc number of arguments from the command line
3014 * @param argv command line arguments
3015 * @return 0 ok, 1 on error
3018 main (int argc, char *const *argv)
3020 return (GNUNET_OK ==
3021 GNUNET_SERVICE_run (argc,
3024 GNUNET_SERVICE_OPTION_NONE,
3025 &run, NULL)) ? 0 : 1;
3028 /* end of gnunet-service-transport.c */