2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
27 * - remove AddressValidations, incorporate them into the PeerAddressLists
30 #include "gnunet_client_lib.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_getopt_lib.h"
33 #include "gnunet_hello_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_peerinfo_service.h"
36 #include "gnunet_plugin_lib.h"
37 #include "gnunet_protocols.h"
38 #include "gnunet_service_lib.h"
39 #include "gnunet_signatures.h"
40 #include "plugin_transport.h"
41 #include "transport.h"
44 * How many messages can we have pending for a given client process
45 * before we start to drop incoming messages? We typically should
46 * have only one client and so this would be the primary buffer for
47 * messages, so the number should be chosen rather generously.
49 * The expectation here is that most of the time the queue is large
50 * enough so that a drop is virtually never required.
52 #define MAX_PENDING 128
55 * How often should we try to reconnect to a peer using a particular
56 * transport plugin before giving up? Note that the plugin may be
57 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
59 #define MAX_CONNECT_RETRY 3
62 * How often must a peer violate bandwidth quotas before we start
63 * to simply drop its messages?
65 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
68 * How long until a HELLO verification attempt should time out?
69 * Must be rather small, otherwise a partially successful HELLO
70 * validation (some addresses working) might not be available
71 * before a client's request for a connection fails for good.
72 * Besides, if a single request to an address takes a long time,
73 * then the peer is unlikely worthwhile anyway.
75 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
78 * How long will we allow sending of a ping to be delayed?
80 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
82 #define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */
85 * How often do we re-add (cheaper) plugins to our list of plugins
86 * to try for a given connected peer?
88 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
91 * After how long do we expire an address in a HELLO
92 * that we just validated? This value is also used
93 * for our own addresses when we create a HELLO.
95 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
99 * List of addresses of other peers
101 struct PeerAddressList
104 * This is a linked list.
106 struct PeerAddressList *next;
109 * Pointer to the validation associated with this
110 * address. May be NULL if already validated!
112 struct ValidationAddress *validation;
115 * Which of our transport plugins does this entry
118 struct TransportPlugin *plugin;
121 * Neighbor this entry belongs to.
123 struct NeighborList *neighbor;
126 * Ready list (transport) that this peer belongs to
128 struct ReadyList *ready_list;
130 * How long until we auto-expire this address (unless it is
131 * re-confirmed by the transport)?
133 struct GNUNET_TIME_Absolute expires;
146 * Is this plugin ready to transmit to the specific target?
147 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
148 * transmission is in progress, "transmit_ready" is set to
154 * What was the last latency observed for this plugin
155 * and peer? Invalid if connected is GNUNET_NO.
157 struct GNUNET_TIME_Relative latency;
160 * If we did not successfully transmit a message to the given peer
161 * via this connection during the specified time, we should consider
162 * the connection to be dead. This is used in the case that a TCP
163 * transport simply stalls writing to the stream but does not
164 * formerly get a signal that the other peer died.
166 struct GNUNET_TIME_Absolute timeout;
169 * Is this plugin currently connected? The first time
170 * we transmit or send data to a peer via a particular
171 * plugin, we set this to GNUNET_YES. If we later get
172 * an error (disconnect notification or transmission
173 * failure), we set it back to GNUNET_NO. Each time the
174 * value is set to GNUNET_YES, we increment the
175 * "connect_attempts" counter. If that one reaches a
176 * particular threshold, we consider the plugin to not
177 * be working properly at this time for the given peer
178 * and remove it from the eligible list.
183 * How often have we tried to connect using this plugin?
185 unsigned int connect_attempts;
191 * Entry in linked list of network addresses.
196 * This is a linked list.
198 struct AddressList *next;
201 * The address, actually a pointer to the end
202 * of this struct. Do not free!
207 * How long until we auto-expire this address (unless it is
208 * re-confirmed by the transport)?
210 struct GNUNET_TIME_Absolute expires;
221 * Entry in linked list of all of our plugins.
223 struct TransportPlugin
227 * This is a linked list.
229 struct TransportPlugin *next;
232 * API of the transport as returned by the plugin's
233 * initialization function.
235 struct GNUNET_TRANSPORT_PluginFunctions *api;
238 * Short name for the plugin (i.e. "tcp").
243 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
248 * List of our known addresses for this transport.
250 struct AddressList *addresses;
253 * Environment this transport service is using
256 struct GNUNET_TRANSPORT_PluginEnvironment env;
259 * ID of task that is used to clean up expired addresses.
261 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
265 * Set to GNUNET_YES if we need to scrap the existing
266 * list of "addresses" and start fresh when we receive
267 * the next address update from a transport. Set to
268 * GNUNET_NO if we should just add the new address
269 * to the list and wait for the commit call.
277 * For each neighbor we keep a list of messages
278 * that we still want to transmit to the neighbor.
284 * This is a linked list.
286 struct MessageQueue *next;
289 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
290 * stuck together in memory.
295 * Size of the message buf
297 size_t message_buf_size;
300 * Client responsible for queueing the message;
301 * used to check that a client has no two messages
302 * pending for the same target. Can be NULL.
304 struct TransportClient *client;
307 * Neighbor this entry belongs to.
309 /*struct NeighborList *neighbor;*/
312 * Peer ID of the Neighbor this entry belongs to.
314 struct GNUNET_PeerIdentity *neighbor_id;
317 * Plugin that we used for the transmission.
318 * NULL until we scheduled a transmission.
320 struct TransportPlugin *plugin;
323 * Internal message of the transport system that should not be
324 * included in the usual SEND-SEND_OK transmission confirmation
325 * traffic management scheme. Typically, "internal_msg" will
326 * be set whenever "client" is NULL (but it is not strictly
332 * How important is the message?
334 unsigned int priority;
337 * Using which specific address should we send this message?
339 struct PeerAddressList *specific_peer;
345 * For a given Neighbor, which plugins are available
346 * to talk to this peer and what are their costs?
351 * This is a linked list.
353 struct ReadyList *next;
356 * Which of our transport plugins does this entry
359 struct TransportPlugin *plugin;
362 * Neighbor this entry belongs to.
364 struct NeighborList *neighbor;
367 * Transport addresses, latency, and readiness for
368 * this particular plugin.
370 struct PeerAddressList *addresses;
373 * Is this plugin ready to transmit to the specific target?
374 * GNUNET_NO if not. Initially, all plugins are marked ready. If a
375 * transmission is in progress, "transmit_ready" is set to
378 int plugin_transmit_ready;
381 * Are any of our PeerAddressList addresses still connected?
383 int connected; /* FIXME: dynamically check PeerAddressList addresses when asked to! */
388 * Entry in linked list of all of our current neighbors.
394 * This is a linked list.
396 struct NeighborList *next;
399 * Which of our transports is connected to this peer
400 * and what is their status?
402 struct ReadyList *plugins;
405 * List of messages we would like to send to this peer;
406 * must contain at most one message per client.
408 struct MessageQueue *messages;
411 * Identity of this neighbor.
413 struct GNUNET_PeerIdentity id;
416 * ID of task scheduled to run when this peer is about to
417 * time out (will free resources associated with the peer).
419 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
422 * How long until we should consider this peer dead
423 * (if we don't receive another message in the
426 struct GNUNET_TIME_Absolute peer_timeout;
429 * At what time did we reset last_received last?
431 struct GNUNET_TIME_Absolute last_quota_update;
434 * At what time should we try to again add plugins to
437 struct GNUNET_TIME_Absolute retry_plugins_time;
440 * How many bytes have we received since the "last_quota_update"
443 uint64_t last_received;
446 * Global quota for inbound traffic for the neighbor in bytes/ms.
451 * How often has the other peer (recently) violated the
452 * inbound traffic limit? Incremented by 10 per violation,
453 * decremented by 1 per non-violation (for each
456 unsigned int quota_violation_count;
459 * Have we seen an ACK from this neighbor in the past?
460 * (used to make up a fake ACK for clients connecting after
461 * the neighbor connected to us).
465 /* The latency we have seen for this particular address for
466 * this particular peer. This latency may have been calculated
467 * over multiple transports. This value reflects how long it took
468 * us to receive a response when SENDING via this particular
469 * transport/neighbor/address combination!
471 struct GNUNET_TIME_RelativeNBO latency;
476 * Message used to ask a peer to validate receipt (to check an address
477 * from a HELLO). Followed by the address used. Note that the
478 * recipients response does not affirm that he has this address,
479 * only that he got the challenge message.
481 struct TransportPingMessage
485 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
487 struct GNUNET_MessageHeader header;
490 * Random challenge number (in network byte order).
492 uint32_t challenge GNUNET_PACKED;
495 * Who is the intended recipient?
497 struct GNUNET_PeerIdentity target;
503 * Message used to validate a HELLO. The challenge is included in the
504 * confirmation to make matching of replies to requests possible. The
505 * signature signs the original challenge number, our public key, the
506 * sender's address (so that the sender can check that the address we
507 * saw is plausible for him and possibly detect a MiM attack) and a
508 * timestamp (to limit replay).<p>
510 * This message is followed by the address of the
511 * client that we are observing (which is part of what
514 struct TransportPongMessage
518 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
520 struct GNUNET_MessageHeader header;
523 * For padding, always zero.
525 uint32_t reserved GNUNET_PACKED;
530 struct GNUNET_CRYPTO_RsaSignature signature;
533 * What are we signing and why?
535 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
538 * Random challenge number (in network byte order).
540 uint32_t challenge GNUNET_PACKED;
543 * Who signed this message?
545 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
548 * Size of address appended to this message
555 * Linked list of messages to be transmitted to
556 * the client. Each entry is followed by the
559 struct ClientMessageQueueEntry
562 * This is a linked list.
564 struct ClientMessageQueueEntry *next;
569 * Client connected to the transport service.
571 struct TransportClient
575 * This is a linked list.
577 struct TransportClient *next;
580 * Handle to the client.
582 struct GNUNET_SERVER_Client *client;
585 * Linked list of messages yet to be transmitted to
588 struct ClientMessageQueueEntry *message_queue_head;
591 * Tail of linked list of messages yet to be transmitted to the
594 struct ClientMessageQueueEntry *message_queue_tail;
597 * Is a call to "transmit_send_continuation" pending? If so, we
598 * must not free this struct (even if the corresponding client
599 * disconnects) and instead only remove it from the linked list and
600 * set the "client" field to NULL.
605 * Length of the list of messages pending for this client.
607 unsigned int message_count;
613 * For each HELLO, we may have to validate multiple addresses;
614 * each address gets its own request entry.
616 struct ValidationAddress
619 * This is a linked list.
621 struct ValidationAddress *next;
624 * What peer_address does this validation belong to?
626 struct PeerAddressList *peer_address;
629 * Name of the transport.
631 char *transport_name;
634 * When should this validated address expire?
636 struct GNUNET_TIME_Absolute expiration;
639 * At what time did we send this validation?
641 struct GNUNET_TIME_Absolute send_time;
644 * Challenge number we used.
649 * Set to GNUNET_YES if the challenge was met,
650 * GNUNET_SYSERR if we know it failed, GNUNET_NO
651 * if we are waiting on a response.
658 * Entry in linked list of all HELLOs awaiting validation.
660 struct ValidationList
664 * This is a linked list.
666 struct ValidationList *next;
669 * Linked list with one entry per address from the HELLO
670 * that needs to be validated.
672 struct ValidationAddress *addresses;
675 * The public key of the peer.
677 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
680 * When does this record time-out? (assuming the
681 * challenge goes unanswered)
683 struct GNUNET_TIME_Absolute timeout;
688 struct CheckHelloValidatedContext
691 * Plugin for which we are validating.
693 struct TransportPlugin *plugin;
696 * Hello that we are validating.
698 struct GNUNET_HELLO_Message *hello;
701 * Validation list being built.
703 struct ValidationList *e;
706 * Context for peerinfo iteration.
707 * NULL after we are done processing peerinfo's information.
709 struct GNUNET_PEERINFO_IteratorContext *piter;
716 * HELLOs awaiting validation.
718 static struct ValidationList *pending_validations;
723 static struct GNUNET_HELLO_Message *our_hello;
726 * "version" of "our_hello". Used to see if a given
727 * neighbor has already been sent the latest version
728 * of our HELLO message.
730 static unsigned int our_hello_version;
735 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
740 static struct GNUNET_PeerIdentity my_identity;
745 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
750 struct GNUNET_SCHEDULER_Handle *sched;
755 const struct GNUNET_CONFIGURATION_Handle *cfg;
758 * Linked list of all clients to this service.
760 static struct TransportClient *clients;
763 * All loaded plugins.
765 static struct TransportPlugin *plugins;
770 static struct GNUNET_SERVER_Handle *server;
773 * All known neighbors and their HELLOs.
775 static struct NeighborList *neighbors;
778 * Number of neighbors we'd like to have.
780 static uint32_t max_connect_per_transport;
783 * The peer specified by the given neighbor has timed-out or a plugin
784 * has disconnected. We may either need to do nothing (other plugins
785 * still up), or trigger a full disconnect and clean up. This
786 * function updates our state and do the necessary notifications.
787 * Also notifies our clients that the neighbor is now officially
790 * @param n the neighbor list entry for the peer
791 * @param check should we just check if all plugins
792 * disconnected or must we ask all plugins to
795 static void disconnect_neighbor (struct NeighborList *n, int check);
799 * Check the ready list for the given neighbor and
800 * if a plugin is ready for transmission (and if we
801 * have a message), do so!
803 * @param neighbor target peer for which to check the plugins
805 static ssize_t try_transmission_to_peer (struct NeighborList *neighbor);
809 * Find an entry in the neighbor list for a particular peer.
810 * if sender_address is not specified (NULL) then return the
811 * first matching entry. If sender_address is specified, then
812 * make sure that the address and address_len also matches.
814 * @return NULL if not found.
816 static struct NeighborList *
817 find_neighbor (const struct GNUNET_PeerIdentity *key)
819 struct NeighborList *head = neighbors;
821 while ((head != NULL) &&
822 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
830 * Find an entry in the transport list for a particular transport.
832 * @return NULL if not found.
834 static struct TransportPlugin *
835 find_transport (const char *short_name)
837 struct TransportPlugin *head = plugins;
838 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
845 * Update the quota values for the given neighbor now.
848 update_quota (struct NeighborList *n)
850 struct GNUNET_TIME_Relative delta;
854 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
855 if (delta.value < MIN_QUOTA_REFRESH_TIME)
856 return; /* not enough time passed for doing quota update */
857 allowed = delta.value * n->quota_in;
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
860 GNUNET_ERROR_TYPE_BULK,
862 ("Update quota: last received is %llu, allowed is %llu\n"), n->last_received, allowed);
864 if (n->last_received < allowed)
866 remaining = allowed - n->last_received;
868 remaining /= n->quota_in;
871 if (remaining > MAX_BANDWIDTH_CARRY)
872 remaining = MAX_BANDWIDTH_CARRY;
873 n->last_received = 0;
874 n->last_quota_update = GNUNET_TIME_absolute_get ();
875 n->last_quota_update.value -= remaining;
876 if (n->quota_violation_count > 0)
877 n->quota_violation_count--;
881 n->last_received -= allowed;
882 n->last_quota_update = GNUNET_TIME_absolute_get ();
883 if (n->last_received > allowed)
885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
886 GNUNET_ERROR_TYPE_BULK,
888 ("LAST RECEIVED: %llu greater than allowed : %llu\n"), n->last_received, allowed);
889 /* more than twice the allowed rate! */
890 n->quota_violation_count += 10;
897 * Function called to notify a client about the socket
898 * being ready to queue more data. "buf" will be
899 * NULL and "size" zero if the socket was closed for
900 * writing in the meantime.
903 * @param size number of bytes available in buf
904 * @param buf where the callee should write the message
905 * @return number of bytes written to buf
908 transmit_to_client_callback (void *cls, size_t size, void *buf)
910 struct TransportClient *client = cls;
911 struct ClientMessageQueueEntry *q;
914 const struct GNUNET_MessageHeader *msg;
915 struct GNUNET_CONNECTION_TransmitHandle *th;
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921 "Transmission to client failed, closing connection.\n");
922 /* fatal error with client, free message queue! */
923 while (NULL != (q = client->message_queue_head))
925 client->message_queue_head = q->next;
928 client->message_queue_tail = NULL;
929 client->message_count = 0;
934 while (NULL != (q = client->message_queue_head))
936 msg = (const struct GNUNET_MessageHeader *) &q[1];
937 msize = ntohs (msg->size);
938 if (msize + tsize > size)
941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942 "Transmitting message of type %u to client.\n",
945 client->message_queue_head = q->next;
947 client->message_queue_tail = NULL;
948 memcpy (&cbuf[tsize], msg, msize);
951 client->message_count--;
955 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
956 th = GNUNET_SERVER_notify_transmit_ready (client->client,
958 GNUNET_TIME_UNIT_FOREVER_REL,
959 &transmit_to_client_callback,
961 GNUNET_assert (th != NULL);
968 * Send the specified message to the specified client. Since multiple
969 * messages may be pending for the same client at a time, this code
970 * makes sure that no message is lost.
972 * @param client client to transmit the message to
973 * @param msg the message to send
974 * @param may_drop can this message be dropped if the
975 * message queue for this client is getting far too large?
978 transmit_to_client (struct TransportClient *client,
979 const struct GNUNET_MessageHeader *msg, int may_drop)
981 struct ClientMessageQueueEntry *q;
983 struct GNUNET_CONNECTION_TransmitHandle *th;
985 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
987 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
989 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
990 client->message_count, MAX_PENDING);
991 /* TODO: call to statistics... */
994 client->message_count++;
995 msize = ntohs (msg->size);
996 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
997 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
998 memcpy (&q[1], msg, msize);
999 /* append to message queue */
1000 if (client->message_queue_tail == NULL)
1002 client->message_queue_tail = q;
1006 client->message_queue_tail->next = q;
1007 client->message_queue_tail = q;
1009 if (client->message_queue_head == NULL)
1011 client->message_queue_head = q;
1012 th = GNUNET_SERVER_notify_transmit_ready (client->client,
1014 GNUNET_TIME_UNIT_FOREVER_REL,
1015 &transmit_to_client_callback,
1017 GNUNET_assert (th != NULL);
1023 * Find alternative plugins for communication.
1025 * @param neighbor for which neighbor should we try to find
1029 try_alternative_plugins (struct NeighborList *neighbor)
1031 struct ReadyList *rl;
1033 if ((neighbor->plugins != NULL) &&
1034 (neighbor->retry_plugins_time.value >
1035 GNUNET_TIME_absolute_get ().value))
1036 return; /* don't try right now */
1037 neighbor->retry_plugins_time
1038 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1040 rl = neighbor->plugins;
1041 #if WTF /* FIXME: What is this supposed to do? */
1044 if (rl->connect_attempts > 0)
1045 rl->connect_attempts--; /* amnesty */
1053 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1054 * upon "completion" of a send request. This tells the API
1055 * that it is now legal to send another message to the given
1058 * @param cls closure, identifies the entry on the
1059 * message queue that was transmitted and the
1060 * client responsible for queueing the message
1061 * @param target the peer receiving the message
1062 * @param result GNUNET_OK on success, if the transmission
1063 * failed, we should not tell the client to transmit
1067 transmit_send_continuation (void *cls,
1068 const struct GNUNET_PeerIdentity *target,
1071 struct MessageQueue *mq = cls;
1072 /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1073 struct SendOkMessage send_ok_msg;
1074 struct NeighborList *n;
1076 GNUNET_assert (mq != NULL);
1077 n = find_neighbor(mq->neighbor_id);
1078 if (n == NULL) /* Neighbor must have been removed asynchronously! */
1081 /* Otherwise, let's make sure we've got the right peer */
1083 memcmp (&n->id, target,
1084 sizeof (struct GNUNET_PeerIdentity)));
1086 if (result == GNUNET_OK)
1088 mq->specific_peer->timeout =
1089 GNUNET_TIME_relative_to_absolute
1090 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1095 "Transmission to peer `%s' failed, marking connection as down.\n",
1096 GNUNET_i2s (target));
1097 mq->specific_peer->connected = GNUNET_NO;
1099 if (!mq->internal_msg)
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1103 "Setting transmit_ready on transport!\n");
1105 mq->specific_peer->transmit_ready = GNUNET_YES;
1108 if (mq->client != NULL)
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Notifying client %p about transmission to peer `%4s'.\n",
1112 mq->client, GNUNET_i2s (target));
1113 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1114 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1115 send_ok_msg.success = htonl (result);
1116 send_ok_msg.peer = n->id;
1117 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1119 GNUNET_free (mq->message_buf);
1120 GNUNET_free (mq->neighbor_id);
1122 /* one plugin just became ready again, try transmitting
1123 another message (if available) */
1124 if (result == GNUNET_OK)
1125 try_transmission_to_peer (n);
1127 disconnect_neighbor (n, GNUNET_YES);
1133 struct PeerAddressList *
1134 find_ready_address(struct NeighborList *neighbor)
1136 struct ReadyList *head = neighbor->plugins;
1137 struct PeerAddressList *addresses;
1138 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1139 struct GNUNET_TIME_Relative min_latency = GNUNET_TIME_relative_get_forever();
1140 struct PeerAddressList *best_address;
1142 best_address = NULL;
1143 while (head != NULL)
1145 addresses = head->addresses;
1147 while (addresses != NULL)
1149 if ((addresses->timeout.value < now.value) && (addresses->connected == GNUNET_YES))
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 "Marking long-time inactive connection to `%4s' as down.\n",
1154 GNUNET_i2s (&addresses->ready_list->neighbor->id));
1156 addresses->connected = GNUNET_NO;
1158 addresses = addresses->next;
1161 addresses = head->addresses;
1162 while (addresses != NULL)
1164 if ((addresses->connected == GNUNET_YES) &&
1165 (addresses->transmit_ready == GNUNET_YES) &&
1166 ((best_address == NULL) || (addresses->latency.value < best_address->latency.value)))
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170 "Found address with latency %llu (previous best was %llu), setting as best found yet!\n",
1171 addresses->latency.value, best_address == NULL ? min_latency.value : best_address->latency.value);
1173 best_address = addresses;
1175 addresses = addresses->next;
1180 if (best_address != NULL)
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 "Best address found has latency of %llu!\n",
1184 best_address->latency.value);
1187 return best_address;
1192 * Check the ready list for the given neighbor and
1193 * if a plugin is ready for transmission (and if we
1194 * have a message), do so!
1197 try_transmission_to_peer (struct NeighborList *neighbor)
1199 struct GNUNET_TIME_Relative min_latency;
1200 struct ReadyList *rl;
1201 struct MessageQueue *mq;
1202 struct GNUNET_TIME_Absolute now;
1204 if (neighbor->messages == NULL)
1205 return 0; /* nothing to do */
1206 try_alternative_plugins (neighbor);
1207 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1209 mq = neighbor->messages;
1210 now = GNUNET_TIME_absolute_get ();
1212 if (mq->specific_peer == NULL)
1213 mq->specific_peer = find_ready_address(neighbor); /* Find first available (or best!) address to transmit to */
1215 if (mq->specific_peer == NULL)
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "No plugin ready to transmit message\n");
1221 return 0; /* nobody ready */
1224 rl = mq->specific_peer->ready_list;
1225 neighbor->messages = mq->next;
1226 mq->plugin = rl->plugin;
1227 if (!mq->internal_msg)
1228 mq->specific_peer->transmit_ready = GNUNET_NO;
1230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1231 "Giving message of size `%u' for `%4s' to plugin `%s'\n",
1232 mq->message_buf_size,
1233 GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
1236 return rl->plugin->api->send (rl->plugin->api->cls,
1239 mq->message_buf_size,
1241 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1242 mq->specific_peer->addr,
1243 mq->specific_peer->addrlen,
1245 &transmit_send_continuation, mq);
1251 * Send the specified message to the specified peer.
1253 * @param client source of the transmission request (can be NULL)
1254 * @param peer_address PeerAddressList where we should send this message
1255 * @param priority how important is the message
1256 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1257 * @param message_buf_size total size of all messages in message_buf
1258 * @param is_internal is this an internal message
1259 * @param neighbor handle to the neighbor for transmission
1262 transmit_to_peer (struct TransportClient *client,
1263 struct PeerAddressList *peer_address,
1264 unsigned int priority,
1265 const char *message_buf,
1266 size_t message_buf_size,
1267 int is_internal, struct NeighborList *neighbor)
1269 struct MessageQueue *mq;
1270 struct MessageQueue *mqe;
1275 /* check for duplicate submission */
1276 mq = neighbor->messages;
1279 if (mq->client == client)
1281 /* client transmitted to same peer twice
1282 before getting SendOk! */
1289 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1290 mq->specific_peer = peer_address;
1291 mq->client = client;
1292 m = GNUNET_malloc (message_buf_size);
1293 memcpy (m, message_buf, message_buf_size);
1294 mq->message_buf = m;
1295 mq->message_buf_size = message_buf_size;
1296 mq->neighbor_id = GNUNET_malloc(sizeof (struct GNUNET_PeerIdentity));
1298 memcpy(mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1299 mq->internal_msg = is_internal;
1300 mq->priority = priority;
1303 mqe = neighbor->messages;
1305 while (mqe->next != NULL)
1310 neighbor->messages = mq;
1317 return try_transmission_to_peer (neighbor);
1324 struct GeneratorContext
1326 struct TransportPlugin *plug_pos;
1327 struct AddressList *addr_pos;
1328 struct GNUNET_TIME_Absolute expiration;
1336 address_generator (void *cls, size_t max, void *buf)
1338 struct GeneratorContext *gc = cls;
1341 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1343 gc->plug_pos = gc->plug_pos->next;
1344 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1346 if (NULL == gc->plug_pos)
1351 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1354 gc->addr_pos->addrlen, buf, max);
1355 gc->addr_pos = gc->addr_pos->next;
1361 * Construct our HELLO message from all of the addresses of
1362 * all of the transports.
1367 struct GNUNET_HELLO_Message *hello;
1368 struct TransportClient *cpos;
1369 struct NeighborList *npos;
1370 struct GeneratorContext gc;
1372 gc.plug_pos = plugins;
1373 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1374 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1375 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1378 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1381 while (cpos != NULL)
1383 transmit_to_client (cpos,
1384 (const struct GNUNET_MessageHeader *) hello,
1389 GNUNET_free_non_null (our_hello);
1391 our_hello_version++;
1392 GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1394 while (npos != NULL)
1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1398 "Transmitting updated `%s' to neighbor `%4s'\n",
1399 "HELLO", GNUNET_i2s (&npos->id));
1400 #endif // FIXME: just testing
1401 //transmit_to_peer (NULL, NULL, 0,
1402 // (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1403 // GNUNET_YES, npos);
1410 * Task used to clean up expired addresses for a plugin.
1412 * @param cls closure
1416 expire_address_task (void *cls,
1417 const struct GNUNET_SCHEDULER_TaskContext *tc);
1421 * Update the list of addresses for this plugin,
1422 * expiring those that are past their expiration date.
1424 * @param plugin addresses of which plugin should be recomputed?
1425 * @param fresh set to GNUNET_YES if a new address was added
1426 * and we need to regenerate the HELLO even if nobody
1430 update_addresses (struct TransportPlugin *plugin, int fresh)
1432 struct GNUNET_TIME_Relative min_remaining;
1433 struct GNUNET_TIME_Relative remaining;
1434 struct GNUNET_TIME_Absolute now;
1435 struct AddressList *pos;
1436 struct AddressList *prev;
1437 struct AddressList *next;
1440 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1441 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1442 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1443 now = GNUNET_TIME_absolute_get ();
1444 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1445 expired = GNUNET_NO;
1447 pos = plugin->addresses;
1451 if (pos->expires.value < now.value)
1453 expired = GNUNET_YES;
1455 plugin->addresses = pos->next;
1457 prev->next = pos->next;
1462 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1463 if (remaining.value < min_remaining.value)
1464 min_remaining = remaining;
1470 if (expired || fresh)
1472 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1473 plugin->address_update_task
1474 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1476 &expire_address_task, plugin);
1482 * Task used to clean up expired addresses for a plugin.
1484 * @param cls closure
1488 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1490 struct TransportPlugin *plugin = cls;
1491 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1492 update_addresses (plugin, GNUNET_NO);
1497 * Function that must be called by each plugin to notify the
1498 * transport service about the addresses under which the transport
1499 * provided by the plugin can be reached.
1501 * @param cls closure
1502 * @param name name of the transport that generated the address
1503 * @param addr one of the addresses of the host, NULL for the last address
1504 * the specific address format depends on the transport
1505 * @param addrlen length of the address
1506 * @param expires when should this address automatically expire?
1509 plugin_env_notify_address (void *cls,
1513 struct GNUNET_TIME_Relative expires)
1515 struct TransportPlugin *p = cls;
1516 struct AddressList *al;
1517 struct GNUNET_TIME_Absolute abex;
1519 abex = GNUNET_TIME_relative_to_absolute (expires);
1520 GNUNET_assert (p == find_transport (name));
1525 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1527 if (al->expires.value < abex.value)
1534 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1536 al->next = p->addresses;
1539 al->addrlen = addrlen;
1540 memcpy (&al[1], addr, addrlen);
1541 update_addresses (p, GNUNET_YES);
1546 * Notify all of our clients about a peer connecting.
1549 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1550 struct GNUNET_TIME_Relative latency)
1552 struct ConnectInfoMessage cim;
1553 struct TransportClient *cpos;
1555 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1556 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1557 cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1558 cim.latency = GNUNET_TIME_relative_hton (latency);
1559 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1561 while (cpos != NULL)
1563 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1570 * Notify all of our clients about a peer disconnecting.
1573 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1575 struct DisconnectInfoMessage dim;
1576 struct TransportClient *cpos;
1578 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1579 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1580 dim.reserved = htonl (0);
1581 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1583 while (cpos != NULL)
1585 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1592 * Copy any validated addresses to buf.
1594 * @return 0 once all addresses have been
1598 list_validated_addresses (void *cls, size_t max, void *buf)
1600 struct ValidationAddress **va = cls;
1603 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1607 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1609 (*va)->peer_address->addr, (*va)->peer_address->addrlen, buf, max);
1616 * HELLO validation cleanup task.
1619 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1621 struct ValidationAddress *va;
1622 struct ValidationList *pos;
1623 struct ValidationList *prev;
1624 struct GNUNET_TIME_Absolute now;
1625 struct GNUNET_TIME_Absolute first;
1626 struct GNUNET_HELLO_Message *hello;
1627 struct GNUNET_PeerIdentity pid;
1628 struct NeighborList *n;
1630 now = GNUNET_TIME_absolute_get ();
1632 pos = pending_validations;
1635 if (pos->timeout.value < now.value)
1638 pending_validations = pos->next;
1640 prev->next = pos->next;
1641 va = pos->addresses;
1642 hello = GNUNET_HELLO_create (&pos->publicKey,
1643 &list_validated_addresses, &va);
1644 GNUNET_CRYPTO_hash (&pos->publicKey,
1646 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1650 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1651 "HELLO", GNUNET_i2s (&pid));
1653 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1654 n = find_neighbor (&pid);
1657 try_transmission_to_peer (n);
1659 GNUNET_free (hello);
1660 while (NULL != (va = pos->addresses))
1662 pos->addresses = va->next;
1663 GNUNET_free (va->transport_name);
1668 pos = pending_validations;
1677 /* finally, reschedule cleanup if needed; list is
1678 ordered by timeout, so we need the last element... */
1679 if (NULL != pending_validations)
1681 first = pending_validations->timeout;
1682 pos = pending_validations;
1685 first = GNUNET_TIME_absolute_min (first, pos->timeout);
1688 if (tc->reason != GNUNET_SCHEDULER_REASON_SHUTDOWN)
1690 GNUNET_SCHEDULER_add_delayed (sched,
1691 GNUNET_TIME_absolute_get_remaining
1692 (first), &cleanup_validation, NULL);
1699 * Function that will be called if we receive a validation
1700 * of an address challenge that we transmitted to another
1701 * peer. Note that the validation should only be considered
1702 * acceptable if the challenge matches AND if the sender
1703 * address is at least a plausible address for this peer
1704 * (otherwise we may be seeing a MiM attack).
1706 * @param cls closure
1707 * @param name name of the transport that generated the address
1708 * @param peer who responded to our challenge
1709 * @param challenge the challenge number we presumably used
1710 * @param sender_addr string describing our sender address (as observed
1711 * by the other peer in human-readable format)
1714 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1715 const struct GNUNET_PeerIdentity *peer,
1716 const char *sender_address,
1717 size_t sender_address_len)
1719 unsigned int not_done;
1721 struct ValidationList *pos;
1722 struct ValidationAddress *va;
1723 struct GNUNET_PeerIdentity id;
1724 const struct TransportPongMessage *pong = (const struct TransportPongMessage *)message;
1726 unsigned int challenge = ntohl(pong->challenge);
1727 pos = pending_validations;
1731 GNUNET_CRYPTO_hash (&pos->publicKey,
1733 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1735 if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1742 /* TODO: call statistics (unmatched PONG) */
1743 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1745 ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1746 GNUNET_i2s (peer), count);
1750 matched = GNUNET_NO;
1751 va = pos->addresses;
1754 if (va->challenge == challenge)
1757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1758 "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1760 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
1761 va->peer_address->addrlen));
1763 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1765 ("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
1766 GNUNET_a2s ((const struct sockaddr *) &pong[1],
1767 ntohs(pong->addrlen)), va->transport_name);
1768 va->ok = GNUNET_YES;
1770 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1771 matched = GNUNET_YES;
1772 va->peer_address->connected = GNUNET_YES;
1773 va->peer_address->latency = GNUNET_TIME_absolute_get_difference(va->send_time, GNUNET_TIME_absolute_get());
1775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1776 "Confirmed validity of address, peer `%4s' has address `%s', latency of %llu\n",
1778 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
1779 va->peer_address->addrlen), (unsigned long long)va->peer_address->latency.value);
1781 va->peer_address->transmit_ready = GNUNET_YES;
1782 va->peer_address->expires = GNUNET_TIME_relative_to_absolute
1783 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1785 if (va->ok != GNUNET_YES)
1789 if (GNUNET_NO == matched)
1791 /* TODO: call statistics (unmatched PONG) */
1792 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1794 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1801 "All addresses validated, will now construct `%s' for `%4s'.\n",
1802 "HELLO", GNUNET_i2s (peer));
1804 pos->timeout.value = 0;
1805 GNUNET_SCHEDULER_add_with_priority (sched,
1806 GNUNET_SCHEDULER_PRIORITY_IDLE,
1807 &cleanup_validation, NULL);
1813 * Add an entry for each of our transport plugins
1814 * (that are able to send) to the list of plugins
1815 * for this neighbor.
1817 * @param neighbor to initialize
1820 add_plugins (struct NeighborList *neighbor)
1822 struct TransportPlugin *tp;
1823 struct ReadyList *rl;
1825 neighbor->retry_plugins_time
1826 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1830 if (tp->api->send != NULL)
1832 rl = GNUNET_malloc (sizeof (struct ReadyList));
1833 rl->next = neighbor->plugins;
1834 neighbor->plugins = rl;
1836 rl->neighbor = neighbor;
1837 rl->addresses = NULL;
1844 neighbor_timeout_task (void *cls,
1845 const struct GNUNET_SCHEDULER_TaskContext *tc)
1847 struct NeighborList *n = cls;
1850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1851 "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1853 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1854 disconnect_neighbor (n, GNUNET_NO);
1858 * Create a fresh entry in our neighbor list for the given peer.
1859 * Will try to transmit our current HELLO to the new neighbor. Also
1860 * notifies our clients about the new "connection".
1862 * @param peer the peer for which we create the entry
1863 * @return the new neighbor list entry
1865 static struct NeighborList *
1866 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1868 struct NeighborList *n;
1870 GNUNET_assert (our_hello != NULL);
1871 n = GNUNET_malloc (sizeof (struct NeighborList));
1872 n->next = neighbors;
1875 n->last_quota_update = GNUNET_TIME_absolute_get ();
1877 GNUNET_TIME_relative_to_absolute
1878 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1879 n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1881 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1882 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1883 &neighbor_timeout_task, n);
1884 transmit_to_peer (NULL, NULL, 0,
1885 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1887 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1891 static struct PeerAddressList *
1892 add_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1894 /* FIXME: should return a list of PeerAddressLists, support for multiple transports! */
1895 struct ReadyList *head = neighbor->plugins;
1896 struct PeerAddressList * new_address;
1898 GNUNET_assert(addr != NULL);
1901 while (head != NULL)
1903 new_address = GNUNET_malloc(sizeof(struct PeerAddressList));
1904 new_address->addr = GNUNET_malloc(addrlen);
1905 memcpy(new_address->addr, addr, addrlen);
1906 new_address->addrlen = addrlen;
1907 new_address->connect_attempts = 0;
1908 new_address->connected = GNUNET_YES; /* Set connected to GNUNET_YES, assuming that we're good */
1909 new_address->expires = GNUNET_TIME_relative_to_absolute
1910 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1911 new_address->latency = GNUNET_TIME_relative_get_forever();
1912 new_address->neighbor = neighbor;
1913 new_address->plugin = head->plugin;
1914 new_address->transmit_ready = GNUNET_YES;
1915 new_address->timeout = GNUNET_TIME_relative_to_absolute
1916 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); /* FIXME: Do we need this? */
1917 new_address->ready_list = head;
1918 new_address->next = head->addresses;
1919 head->addresses = new_address;
1926 static struct PeerAddressList *
1927 find_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1929 struct ReadyList *head = neighbor->plugins;
1930 struct PeerAddressList *address_head;
1931 while (head != NULL)
1933 address_head = head->addresses;
1934 while ((address_head != NULL) &&
1935 (address_head->addrlen != addrlen) &&
1936 (memcmp(address_head->addr, addr, addrlen) != 0))
1938 address_head = address_head->next;
1940 if (address_head != NULL)
1941 return address_head;
1949 * Append the given address to the list of entries
1950 * that need to be validated.
1953 run_validation (void *cls,
1955 struct GNUNET_TIME_Absolute expiration,
1956 const void *addr, size_t addrlen)
1958 struct ValidationList *e = cls;
1959 struct TransportPlugin *tp;
1960 struct ValidationAddress *va;
1961 struct GNUNET_PeerIdentity id;
1962 struct NeighborList *neighbor;
1963 struct PeerAddressList *peer_address;
1965 struct TransportPingMessage *ping;
1970 tp = find_transport (tname);
1973 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1974 GNUNET_ERROR_TYPE_BULK,
1976 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1980 GNUNET_CRYPTO_hash (&e->publicKey,
1982 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1986 "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1987 GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1989 va = GNUNET_malloc (sizeof (struct ValidationAddress));
1990 va->next = e->addresses;
1992 va->transport_name = GNUNET_strdup (tname);
1993 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1995 va->send_time = GNUNET_TIME_absolute_get();
1997 neighbor = find_neighbor(&id);
1999 if (neighbor == NULL)
2000 neighbor = setup_new_neighbor(&id);
2002 peer_address = find_peer_address(neighbor, addr, addrlen);
2003 if (peer_address == NULL)
2005 peer_address = add_peer_address(neighbor, addr, addrlen);
2008 GNUNET_assert(peer_address != NULL);
2010 va->peer_address = peer_address; /* Back pointer FIXME: remove this nonsense! */
2011 peer_address->validation = va;
2013 hello_size = GNUNET_HELLO_size(our_hello);
2014 tsize = sizeof(struct TransportPingMessage) + hello_size;
2016 message_buf = GNUNET_malloc(tsize);
2018 ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
2019 ping->challenge = htonl(va->challenge);
2020 ping->header.size = htons(sizeof(struct TransportPingMessage));
2021 ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2022 memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
2025 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "hello size is %d, ping size is %d, total size is %d\n", hello_size, sizeof(struct TransportPingMessage), tsize);
2027 memcpy(message_buf, our_hello, hello_size);
2028 memcpy(&message_buf[hello_size], ping, sizeof(struct TransportPingMessage));
2031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message of size %d to address `%s' via `%s' for `%4s'\n",
2032 tsize, GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
2034 sent = transmit_to_peer(NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2035 message_buf, tsize, GNUNET_NO, neighbor);
2038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
2042 GNUNET_free(message_buf);
2048 * @param cls handle to the plugin (for sending)
2049 * @param target the peer identity of the peer we are sending to
2050 * @param challenge the challenge number
2051 * @param timeout how long to await validation?
2052 * @param addr the address to validate
2053 * @param addrlen the length of the address
2055 * Perform address validation, which means sending a PING PONG to
2056 * the address via the transport plugin. If not validated, then
2057 * do not count this as a good peer/address...
2059 * Currently this function is not used, ping/pongs get sent from the
2060 * run_validation function. Haven't decided yet how to do this.
2063 validate_address (void *cls, struct ValidationAddress *va,
2064 const struct GNUNET_PeerIdentity *target,
2065 struct GNUNET_TIME_Relative timeout,
2066 const void *addr, size_t addrlen)
2068 /* struct Plugin *plugin = cls;
2069 int challenge = va->challenge; */
2077 * Check if addresses in validated hello "h" overlap with
2078 * those in "chvc->hello" and update "chvc->hello" accordingly,
2079 * removing those addresses that have already been validated.
2082 check_hello_validated (void *cls,
2083 const struct GNUNET_PeerIdentity *peer,
2084 const struct GNUNET_HELLO_Message *h, uint32_t trust)
2086 struct CheckHelloValidatedContext *chvc = cls;
2087 struct ValidationAddress *va;
2088 struct TransportPlugin *tp;
2091 struct GNUNET_PeerIdentity apeer;
2093 first_call = GNUNET_NO;
2094 if (chvc->e == NULL)
2097 first_call = GNUNET_YES;
2098 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
2099 GNUNET_assert (GNUNET_OK ==
2100 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
2101 &chvc->e->publicKey));
2103 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
2104 chvc->e->next = pending_validations;
2105 pending_validations = chvc->e;
2110 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2112 GNUNET_TIME_absolute_get (),
2113 &run_validation, chvc->e);
2115 else if (GNUNET_YES == first_call)
2117 /* no existing HELLO, all addresses are new */
2118 GNUNET_HELLO_iterate_addresses (chvc->hello,
2119 GNUNET_NO, &run_validation, chvc->e);
2123 return; /* wait for next call */
2124 /* finally, transmit validation attempts */
2125 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
2127 va = chvc->e->addresses;
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2133 "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
2136 GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
2137 va->peer_address->addrlen), GNUNET_i2s (&apeer));
2139 tp = find_transport (va->transport_name);
2140 GNUNET_assert (tp != NULL);
2141 /* This validation should happen inside the transport, not from the plugin! */
2142 va->ok = GNUNET_SYSERR;
2147 GNUNET_SCHEDULER_add_delayed (sched,
2148 GNUNET_TIME_absolute_get_remaining (chvc->
2150 &cleanup_validation, NULL);
2156 * Process HELLO-message.
2158 * @param plugin transport involved, may be NULL
2159 * @param message the actual message
2160 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2163 process_hello (struct TransportPlugin *plugin,
2164 const struct GNUNET_MessageHeader *message)
2166 struct ValidationList *e;
2168 struct GNUNET_PeerIdentity target;
2169 const struct GNUNET_HELLO_Message *hello;
2170 struct CheckHelloValidatedContext *chvc;
2171 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2173 hsize = ntohs (message->size);
2174 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2175 (hsize < sizeof (struct GNUNET_MessageHeader)))
2178 return GNUNET_SYSERR;
2180 /* first, check if load is too high */
2181 if (GNUNET_OS_load_cpu_get (cfg) > 100)
2183 /* TODO: call to stats? */
2186 hello = (const struct GNUNET_HELLO_Message *) message;
2187 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2189 GNUNET_break_op (0);
2190 return GNUNET_SYSERR;
2192 GNUNET_CRYPTO_hash (&publicKey,
2193 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2194 &target.hashPubKey);
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2197 "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
2198 "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
2202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2203 "Notifying peerinfo about peer %s\n",
2204 GNUNET_i2s (&target));
2207 /* check if a HELLO for this peer is already on the validation list */
2208 e = pending_validations;
2211 if (0 == memcmp (&e->publicKey,
2214 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
2216 /* TODO: call to stats? */
2218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2219 "`%s' message for peer `%4s' is already pending; ignoring new message\n",
2220 "HELLO", GNUNET_i2s (&target));
2226 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2227 chvc->plugin = plugin;
2228 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
2230 memcpy (chvc->hello, hello, hsize);
2231 /* finally, check if HELLO was previously validated
2232 (continuation will then schedule actual validation) */
2233 chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2237 HELLO_VERIFICATION_TIMEOUT,
2238 &check_hello_validated, chvc);
2244 * The peer specified by the given neighbor has timed-out or a plugin
2245 * has disconnected. We may either need to do nothing (other plugins
2246 * still up), or trigger a full disconnect and clean up. This
2247 * function updates our state and does the necessary notifications.
2248 * Also notifies our clients that the neighbor is now officially
2251 * @param n the neighbor list entry for the peer
2252 * @param check should we just check if all plugins
2253 * disconnected or must we ask all plugins to
2257 disconnect_neighbor (struct NeighborList *current_handle, int check)
2259 struct ReadyList *rpos;
2260 struct NeighborList *npos;
2261 struct NeighborList *nprev;
2262 struct NeighborList *n;
2263 struct MessageQueue *mq;
2264 struct PeerAddressList *peer_addresses;
2265 struct PeerAddressList *peer_pos;
2267 if (neighbors == NULL)
2268 return; /* We don't have any neighbors, so client has an already removed handle! */
2271 while ((npos != NULL) && (current_handle != npos))
2275 return; /* Couldn't find neighbor in existing list, must have been already removed! */
2279 if (GNUNET_YES == check)
2282 while (NULL != rpos)
2284 peer_addresses = rpos->addresses;
2285 while (peer_addresses != NULL)
2287 if (GNUNET_YES == peer_addresses->connected)
2288 return; /* still connected */
2289 peer_addresses = peer_addresses->next;
2296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2297 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2299 /* remove n from neighbors list */
2302 while ((npos != NULL) && (npos != n))
2307 GNUNET_assert (npos != NULL);
2309 neighbors = n->next;
2311 nprev->next = n->next;
2313 /* notify all clients about disconnect */
2314 notify_clients_disconnect (&n->id);
2316 /* clean up all plugins, cancel connections and pending transmissions */
2317 while (NULL != (rpos = n->plugins))
2319 n->plugins = rpos->next;
2320 GNUNET_assert (rpos->neighbor == n);
2321 if (GNUNET_YES == rpos->connected)
2322 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2324 peer_pos = rpos->addresses;
2325 rpos->addresses = peer_pos->next;
2326 while (peer_pos != NULL)
2328 GNUNET_free(peer_pos->addr);
2329 GNUNET_free(peer_pos);
2330 peer_pos = rpos->addresses;
2331 rpos->addresses = peer_pos->next;
2336 /* free all messages on the queue */
2337 while (NULL != (mq = n->messages))
2339 n->messages = mq->next;
2340 GNUNET_assert (0 == memcmp(mq->neighbor_id, &n->id, sizeof(struct GNUNET_PeerIdentity)));
2341 GNUNET_free (mq->neighbor_id);
2344 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2345 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2346 /* finally, free n itself */
2352 * We have received a PING message from someone. Need to send a PONG message
2353 * in response to the peer by any means necessary. Of course, with something
2354 * like TCP where a connection exists, we may want to send it that way. But
2355 * we may not be able to make that distinction...
2357 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2358 const struct GNUNET_PeerIdentity *peer,
2359 const char *sender_address,
2360 size_t sender_address_len)
2362 struct TransportPlugin *plugin = cls;
2363 struct TransportPingMessage *ping;
2364 struct TransportPongMessage *pong;
2365 struct PeerAddressList *peer_address;
2367 struct NeighborList *n;
2370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2371 "Processing `%s' from `%s'\n",
2372 "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2375 msize = ntohs (message->size);
2376 if (msize < sizeof (struct TransportPingMessage))
2378 GNUNET_break_op (0);
2379 return GNUNET_SYSERR;
2381 ping = (struct TransportPingMessage *) message;
2382 if (0 != memcmp (&ping->target,
2383 plugin->env.my_identity,
2384 sizeof (struct GNUNET_PeerIdentity)))
2386 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2387 _("Received `%s' message not destined for me!\n"), "PING");
2388 return GNUNET_SYSERR;
2391 msize -= sizeof (struct TransportPingMessage);
2393 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2394 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2395 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2396 pong->purpose.size =
2397 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2399 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2400 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2401 pong->challenge = ping->challenge;
2402 pong->addrlen = htons(sender_address_len);
2404 memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2405 memcpy (&pong[1], sender_address, sender_address_len);
2406 GNUNET_assert (GNUNET_OK ==
2407 GNUNET_CRYPTO_rsa_sign (my_private_key,
2408 &pong->purpose, &pong->signature));
2410 n = find_neighbor(peer);
2412 n = setup_new_neighbor(peer);
2414 peer_address = find_peer_address(n, sender_address, sender_address_len);
2415 if (peer_address == NULL)
2416 peer_address = add_peer_address(n, sender_address, sender_address_len);
2418 peer_address->timeout = GNUNET_TIME_relative_to_absolute(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2420 /* We don't use the peer_address because the address we received the message from may not
2421 * be a reliable way to send it back! We add it to the list which should queue up a separate
2422 * ping to determine if the address is viable.
2424 transmit_to_peer(NULL, NULL, TRANSPORT_DEFAULT_PRIORITY, (char *)pong, ntohs(pong->header.size), GNUNET_NO, n);
2431 * Function called by the plugin for each received message.
2432 * Update data volumes, possibly notify plugins about
2433 * reducing the rate at which they read from the socket
2434 * and generally forward to our receive callback.
2436 * @param cls the "struct TransportPlugin *" we gave to the plugin
2437 * @param message the message, NULL if peer was disconnected
2438 * @param distance the transport cost to this peer (not latency!)
2439 * @param sender_address the address that the sender reported
2440 * (opaque to transport service)
2441 * @param sender_address_len the length of the sender address
2442 * @param peer (claimed) identity of the other peer
2443 * @return the new service_context that the plugin should use
2444 * for future receive calls for messages from this
2449 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2450 const struct GNUNET_MessageHeader *message,
2451 unsigned int distance, const char *sender_address,
2452 size_t sender_address_len)
2454 struct ReadyList *service_context;
2455 struct TransportPlugin *plugin = cls;
2456 struct TransportClient *cpos;
2457 struct InboundMessage *im;
2458 struct PeerAddressList *peer_address;
2460 struct NeighborList *n;
2462 n = find_neighbor (peer);
2465 if (message == NULL)
2466 return; /* disconnect of peer already marked down */
2467 n = setup_new_neighbor (peer);
2471 peer_address = find_peer_address(n, sender_address, sender_address_len);
2472 if (peer_address == NULL)
2473 peer_address = add_peer_address(n, sender_address, sender_address_len);
2475 service_context = n->plugins;
2476 while ((service_context != NULL) && (plugin != service_context->plugin))
2477 service_context = service_context->next;
2478 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2479 if (message == NULL)
2482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2483 "Receive failed from `%4s', triggering disconnect\n",
2484 GNUNET_i2s (&n->id));
2486 /* TODO: call stats */
2487 if (service_context != NULL)
2488 service_context->connected = GNUNET_NO;
2489 disconnect_neighbor (n, GNUNET_YES);
2493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2494 "Processing message of type `%u' received by plugin...\n",
2495 ntohs (message->type));
2497 if (service_context != NULL)
2499 if (service_context->connected == GNUNET_NO)
2501 /*service_context->connected = GNUNET_YES;*/
2502 /* FIXME: What to do here? Should we use these as well, to specify some Address
2503 * in the AddressList should be available?
2505 peer_address->transmit_ready = GNUNET_YES;
2506 peer_address->connect_attempts++;
2508 peer_address->timeout
2510 GNUNET_TIME_relative_to_absolute
2511 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2513 /* update traffic received amount ... */
2514 msize = ntohs (message->size);
2515 n->last_received += msize;
2516 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2518 GNUNET_TIME_relative_to_absolute
2519 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2521 GNUNET_SCHEDULER_add_delayed (sched,
2522 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2523 &neighbor_timeout_task, n);
2525 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2527 /* dropping message due to frequent inbound volume violations! */
2528 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2529 GNUNET_ERROR_TYPE_BULK,
2531 ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2532 /* TODO: call stats */
2533 GNUNET_assert ((service_context == NULL) ||
2534 (NULL != service_context->neighbor));
2538 switch (ntohs (message->type))
2540 case GNUNET_MESSAGE_TYPE_HELLO:
2542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2543 "Receiving `%s' message from `%4s'.\n", "HELLO",
2546 process_hello (plugin, message);
2548 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2551 "Receiving `%s' message from `%4s'.\n", "PING",
2554 handle_ping(plugin, message, peer, sender_address, sender_address_len);
2556 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2559 "Receiving `%s' message from `%4s'.\n", "PONG",
2562 handle_pong(plugin, message, peer, sender_address, sender_address_len);
2566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2567 "Received REAL MESSAGE type %u from `%4s', sending to all clients.\n",
2568 ntohs (message->type), GNUNET_i2s (peer));
2570 /* transmit message to all clients */
2571 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2572 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2573 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2574 im->latency = n->latency;
2576 memcpy (&im[1], message, msize);
2579 while (cpos != NULL)
2581 transmit_to_client (cpos, &im->header, GNUNET_YES);
2586 GNUNET_assert ((service_context == NULL) ||
2587 (NULL != service_context->neighbor));
2592 * Handle START-message. This is the first message sent to us
2593 * by any client which causes us to add it to our list.
2595 * @param cls closure (always NULL)
2596 * @param client identification of the client
2597 * @param message the actual message
2600 handle_start (void *cls,
2601 struct GNUNET_SERVER_Client *client,
2602 const struct GNUNET_MessageHeader *message)
2604 struct TransportClient *c;
2605 struct ConnectInfoMessage cim;
2606 struct NeighborList *n;
2607 struct InboundMessage *im;
2608 struct GNUNET_MessageHeader *ack;
2611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612 "Received `%s' request from client\n", "START");
2617 if (c->client == client)
2619 /* client already on our list! */
2621 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2626 c = GNUNET_malloc (sizeof (struct TransportClient));
2630 if (our_hello != NULL)
2633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2634 "Sending our own `%s' to new client\n", "HELLO");
2636 transmit_to_client (c,
2637 (const struct GNUNET_MessageHeader *) our_hello,
2639 /* tell new client about all existing connections */
2640 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2641 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2643 htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2644 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2645 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2646 sizeof (struct GNUNET_MessageHeader));
2647 im->header.size = htons (sizeof (struct InboundMessage) +
2648 sizeof (struct GNUNET_MessageHeader));
2649 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2650 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2651 ack = (struct GNUNET_MessageHeader *) &im[1];
2652 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2653 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2654 for (n = neighbors; n != NULL; n = n->next)
2657 transmit_to_client (c, &cim.header, GNUNET_NO);
2658 if (n->received_pong)
2661 transmit_to_client (c, &im->header, GNUNET_NO);
2668 fprintf(stderr, "Our hello is NULL!\n");
2670 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2675 * Handle HELLO-message.
2677 * @param cls closure (always NULL)
2678 * @param client identification of the client
2679 * @param message the actual message
2682 handle_hello (void *cls,
2683 struct GNUNET_SERVER_Client *client,
2684 const struct GNUNET_MessageHeader *message)
2689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2690 "Received `%s' request from client\n", "HELLO");
2692 ret = process_hello (NULL, message);
2693 GNUNET_SERVER_receive_done (client, ret);
2698 * Handle SEND-message.
2700 * @param cls closure (always NULL)
2701 * @param client identification of the client
2702 * @param message the actual message
2705 handle_send (void *cls,
2706 struct GNUNET_SERVER_Client *client,
2707 const struct GNUNET_MessageHeader *message)
2709 struct TransportClient *tc;
2710 struct NeighborList *n;
2711 const struct OutboundMessage *obm;
2712 const struct GNUNET_MessageHeader *obmm;
2716 size = ntohs (message->size);
2718 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2721 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2724 obm = (const struct OutboundMessage *) message;
2726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2727 "Received `%s' request from client with target `%4s'\n",
2728 "SEND", GNUNET_i2s (&obm->peer));
2730 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2731 msize = ntohs (obmm->size);
2732 if (size != msize + sizeof (struct OutboundMessage))
2735 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2738 n = find_neighbor (&obm->peer);
2740 n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2742 while ((tc != NULL) && (tc->client != client))
2746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2747 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2749 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2751 transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, ntohs (obmm->size), GNUNET_NO, n);
2752 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2757 * Handle SET_QUOTA-message.
2759 * @param cls closure (always NULL)
2760 * @param client identification of the client
2761 * @param message the actual message
2764 handle_set_quota (void *cls,
2765 struct GNUNET_SERVER_Client *client,
2766 const struct GNUNET_MessageHeader *message)
2768 const struct QuotaSetMessage *qsm =
2769 (const struct QuotaSetMessage *) message;
2770 struct NeighborList *n;
2771 struct TransportPlugin *p;
2772 struct ReadyList *rl;
2775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2776 "Received `%s' request from client for peer `%4s'\n",
2777 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2779 n = find_neighbor (&qsm->peer);
2782 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2786 if (n->quota_in < ntohl (qsm->quota_in))
2787 n->last_quota_update = GNUNET_TIME_absolute_get ();
2788 n->quota_in = ntohl (qsm->quota_in);
2793 p->api->set_receive_quota (p->api->cls,
2794 &qsm->peer, ntohl (qsm->quota_in));
2797 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2802 * Handle TRY_CONNECT-message.
2804 * @param cls closure (always NULL)
2805 * @param client identification of the client
2806 * @param message the actual message
2809 handle_try_connect (void *cls,
2810 struct GNUNET_SERVER_Client *client,
2811 const struct GNUNET_MessageHeader *message)
2813 const struct TryConnectMessage *tcm;
2814 struct NeighborList *neighbor;
2815 tcm = (const struct TryConnectMessage *) message;
2817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2818 "Received `%s' request from client %p asking to connect to `%4s'\n",
2819 "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2821 neighbor = find_neighbor(&tcm->peer);
2823 if (neighbor == NULL)
2824 setup_new_neighbor (&tcm->peer);
2828 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2829 "Client asked to connect to `%4s', but connection already exists\n",
2830 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2832 transmit_to_peer (NULL, NULL, 0,
2833 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2834 GNUNET_YES, neighbor);
2835 notify_clients_connect (&tcm->peer, GNUNET_TIME_UNIT_FOREVER_REL);
2837 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2841 transmit_address_to_client (void *cls, const char *address)
2843 struct GNUNET_SERVER_TransmitContext *tc = cls;
2846 if (NULL == address)
2849 slen = strlen (address) + 1;
2850 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2851 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2852 if (NULL == address)
2853 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2857 * Handle AddressLookup-message.
2859 * @param cls closure (always NULL)
2860 * @param client identification of the client
2861 * @param message the actual message
2864 handle_address_lookup (void *cls,
2865 struct GNUNET_SERVER_Client *client,
2866 const struct GNUNET_MessageHeader *message)
2868 const struct AddressLookupMessage *alum;
2869 struct TransportPlugin *lsPlugin;
2870 const char *nameTransport;
2871 const char *address;
2873 struct GNUNET_SERVER_TransmitContext *tc;
2875 size = ntohs (message->size);
2876 if (size < sizeof (struct AddressLookupMessage))
2878 GNUNET_break_op (0);
2879 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2882 alum = (const struct AddressLookupMessage *) message;
2883 uint32_t addressLen = ntohl (alum->addrlen);
2884 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2886 GNUNET_break_op (0);
2887 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2890 address = (const char *) &alum[1];
2891 nameTransport = (const char *) &address[addressLen];
2893 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2895 GNUNET_break_op (0);
2896 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2899 struct GNUNET_TIME_Absolute timeout =
2900 GNUNET_TIME_absolute_ntoh (alum->timeout);
2901 struct GNUNET_TIME_Relative rtimeout =
2902 GNUNET_TIME_absolute_get_remaining (timeout);
2903 lsPlugin = find_transport (nameTransport);
2904 if (NULL == lsPlugin)
2906 tc = GNUNET_SERVER_transmit_context_create (client);
2907 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2908 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2909 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2912 tc = GNUNET_SERVER_transmit_context_create (client);
2913 lsPlugin->api->address_pretty_printer (cls, nameTransport,
2914 address, addressLen, GNUNET_YES,
2916 &transmit_address_to_client, tc);
2920 * List of handlers for the messages understood by this
2923 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2924 {&handle_start, NULL,
2925 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2926 {&handle_hello, NULL,
2927 GNUNET_MESSAGE_TYPE_HELLO, 0},
2928 {&handle_send, NULL,
2929 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2930 {&handle_set_quota, NULL,
2931 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2932 {&handle_try_connect, NULL,
2933 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2934 sizeof (struct TryConnectMessage)},
2935 {&handle_address_lookup, NULL,
2936 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2943 * Setup the environment for this plugin.
2946 create_environment (struct TransportPlugin *plug)
2948 plug->env.cfg = cfg;
2949 plug->env.sched = sched;
2950 plug->env.my_identity = &my_identity;
2951 plug->env.cls = plug;
2952 plug->env.receive = &plugin_env_receive;
2953 plug->env.notify_address = &plugin_env_notify_address;
2954 plug->env.default_quota_in =
2955 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2956 plug->env.max_connections = max_connect_per_transport;
2961 * Start the specified transport (load the plugin).
2964 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2966 struct TransportPlugin *plug;
2969 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2970 _("Loading `%s' transport plugin\n"), name);
2971 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2972 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2973 create_environment (plug);
2974 plug->short_name = GNUNET_strdup (name);
2975 plug->lib_name = libname;
2976 plug->next = plugins;
2978 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2979 if (plug->api == NULL)
2981 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2982 _("Failed to load transport plugin for `%s'\n"), name);
2983 GNUNET_free (plug->short_name);
2984 plugins = plug->next;
2985 GNUNET_free (libname);
2992 * Called whenever a client is disconnected. Frees our
2993 * resources associated with that client.
2995 * @param cls closure
2996 * @param client identification of the client
2999 client_disconnect_notification (void *cls,
3000 struct GNUNET_SERVER_Client *client)
3002 struct TransportClient *pos;
3003 struct TransportClient *prev;
3004 struct ClientMessageQueueEntry *mqe;
3009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3010 "Client disconnected, cleaning up.\n");
3014 while ((pos != NULL) && (pos->client != client))
3021 while (NULL != (mqe = pos->message_queue_head))
3023 pos->message_queue_head = mqe->next;
3026 pos->message_queue_head = NULL;
3028 clients = pos->next;
3030 prev->next = pos->next;
3031 if (GNUNET_YES == pos->tcs_pending)
3041 * Function called when the service shuts down. Unloads our plugins.
3043 * @param cls closure, unused
3044 * @param tc task context (unused)
3047 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3049 struct TransportPlugin *plug;
3050 struct AddressList *al;
3053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054 "Transport service is unloading plugins...\n");
3056 while (NULL != (plug = plugins))
3058 plugins = plug->next;
3059 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3060 GNUNET_free (plug->lib_name);
3061 GNUNET_free (plug->short_name);
3062 while (NULL != (al = plug->addresses))
3064 plug->addresses = al->next;
3069 if (my_private_key != NULL)
3070 GNUNET_CRYPTO_rsa_key_free (my_private_key);
3071 GNUNET_free_non_null (our_hello);
3076 * Initiate transport service.
3078 * @param cls closure
3079 * @param s scheduler to use
3080 * @param serv the initialized server
3081 * @param c configuration to use
3085 struct GNUNET_SCHEDULER_Handle *s,
3086 struct GNUNET_SERVER_Handle *serv,
3087 const struct GNUNET_CONFIGURATION_Handle *c)
3092 unsigned long long tneigh;
3097 /* parse configuration */
3099 GNUNET_CONFIGURATION_get_value_number (c,
3104 GNUNET_CONFIGURATION_get_value_filename (c,
3106 "HOSTKEY", &keyfile)))
3108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3110 ("Transport service is lacking key configuration settings. Exiting.\n"));
3111 GNUNET_SCHEDULER_shutdown (s);
3114 max_connect_per_transport = (uint32_t) tneigh;
3115 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3116 GNUNET_free (keyfile);
3117 if (my_private_key == NULL)
3119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3121 ("Transport service could not access hostkey. Exiting.\n"));
3122 GNUNET_SCHEDULER_shutdown (s);
3125 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3126 GNUNET_CRYPTO_hash (&my_public_key,
3127 sizeof (my_public_key), &my_identity.hashPubKey);
3128 /* setup notification */
3130 GNUNET_SERVER_disconnect_notify (server,
3131 &client_disconnect_notification, NULL);
3132 /* load plugins... */
3135 GNUNET_CONFIGURATION_get_value_string (c,
3136 "TRANSPORT", "PLUGINS", &plugs))
3138 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3139 _("Starting transport plugins `%s'\n"), plugs);
3140 pos = strtok (plugs, " ");
3143 start_transport (server, pos);
3145 pos = strtok (NULL, " ");
3147 GNUNET_free (plugs);
3149 GNUNET_SCHEDULER_add_delayed (sched,
3150 GNUNET_TIME_UNIT_FOREVER_REL,
3151 &unload_plugins, NULL);
3156 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3158 /* process client requests */
3159 GNUNET_SERVER_add_handlers (server, handlers);
3164 * The main function for the transport service.
3166 * @param argc number of arguments from the command line
3167 * @param argv command line arguments
3168 * @return 0 ok, 1 on error
3171 main (int argc, char *const *argv)
3173 return (GNUNET_OK ==
3174 GNUNET_SERVICE_run (argc,
3177 GNUNET_SERVICE_OPTION_NONE,
3178 &run, NULL)) ? 0 : 1;
3181 /* end of gnunet-service-transport.c */