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 rl->plugin->api->send (rl->plugin->api->cls,
1117 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1119 rl->neighbor->addr_len,
1121 &transmit_send_continuation, mq);
1126 * Send the specified message to the specified peer.
1128 * @param client source of the transmission request (can be NULL)
1129 * @param priority how important is the message
1130 * @param msg message to send
1131 * @param is_internal is this an internal message
1132 * @param neighbor handle to the neighbor for transmission
1135 transmit_to_peer (struct TransportClient *client,
1136 unsigned int priority,
1137 const struct GNUNET_MessageHeader *msg,
1138 int is_internal, struct NeighborList *neighbor)
1140 struct MessageQueue *mq;
1141 struct MessageQueue *mqe;
1142 struct GNUNET_MessageHeader *m;
1145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146 _("Sending message of type %u to peer `%4s'\n"),
1147 ntohs (msg->type), GNUNET_i2s (&neighbor->id));
1148 if (neighbor->addr != NULL)
1149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("transmit_to_peer: at this point neighbor->addr is NOT NULL\n"));
1153 /* check for duplicate submission */
1154 mq = neighbor->messages;
1157 if (mq->client == client)
1159 /* client transmitted to same peer twice
1160 before getting SendOk! */
1167 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1168 mq->client = client;
1169 m = GNUNET_malloc (ntohs (msg->size));
1170 memcpy (m, msg, ntohs (msg->size));
1172 mq->neighbor = neighbor;
1173 mq->internal_msg = is_internal;
1174 mq->priority = priority;
1177 mqe = neighbor->messages;
1179 while (mqe->next != NULL)
1184 neighbor->messages = mq;
1191 try_transmission_to_peer (neighbor);
1198 struct GeneratorContext
1200 struct TransportPlugin *plug_pos;
1201 struct AddressList *addr_pos;
1202 struct GNUNET_TIME_Absolute expiration;
1210 address_generator (void *cls, size_t max, void *buf)
1212 struct GeneratorContext *gc = cls;
1215 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1217 gc->plug_pos = gc->plug_pos->next;
1218 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1220 if (NULL == gc->plug_pos)
1223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224 "In address_generator, gc->plug_pos is NULL!\n");
1229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1230 "Should be adding an address...\n");
1232 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1235 gc->addr_pos->addrlen, buf, max);
1236 gc->addr_pos = gc->addr_pos->next;
1242 * Construct our HELLO message from all of the addresses of
1243 * all of the transports.
1248 struct GNUNET_HELLO_Message *hello;
1249 struct TransportClient *cpos;
1250 struct NeighborList *npos;
1251 struct GeneratorContext gc;
1254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1255 "Refreshing my `%s'\n", "HELLO");
1257 gc.plug_pos = plugins;
1258 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1259 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1260 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1263 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1266 while (cpos != NULL)
1268 transmit_to_client (cpos,
1269 (const struct GNUNET_MessageHeader *) hello,
1274 GNUNET_free_non_null (our_hello);
1276 our_hello_version++;
1277 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1279 while (npos != NULL)
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1283 "Transmitting updated `%s' to neighbor `%4s'\n",
1284 "HELLO", GNUNET_i2s (&npos->id));
1286 transmit_to_peer (NULL, 0,
1287 (const struct GNUNET_MessageHeader *) our_hello,
1295 * Task used to clean up expired addresses for a plugin.
1297 * @param cls closure
1301 expire_address_task (void *cls,
1302 const struct GNUNET_SCHEDULER_TaskContext *tc);
1306 * Update the list of addresses for this plugin,
1307 * expiring those that are past their expiration date.
1309 * @param plugin addresses of which plugin should be recomputed?
1310 * @param fresh set to GNUNET_YES if a new address was added
1311 * and we need to regenerate the HELLO even if nobody
1315 update_addresses (struct TransportPlugin *plugin, int fresh)
1317 struct GNUNET_TIME_Relative min_remaining;
1318 struct GNUNET_TIME_Relative remaining;
1319 struct GNUNET_TIME_Absolute now;
1320 struct AddressList *pos;
1321 struct AddressList *prev;
1322 struct AddressList *next;
1325 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1326 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1327 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1328 now = GNUNET_TIME_absolute_get ();
1329 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1330 expired = GNUNET_NO;
1332 pos = plugin->addresses;
1336 if (pos->expires.value < now.value)
1338 expired = GNUNET_YES;
1340 plugin->addresses = pos->next;
1342 prev->next = pos->next;
1347 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1348 if (remaining.value < min_remaining.value)
1349 min_remaining = remaining;
1355 if (expired || fresh)
1357 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1358 plugin->address_update_task
1359 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1361 &expire_address_task, plugin);
1367 * Task used to clean up expired addresses for a plugin.
1369 * @param cls closure
1373 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1375 struct TransportPlugin *plugin = cls;
1376 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1377 update_addresses (plugin, GNUNET_NO);
1382 * Function that must be called by each plugin to notify the
1383 * transport service about the addresses under which the transport
1384 * provided by the plugin can be reached.
1386 * @param cls closure
1387 * @param name name of the transport that generated the address
1388 * @param addr one of the addresses of the host, NULL for the last address
1389 * the specific address format depends on the transport
1390 * @param addrlen length of the address
1391 * @param expires when should this address automatically expire?
1394 plugin_env_notify_address (void *cls,
1398 struct GNUNET_TIME_Relative expires)
1400 struct TransportPlugin *p = cls;
1401 struct AddressList *al;
1402 struct GNUNET_TIME_Absolute abex;
1404 abex = GNUNET_TIME_relative_to_absolute (expires);
1405 GNUNET_assert (p == find_transport (name));
1410 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1412 if (al->expires.value < abex.value)
1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1420 "Plugin `%s' informs us about a new address `%s'\n", name,
1421 GNUNET_a2s (addr, addrlen));
1423 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1425 al->next = p->addresses;
1428 al->addrlen = addrlen;
1429 memcpy (&al[1], addr, addrlen);
1430 update_addresses (p, GNUNET_YES);
1435 * Notify all of our clients about a peer connecting.
1438 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1439 struct GNUNET_TIME_Relative latency)
1441 struct ConnectInfoMessage cim;
1442 struct TransportClient *cpos;
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446 "Informing clients about peer `%4s' connecting to us\n",
1449 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1450 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1451 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1452 cim.latency = GNUNET_TIME_relative_hton (latency);
1453 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1455 while (cpos != NULL)
1457 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1464 * Notify all of our clients about a peer disconnecting.
1467 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1469 struct DisconnectInfoMessage dim;
1470 struct TransportClient *cpos;
1473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1474 "Informing clients about peer `%4s' disconnecting\n",
1477 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1478 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1479 dim.reserved = htonl (0);
1480 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1482 while (cpos != NULL)
1484 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1491 * Copy any validated addresses to buf.
1493 * @return 0 once all addresses have been
1497 list_validated_addresses (void *cls, size_t max, void *buf)
1499 struct ValidationAddress **va = cls;
1502 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1506 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1508 &(*va)[1], (*va)->addr_len, buf, max);
1515 * HELLO validation cleanup task.
1518 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1520 struct ValidationAddress *va;
1521 struct ValidationList *pos;
1522 struct ValidationList *prev;
1523 struct GNUNET_TIME_Absolute now;
1524 struct GNUNET_TIME_Absolute first;
1525 struct GNUNET_HELLO_Message *hello;
1526 struct GNUNET_PeerIdentity pid;
1527 struct NeighborList *n;
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1531 "HELLO validation cleanup background task running...\n");
1533 now = GNUNET_TIME_absolute_get ();
1535 pos = pending_validations;
1538 if (pos->timeout.value < now.value)
1541 pending_validations = pos->next;
1543 prev->next = pos->next;
1544 va = pos->addresses;
1545 hello = GNUNET_HELLO_create (&pos->publicKey,
1546 &list_validated_addresses, &va);
1547 GNUNET_CRYPTO_hash (&pos->publicKey,
1549 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1553 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1554 "HELLO", GNUNET_i2s (&pid));
1556 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1557 n = find_neighbor (&pid, NULL, 0);
1559 try_transmission_to_peer (n);
1560 GNUNET_free (hello);
1561 while (NULL != (va = pos->addresses))
1563 pos->addresses = va->next;
1564 GNUNET_free (va->transport_name);
1569 pos = pending_validations;
1578 /* finally, reschedule cleanup if needed; list is
1579 ordered by timeout, so we need the last element... */
1580 if (NULL != pending_validations)
1582 first = pending_validations->timeout;
1583 pos = pending_validations;
1586 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1589 GNUNET_SCHEDULER_add_delayed (sched,
1590 GNUNET_TIME_absolute_get_remaining
1591 (first), &cleanup_validation, NULL);
1596 static struct GNUNET_MessageHeader *
1597 createPingMessage (struct GNUNET_PeerIdentity * target, struct ValidationAddress *va)
1600 struct TransportPingMessage *ping;
1601 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
1603 ping->challenge = htonl(va->challenge);
1604 ping->header.size = sizeof(struct TransportPingMessage);
1605 ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1606 memcpy(&ping->target, target, sizeof(struct GNUNET_PeerIdentity));
1608 return &ping->header;
1612 * Function that will be called if we receive a validation
1613 * of an address challenge that we transmitted to another
1614 * peer. Note that the validation should only be considered
1615 * acceptable if the challenge matches AND if the sender
1616 * address is at least a plausible address for this peer
1617 * (otherwise we may be seeing a MiM attack).
1619 * @param cls closure
1620 * @param name name of the transport that generated the address
1621 * @param peer who responded to our challenge
1622 * @param challenge the challenge number we presumably used
1623 * @param sender_addr string describing our sender address (as observed
1624 * by the other peer in human-readable format)
1627 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1628 const struct GNUNET_PeerIdentity *peer,
1629 const char *sender_address,
1630 size_t sender_address_len)
1632 unsigned int not_done;
1634 struct ValidationList *pos;
1635 struct ValidationAddress *va;
1636 struct GNUNET_PeerIdentity id;
1637 struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
1639 unsigned int challenge = ntohl(pong->challenge);
1640 pos = pending_validations;
1643 GNUNET_CRYPTO_hash (&pos->publicKey,
1645 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1647 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1654 /* TODO: call statistics (unmatched PONG) */
1655 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1657 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1658 GNUNET_i2s (peer), count);
1662 matched = GNUNET_NO;
1663 va = pos->addresses;
1666 if (va->challenge == challenge)
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1672 GNUNET_a2s ((const struct sockaddr *) sender_address,
1673 sender_address_len));
1675 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1677 ("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"),
1678 GNUNET_a2s ((const struct sockaddr *) &va[1],
1680 va->ok = GNUNET_YES;
1682 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1683 matched = GNUNET_YES;
1685 if (va->ok != GNUNET_YES)
1689 if (GNUNET_NO == matched)
1691 /* TODO: call statistics (unmatched PONG) */
1692 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1694 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1701 "All addresses validated, will now construct `%s' for `%4s'.\n",
1702 "HELLO", GNUNET_i2s (peer));
1704 pos->timeout.value = 0;
1705 GNUNET_SCHEDULER_add_with_priority (sched,
1706 GNUNET_SCHEDULER_PRIORITY_IDLE,
1707 &cleanup_validation, NULL);
1712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1713 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
1714 not_done, "PONG", "HELLO", GNUNET_i2s (peer));
1720 struct CheckHelloValidatedContext
1723 * Plugin for which we are validating.
1725 struct TransportPlugin *plugin;
1728 * Hello that we are validating.
1730 struct GNUNET_HELLO_Message *hello;
1733 * Validation list being build.
1735 struct ValidationList *e;
1738 * Context for peerinfo iteration.
1739 * NULL after we are done processing peerinfo's information.
1741 struct GNUNET_PEERINFO_IteratorContext *piter;
1747 * Append the given address to the list of entries
1748 * that need to be validated.
1751 run_validation (void *cls,
1753 struct GNUNET_TIME_Absolute expiration,
1754 const void *addr, size_t addrlen)
1756 struct ValidationList *e = cls;
1757 struct TransportPlugin *tp;
1758 struct ValidationAddress *va;
1759 struct GNUNET_PeerIdentity id;
1760 struct GNUNET_MessageHeader *pingMessage;
1762 tp = find_transport (tname);
1765 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1766 GNUNET_ERROR_TYPE_BULK,
1768 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1772 GNUNET_CRYPTO_hash (&e->publicKey,
1774 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1777 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1778 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1780 va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
1781 va->next = e->addresses;
1783 va->transport_name = GNUNET_strdup (tname);
1784 va->addr_len = addrlen;
1785 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1787 memcpy (&va[1], addr, addrlen);
1789 pingMessage = createPingMessage(&id, va);
1791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message to address `%s' via `%s' for `%4s'\n",
1792 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1795 sent = tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1796 TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
1798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
1800 GNUNET_free(pingMessage);
1806 * @param cls handle to the plugin (for sending)
1807 * @param target the peer identity of the peer we are sending to
1808 * @param challenge the challenge number
1809 * @param timeout how long to await validation?
1810 * @param addr the address to validate
1811 * @param addrlen the length of the address
1813 * Perform address validation, which means sending a PING PONG to
1814 * the address via the transport plugin. If not validated, then
1815 * do not count this as a good peer/address...
1819 validate_address (void *cls, struct ValidationAddress *va,
1820 const struct GNUNET_PeerIdentity *target,
1821 struct GNUNET_TIME_Relative timeout,
1822 const void *addr, size_t addrlen)
1824 /* struct Plugin *plugin = cls;
1825 int challenge = va->challenge; */
1833 * Check if addresses in validated hello "h" overlap with
1834 * those in "chvc->hello" and update "chvc->hello" accordingly,
1835 * removing those addresses that have already been validated.
1838 check_hello_validated (void *cls,
1839 const struct GNUNET_PeerIdentity *peer,
1840 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1842 struct CheckHelloValidatedContext *chvc = cls;
1843 struct ValidationAddress *va;
1844 struct TransportPlugin *tp;
1847 struct GNUNET_PeerIdentity apeer;
1849 first_call = GNUNET_NO;
1850 if (chvc->e == NULL)
1853 first_call = GNUNET_YES;
1854 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1855 GNUNET_assert (GNUNET_OK ==
1856 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1857 &chvc->e->publicKey));
1859 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1860 chvc->e->next = pending_validations;
1861 pending_validations = chvc->e;
1863 /* no existing HELLO, all addresses are new */
1864 GNUNET_HELLO_iterate_addresses (chvc->hello,
1865 GNUNET_NO, &run_validation, chvc->e);
1869 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1871 GNUNET_TIME_absolute_get (),
1872 &run_validation, chvc->e);
1874 else if (GNUNET_YES == first_call)
1876 /* no existing HELLO, all addresses are new */
1877 GNUNET_HELLO_iterate_addresses (chvc->hello,
1878 GNUNET_NO, &run_validation, chvc->e);
1882 return; /* wait for next call */
1883 /* finally, transmit validation attempts */
1884 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887 "Ready to validate addresses from `%s' message for peer `%4s'\n",
1888 "HELLO", GNUNET_i2s (&apeer));
1890 va = chvc->e->addresses;
1895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1896 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
1899 GNUNET_a2s ((const struct sockaddr *) &va[1],
1900 va->addr_len), GNUNET_i2s (&apeer));
1902 tp = find_transport (va->transport_name);
1903 GNUNET_assert (tp != NULL);
1904 /* This validation should happen inside the transport, not from the plugin! */
1905 validate_address (tp->api->cls, va, &apeer,
1906 HELLO_VERIFICATION_TIMEOUT,
1907 &va[1], va->addr_len);
1908 /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "Found %d addresses in hello of size %d\n", count, GNUNET_HELLO_size(chvc->hello));
1917 GNUNET_SCHEDULER_add_delayed (sched,
1918 GNUNET_TIME_absolute_get_remaining (chvc->
1920 &cleanup_validation, NULL);
1926 * Process HELLO-message.
1928 * @param plugin transport involved, may be NULL
1929 * @param message the actual message
1930 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1933 process_hello (struct TransportPlugin *plugin,
1934 const struct GNUNET_MessageHeader *message)
1936 struct ValidationList *e;
1938 struct GNUNET_PeerIdentity target;
1939 const struct GNUNET_HELLO_Message *hello;
1940 struct CheckHelloValidatedContext *chvc;
1941 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1943 hsize = ntohs (message->size);
1944 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1945 (hsize < sizeof (struct GNUNET_MessageHeader)))
1948 return GNUNET_SYSERR;
1950 /* first, check if load is too high */
1951 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1953 /* TODO: call to stats? */
1956 hello = (const struct GNUNET_HELLO_Message *) message;
1957 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1959 GNUNET_break_op (0);
1960 return GNUNET_SYSERR;
1962 GNUNET_CRYPTO_hash (&publicKey,
1963 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1964 &target.hashPubKey);
1966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1967 "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
1968 "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
1970 /* check if a HELLO for this peer is already on the validation list */
1971 e = pending_validations;
1974 if (0 == memcmp (&e->publicKey,
1977 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1979 /* TODO: call to stats? */
1981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1982 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1983 "HELLO", GNUNET_i2s (&target));
1989 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1990 chvc->plugin = plugin;
1991 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1992 memcpy (chvc->hello, hello, hsize);
1993 /* finally, check if HELLO was previously validated
1994 (continuation will then schedule actual validation) */
1995 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
1999 HELLO_VERIFICATION_TIMEOUT,
2000 &check_hello_validated, chvc);
2006 * The peer specified by the given neighbor has timed-out or a plugin
2007 * has disconnected. We may either need to do nothing (other plugins
2008 * still up), or trigger a full disconnect and clean up. This
2009 * function updates our state and do the necessary notifications.
2010 * Also notifies our clients that the neighbor is now officially
2013 * @param n the neighbor list entry for the peer
2014 * @param check should we just check if all plugins
2015 * disconnected or must we ask all plugins to
2019 disconnect_neighbor (struct NeighborList *n, int check)
2021 struct ReadyList *rpos;
2022 struct NeighborList *npos;
2023 struct NeighborList *nprev;
2024 struct MessageQueue *mq;
2026 if (GNUNET_YES == check)
2029 while (NULL != rpos)
2031 if (GNUNET_YES == rpos->connected)
2032 return; /* still connected */
2038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2039 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2041 /* remove n from neighbors list */
2044 while ((npos != NULL) && (npos != n))
2049 GNUNET_assert (npos != NULL);
2051 neighbors = n->next;
2053 nprev->next = n->next;
2055 /* notify all clients about disconnect */
2056 notify_clients_disconnect (&n->id);
2058 /* clean up all plugins, cancel connections and pending transmissions */
2059 while (NULL != (rpos = n->plugins))
2061 n->plugins = rpos->next;
2062 GNUNET_assert (rpos->neighbor == n);
2063 if (GNUNET_YES == rpos->connected)
2064 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2068 /* free all messages on the queue */
2069 while (NULL != (mq = n->messages))
2071 n->messages = mq->next;
2072 GNUNET_assert (mq->neighbor == n);
2075 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2076 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2077 /* finally, free n itself */
2083 * Add an entry for each of our transport plugins
2084 * (that are able to send) to the list of plugins
2085 * for this neighbor.
2087 * @param neighbor to initialize
2090 add_plugins (struct NeighborList *neighbor)
2092 struct TransportPlugin *tp;
2093 struct ReadyList *rl;
2095 neighbor->retry_plugins_time
2096 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2100 if (tp->api->send != NULL)
2102 rl = GNUNET_malloc (sizeof (struct ReadyList));
2103 rl->next = neighbor->plugins;
2104 neighbor->plugins = rl;
2106 rl->neighbor = neighbor;
2107 rl->transmit_ready = GNUNET_YES;
2115 neighbor_timeout_task (void *cls,
2116 const struct GNUNET_SCHEDULER_TaskContext *tc)
2118 struct NeighborList *n = cls;
2121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2122 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2124 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2125 disconnect_neighbor (n, GNUNET_NO);
2130 * Create a fresh entry in our neighbor list for the given peer.
2131 * Will try to transmit our current HELLO to the new neighbor. Also
2132 * notifies our clients about the new "connection".
2134 * @param peer the peer for which we create the entry
2135 * @return the new neighbor list entry
2137 static struct NeighborList *
2138 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
2140 struct NeighborList *n;
2143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2144 "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
2147 GNUNET_assert (our_hello != NULL);
2148 n = GNUNET_malloc (sizeof (struct NeighborList));
2149 n->next = neighbors;
2152 n->last_quota_update = GNUNET_TIME_absolute_get ();
2154 GNUNET_TIME_relative_to_absolute
2155 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2156 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2158 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2159 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2160 &neighbor_timeout_task, n);
2161 transmit_to_peer (NULL, 0,
2162 (const struct GNUNET_MessageHeader *) our_hello,
2164 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2169 * We have received a PING message from someone. Need to send a PONG message
2170 * in response to the peer by any means necessary. Of course, with something
2171 * like TCP where a connection exists, we may want to send it that way. But
2172 * we may not be able to make that distinction...
2174 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2175 const struct GNUNET_PeerIdentity *peer,
2176 const char *sender_address,
2177 size_t sender_address_len)
2179 struct TransportPlugin *plugin = cls;
2180 struct TransportPingMessage *ping;
2181 struct TransportPongMessage *pong;
2183 struct NeighborList *n;
2184 pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2188 "Processing `%s' from `%s'\n",
2189 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2192 msize = ntohs (message->size);
2193 if (msize < sizeof (struct TransportPingMessage))
2195 GNUNET_break_op (0);
2196 return GNUNET_SYSERR;
2198 ping = (struct TransportPingMessage *) message;
2199 if (0 != memcmp (&ping->target,
2200 plugin->env.my_identity,
2201 sizeof (struct GNUNET_PeerIdentity)))
2203 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2204 _("Received `%s' message not destined for me!\n"), "PING");
2205 return GNUNET_SYSERR;
2208 msize -= sizeof (struct TransportPingMessage);
2210 * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
2212 GNUNET_break_op (0);
2213 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2217 if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
2220 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2224 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2225 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2226 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2227 pong->purpose.size =
2228 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2230 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2231 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2232 pong->challenge = ping->challenge;
2234 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2235 memcpy (&pong[1], sender_address, sender_address_len);
2236 GNUNET_assert (GNUNET_OK ==
2237 GNUNET_CRYPTO_rsa_sign (my_private_key,
2238 &pong->purpose, &pong->signature));
2239 /* Will this nonsense work, even for UDP?
2240 * The idea is that we need an address to send to for UDP, but we may not know
2241 * this peer yet. So in that case, we need to create a new neighbor with the
2242 * current address, but is this address going to be correct, or will it have a
2243 * random high port or something? Another question is, why didn't we get a WELCOME
2244 * from this peer with its advertised addresses already? We don't want to
2245 * differentiate based on transport... */
2246 n = find_neighbor(peer, NULL, 0);
2250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2251 "Didn't find peer in list, adding...\n");
2253 setup_new_neighbor(peer, sender_address, sender_address_len);
2254 n = find_neighbor(peer, sender_address, sender_address_len);
2255 GNUNET_assert(n != NULL);
2257 else if (n->addr == NULL)
2260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2261 "Found peer in list, but without address, adding!\n");
2263 n->addr = GNUNET_malloc(sender_address_len);
2264 memcpy(n->addr, sender_address, sender_address_len);
2265 n->addr_len = sender_address_len;
2268 transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, n);
2275 * Function called by the plugin for each received message.
2276 * Update data volumes, possibly notify plugins about
2277 * reducing the rate at which they read from the socket
2278 * and generally forward to our receive callback.
2280 * @param cls the "struct TransportPlugin *" we gave to the plugin
2281 * @param message the message, NULL if peer was disconnected
2282 * @param distance the transport cost to this peer (not latency!)
2283 * @param sender_address the address that the sender reported
2284 * (opaque to transport service)
2285 * @param sender_address_len the length of the sender address
2286 * @param peer (claimed) identity of the other peer
2287 * @return the new service_context that the plugin should use
2288 * for future receive calls for messages from this
2293 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2294 const struct GNUNET_MessageHeader *message,
2295 unsigned int distance, const char *sender_address,
2296 size_t sender_address_len)
2298 const struct GNUNET_MessageHeader ack = {
2299 htons (sizeof (struct GNUNET_MessageHeader)),
2300 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2302 struct ReadyList *service_context;
2303 struct TransportPlugin *plugin = cls;
2304 struct TransportClient *cpos;
2305 struct InboundMessage *im;
2307 struct NeighborList *n;
2309 n = find_neighbor (peer, sender_address, sender_address_len);
2312 if (message == NULL)
2313 return; /* disconnect of peer already marked down */
2314 n = setup_new_neighbor (peer, sender_address, sender_address_len);
2316 service_context = n->plugins;
2317 while ((service_context != NULL) && (plugin != service_context->plugin))
2318 service_context = service_context->next;
2319 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2320 if (message == NULL)
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2324 "Receive failed from `%4s', triggering disconnect\n",
2325 GNUNET_i2s (&n->id));
2327 /* TODO: call stats */
2328 if (service_context != NULL)
2329 service_context->connected = GNUNET_NO;
2330 disconnect_neighbor (n, GNUNET_YES);
2334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2335 "Processing message of type `%u' received by plugin...\n",
2336 ntohs (message->type));
2338 if (service_context != NULL)
2340 if (service_context->connected == GNUNET_NO)
2342 service_context->connected = GNUNET_YES;
2343 service_context->transmit_ready = GNUNET_YES;
2344 service_context->connect_attempts++;
2346 service_context->timeout
2348 GNUNET_TIME_relative_to_absolute
2349 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2350 /* service_context->latency = latency; */ /* This value should be set by us! */
2352 /* update traffic received amount ... */
2353 msize = ntohs (message->size);
2354 n->last_received += msize;
2355 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2357 GNUNET_TIME_relative_to_absolute
2358 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2360 GNUNET_SCHEDULER_add_delayed (sched,
2361 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2362 &neighbor_timeout_task, n);
2364 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2366 /* dropping message due to frequent inbound volume violations! */
2367 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2368 GNUNET_ERROR_TYPE_BULK,
2370 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2371 /* TODO: call stats */
2372 GNUNET_assert ((service_context == NULL) ||
2373 (NULL != service_context->neighbor));
2376 switch (ntohs (message->type))
2378 case GNUNET_MESSAGE_TYPE_HELLO:
2380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2381 "Receiving `%s' message from `%4s'.\n", "HELLO",
2384 process_hello (plugin, message);
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
2390 transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2392 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2393 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2395 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2396 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2398 //plugin_env_notify_validation();
2399 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2400 n->saw_ack = GNUNET_YES;
2401 /* intentional fall-through! */
2404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2405 "Received message of type %u from `%4s', sending to all clients.\n",
2406 ntohs (message->type), GNUNET_i2s (peer));
2408 /* transmit message to all clients */
2409 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2410 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2411 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2412 im->latency = n->latency;
2414 memcpy (&im[1], message, msize);
2417 while (cpos != NULL)
2419 transmit_to_client (cpos, &im->header, GNUNET_YES);
2424 GNUNET_assert ((service_context == NULL) ||
2425 (NULL != service_context->neighbor));
2430 * Handle START-message. This is the first message sent to us
2431 * by any client which causes us to add it to our list.
2433 * @param cls closure (always NULL)
2434 * @param client identification of the client
2435 * @param message the actual message
2438 handle_start (void *cls,
2439 struct GNUNET_SERVER_Client *client,
2440 const struct GNUNET_MessageHeader *message)
2442 struct TransportClient *c;
2443 struct ConnectInfoMessage cim;
2444 struct NeighborList *n;
2445 struct InboundMessage *im;
2446 struct GNUNET_MessageHeader *ack;
2449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2450 "Received `%s' request from client\n", "START");
2455 if (c->client == client)
2457 /* client already on our list! */
2459 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2464 c = GNUNET_malloc (sizeof (struct TransportClient));
2468 if (our_hello != NULL)
2471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2472 "Sending our own `%s' to new client\n", "HELLO");
2474 transmit_to_client (c,
2475 (const struct GNUNET_MessageHeader *) our_hello,
2477 /* tell new client about all existing connections */
2478 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2479 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2481 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2482 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2483 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2484 sizeof (struct GNUNET_MessageHeader));
2485 im->header.size = htons (sizeof (struct InboundMessage) +
2486 sizeof (struct GNUNET_MessageHeader));
2487 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2488 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2489 ack = (struct GNUNET_MessageHeader *) &im[1];
2490 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2491 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2492 for (n = neighbors; n != NULL; n = n->next)
2495 transmit_to_client (c, &cim.header, GNUNET_NO);
2499 transmit_to_client (c, &im->header, GNUNET_NO);
2506 fprintf(stderr, "Our hello is NULL!\n");
2508 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2513 * Handle HELLO-message.
2515 * @param cls closure (always NULL)
2516 * @param client identification of the client
2517 * @param message the actual message
2520 handle_hello (void *cls,
2521 struct GNUNET_SERVER_Client *client,
2522 const struct GNUNET_MessageHeader *message)
2527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2528 "Received `%s' request from client\n", "HELLO");
2530 ret = process_hello (NULL, message);
2531 GNUNET_SERVER_receive_done (client, ret);
2536 * Handle SEND-message.
2538 * @param cls closure (always NULL)
2539 * @param client identification of the client
2540 * @param message the actual message
2543 handle_send (void *cls,
2544 struct GNUNET_SERVER_Client *client,
2545 const struct GNUNET_MessageHeader *message)
2547 struct TransportClient *tc;
2548 struct NeighborList *n;
2549 const struct OutboundMessage *obm;
2550 const struct GNUNET_MessageHeader *obmm;
2554 size = ntohs (message->size);
2556 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2559 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2562 obm = (const struct OutboundMessage *) message;
2564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2565 "Received `%s' request from client with target `%4s'\n",
2566 "SEND", GNUNET_i2s (&obm->peer));
2568 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2569 msize = ntohs (obmm->size);
2570 if (size != msize + sizeof (struct OutboundMessage))
2573 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2576 n = find_neighbor (&obm->peer, NULL, 0);
2578 n = setup_new_neighbor (&obm->peer, NULL, 0);
2580 while ((tc != NULL) && (tc->client != client))
2584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2587 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2589 transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
2590 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2595 * Handle SET_QUOTA-message.
2597 * @param cls closure (always NULL)
2598 * @param client identification of the client
2599 * @param message the actual message
2602 handle_set_quota (void *cls,
2603 struct GNUNET_SERVER_Client *client,
2604 const struct GNUNET_MessageHeader *message)
2606 const struct QuotaSetMessage *qsm =
2607 (const struct QuotaSetMessage *) message;
2608 struct NeighborList *n;
2609 struct TransportPlugin *p;
2610 struct ReadyList *rl;
2613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2614 "Received `%s' request from client for peer `%4s'\n",
2615 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2617 n = find_neighbor (&qsm->peer, NULL, 0);
2620 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2624 if (n->quota_in < ntohl (qsm->quota_in))
2625 n->last_quota_update = GNUNET_TIME_absolute_get ();
2626 n->quota_in = ntohl (qsm->quota_in);
2631 p->api->set_receive_quota (p->api->cls,
2632 &qsm->peer, ntohl (qsm->quota_in));
2635 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2640 * Handle TRY_CONNECT-message.
2642 * @param cls closure (always NULL)
2643 * @param client identification of the client
2644 * @param message the actual message
2647 handle_try_connect (void *cls,
2648 struct GNUNET_SERVER_Client *client,
2649 const struct GNUNET_MessageHeader *message)
2651 const struct TryConnectMessage *tcm;
2653 tcm = (const struct TryConnectMessage *) message;
2655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2656 "Received `%s' request from client %p asking to connect to `%4s'\n",
2657 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2659 if (NULL == find_neighbor (&tcm->peer, NULL, 0))
2660 setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
2661 knowing its address? Should we ask the plugin
2662 for more information about this peer? I don't
2663 think we can... Or set up new peer should only
2664 happen when transport notifies us of an address,
2665 and this setup should check for an address in
2666 the existing list only */
2669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2670 "Client asked to connect to `%4s', but connection already exists\n",
2671 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2673 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2677 transmit_address_to_client (void *cls, const char *address)
2679 struct GNUNET_SERVER_TransmitContext *tc = cls;
2682 if (NULL == address)
2685 slen = strlen (address) + 1;
2686 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2687 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2688 if (NULL == address)
2689 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2693 * Handle AddressLookup-message.
2695 * @param cls closure (always NULL)
2696 * @param client identification of the client
2697 * @param message the actual message
2700 handle_address_lookup (void *cls,
2701 struct GNUNET_SERVER_Client *client,
2702 const struct GNUNET_MessageHeader *message)
2704 const struct AddressLookupMessage *alum;
2705 struct TransportPlugin *lsPlugin;
2706 const char *nameTransport;
2707 const char *address;
2709 struct GNUNET_SERVER_TransmitContext *tc;
2711 size = ntohs (message->size);
2712 if (size < sizeof (struct AddressLookupMessage))
2714 GNUNET_break_op (0);
2715 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2718 alum = (const struct AddressLookupMessage *) message;
2719 uint32_t addressLen = ntohl (alum->addrlen);
2720 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2722 GNUNET_break_op (0);
2723 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2726 address = (const char *) &alum[1];
2727 nameTransport = (const char *) &address[addressLen];
2729 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2731 GNUNET_break_op (0);
2732 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2735 struct GNUNET_TIME_Absolute timeout =
2736 GNUNET_TIME_absolute_ntoh (alum->timeout);
2737 struct GNUNET_TIME_Relative rtimeout =
2738 GNUNET_TIME_absolute_get_remaining (timeout);
2739 lsPlugin = find_transport (nameTransport);
2740 if (NULL == lsPlugin)
2742 tc = GNUNET_SERVER_transmit_context_create (client);
2743 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2744 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2745 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2748 tc = GNUNET_SERVER_transmit_context_create (client);
2749 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2750 address, addressLen, GNUNET_YES,
2752 &transmit_address_to_client, tc);
2756 * List of handlers for the messages understood by this
2759 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2760 {&handle_start, NULL,
2761 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2762 {&handle_hello, NULL,
2763 GNUNET_MESSAGE_TYPE_HELLO, 0},
2764 {&handle_send, NULL,
2765 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2766 {&handle_set_quota, NULL,
2767 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2768 {&handle_try_connect, NULL,
2769 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2770 sizeof (struct TryConnectMessage)},
2771 {&handle_address_lookup, NULL,
2772 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2779 * Setup the environment for this plugin.
2782 create_environment (struct TransportPlugin *plug)
2784 plug->env.cfg = cfg;
2785 plug->env.sched = sched;
2786 plug->env.my_identity = &my_identity;
2787 plug->env.cls = plug;
2788 plug->env.receive = &plugin_env_receive;
2789 plug->env.notify_address = &plugin_env_notify_address;
2790 plug->env.default_quota_in =
2791 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2792 plug->env.max_connections = max_connect_per_transport;
2797 * Start the specified transport (load the plugin).
2800 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2802 struct TransportPlugin *plug;
2805 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2806 _("Loading `%s' transport plugin\n"), name);
2807 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2808 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2809 create_environment (plug);
2810 plug->short_name = GNUNET_strdup (name);
2811 plug->lib_name = libname;
2812 plug->next = plugins;
2814 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2815 if (plug->api == NULL)
2817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2818 _("Failed to load transport plugin for `%s'\n"), name);
2819 GNUNET_free (plug->short_name);
2820 plugins = plug->next;
2821 GNUNET_free (libname);
2828 * Called whenever a client is disconnected. Frees our
2829 * resources associated with that client.
2831 * @param cls closure
2832 * @param client identification of the client
2835 client_disconnect_notification (void *cls,
2836 struct GNUNET_SERVER_Client *client)
2838 struct TransportClient *pos;
2839 struct TransportClient *prev;
2840 struct ClientMessageQueueEntry *mqe;
2845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2846 "Client disconnected, cleaning up.\n");
2850 while ((pos != NULL) && (pos->client != client))
2857 while (NULL != (mqe = pos->message_queue_head))
2859 pos->message_queue_head = mqe->next;
2862 pos->message_queue_head = NULL;
2864 clients = pos->next;
2866 prev->next = pos->next;
2867 if (GNUNET_YES == pos->tcs_pending)
2877 * Function called when the service shuts down. Unloads our plugins.
2879 * @param cls closure, unused
2880 * @param tc task context (unused)
2883 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2885 struct TransportPlugin *plug;
2886 struct AddressList *al;
2889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2890 "Transport service is unloading plugins...\n");
2892 while (NULL != (plug = plugins))
2894 plugins = plug->next;
2895 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2896 GNUNET_free (plug->lib_name);
2897 GNUNET_free (plug->short_name);
2898 while (NULL != (al = plug->addresses))
2900 plug->addresses = al->next;
2905 if (my_private_key != NULL)
2906 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2907 GNUNET_free_non_null (our_hello);
2912 * Initiate transport service.
2914 * @param cls closure
2915 * @param s scheduler to use
2916 * @param serv the initialized server
2917 * @param c configuration to use
2921 struct GNUNET_SCHEDULER_Handle *s,
2922 struct GNUNET_SERVER_Handle *serv,
2923 const struct GNUNET_CONFIGURATION_Handle *c)
2928 unsigned long long tneigh;
2933 /* parse configuration */
2935 GNUNET_CONFIGURATION_get_value_number (c,
2940 GNUNET_CONFIGURATION_get_value_filename (c,
2942 "HOSTKEY", &keyfile)))
2944 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2946 ("Transport service is lacking key configuration settings. Exiting.\n"));
2947 GNUNET_SCHEDULER_shutdown (s);
2950 max_connect_per_transport = (uint32_t) tneigh;
2951 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2952 GNUNET_free (keyfile);
2953 if (my_private_key == NULL)
2955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2957 ("Transport service could not access hostkey. Exiting.\n"));
2958 GNUNET_SCHEDULER_shutdown (s);
2961 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2962 GNUNET_CRYPTO_hash (&my_public_key,
2963 sizeof (my_public_key), &my_identity.hashPubKey);
2964 /* setup notification */
2966 GNUNET_SERVER_disconnect_notify (server,
2967 &client_disconnect_notification, NULL);
2968 /* load plugins... */
2971 GNUNET_CONFIGURATION_get_value_string (c,
2972 "TRANSPORT", "PLUGINS", &plugs))
2974 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2975 _("Starting transport plugins `%s'\n"), plugs);
2976 pos = strtok (plugs, " ");
2979 start_transport (server, pos);
2981 pos = strtok (NULL, " ");
2983 GNUNET_free (plugs);
2985 GNUNET_SCHEDULER_add_delayed (sched,
2986 GNUNET_TIME_UNIT_FOREVER_REL,
2987 &unload_plugins, NULL);
2992 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2994 /* process client requests */
2995 GNUNET_SERVER_add_handlers (server, handlers);
3000 * The main function for the transport service.
3002 * @param argc number of arguments from the command line
3003 * @param argv command line arguments
3004 * @return 0 ok, 1 on error
3007 main (int argc, char *const *argv)
3009 return (GNUNET_OK ==
3010 GNUNET_SERVICE_run (argc,
3013 GNUNET_SERVICE_OPTION_NONE,
3014 &run, NULL)) ? 0 : 1;
3017 /* end of gnunet-service-transport.c */