aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/gnunet-service-transport.c')
-rw-r--r--src/transport/gnunet-service-transport.c2852
1 files changed, 2852 insertions, 0 deletions
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
new file mode 100644
index 000000000..08745c378
--- /dev/null
+++ b/src/transport/gnunet-service-transport.c
@@ -0,0 +1,2852 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20
21/**
22 * @file transport/gnunet-service-transport.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - if we do not receive an ACK in response to our
28 * HELLO, retransmit HELLO!
29 */
30#include "platform.h"
31#include "gnunet_client_lib.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"
42
43/**
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.
48 *
49 * The expectation here is that most of the time the queue is large
50 * enough so that a drop is virtually never required.
51 */
52#define MAX_PENDING 128
53
54/**
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.
58 */
59#define MAX_CONNECT_RETRY 3
60
61/**
62 * How often must a peer violate bandwidth quotas before we start
63 * to simply drop its messages?
64 */
65#define QUOTA_VIOLATION_DROP_THRESHOLD 100
66
67/**
68 * How long until a HELLO verification attempt should time out?
69 */
70#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
71
72/**
73 * How often do we re-add (cheaper) plugins to our list of plugins
74 * to try for a given connected peer?
75 */
76#define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
77
78/**
79 * After how long do we expire an address in a HELLO
80 * that we just validated? This value is also used
81 * for our own addresses when we create a HELLO.
82 */
83#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
84
85/**
86 * After how long do we consider a connection to a peer dead
87 * if we don't receive messages from the peer?
88 */
89#define IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
90
91
92/**
93 * Entry in linked list of network addresses.
94 */
95struct AddressList
96{
97 /**
98 * This is a linked list.
99 */
100 struct AddressList *next;
101
102 /**
103 * The address, actually a pointer to the end
104 * of this struct. Do not free!
105 */
106 void *addr;
107
108 /**
109 * How long until we auto-expire this address (unless it is
110 * re-confirmed by the transport)?
111 */
112 struct GNUNET_TIME_Absolute expires;
113
114 /**
115 * Length of addr.
116 */
117 size_t addrlen;
118
119};
120
121
122/**
123 * Entry in linked list of all of our plugins.
124 */
125struct TransportPlugin
126{
127
128 /**
129 * This is a linked list.
130 */
131 struct TransportPlugin *next;
132
133 /**
134 * API of the transport as returned by the plugin's
135 * initialization function.
136 */
137 struct GNUNET_TRANSPORT_PluginFunctions *api;
138
139 /**
140 * Short name for the plugin (i.e. "tcp").
141 */
142 char *short_name;
143
144 /**
145 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
146 */
147 char *lib_name;
148
149 /**
150 * List of our known addresses for this transport.
151 */
152 struct AddressList *addresses;
153
154 /**
155 * Environment this transport service is using
156 * for this plugin.
157 */
158 struct GNUNET_TRANSPORT_PluginEnvironment env;
159
160 /**
161 * ID of task that is used to clean up expired addresses.
162 */
163 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
164
165
166 /**
167 * Set to GNUNET_YES if we need to scrap the existing
168 * list of "addresses" and start fresh when we receive
169 * the next address update from a transport. Set to
170 * GNUNET_NO if we should just add the new address
171 * to the list and wait for the commit call.
172 */
173 int rebuild;
174};
175
176struct NeighbourList;
177
178/**
179 * For each neighbour we keep a list of messages
180 * that we still want to transmit to the neighbour.
181 */
182struct MessageQueue
183{
184
185 /**
186 * This is a linked list.
187 */
188 struct MessageQueue *next;
189
190 /**
191 * The message we want to transmit.
192 */
193 struct GNUNET_MessageHeader *message;
194
195 /**
196 * Client responsible for queueing the message;
197 * used to check that a client has not two messages
198 * pending for the same target. Can be NULL.
199 */
200 struct TransportClient *client;
201
202 /**
203 * Neighbour this entry belongs to.
204 */
205 struct NeighbourList *neighbour;
206
207 /**
208 * Plugin that we used for the transmission.
209 * NULL until we scheduled a transmission.
210 */
211 struct TransportPlugin *plugin;
212
213 /**
214 * Internal message of the transport system that should not be
215 * included in the usual SEND-SEND_OK transmission confirmation
216 * traffic management scheme. Typically, "internal_msg" will
217 * be set whenever "client" is NULL (but it is not strictly
218 * required).
219 */
220 int internal_msg;
221
222};
223
224
225/**
226 * For a given Neighbour, which plugins are available
227 * to talk to this peer and what are their costs?
228 */
229struct ReadyList
230{
231
232 /**
233 * This is a linked list.
234 */
235 struct ReadyList *next;
236
237 /**
238 * Which of our transport plugins does this entry
239 * represent?
240 */
241 struct TransportPlugin *plugin;
242
243 /**
244 * Neighbour this entry belongs to.
245 */
246 struct NeighbourList *neighbour;
247
248 /**
249 * Opaque handle (specific to the plugin) for the
250 * connection to our target; can be NULL.
251 */
252 void *plugin_handle;
253
254 /**
255 * What was the last latency observed for this plugin
256 * and peer? Invalid if connected is GNUNET_NO.
257 */
258 struct GNUNET_TIME_Relative latency;
259
260 /**
261 * If we did not successfully transmit a message to the
262 * given peer via this connection during the specified
263 * time, we should consider the connection to be dead.
264 * This is used in the case that a TCP transport simply
265 * stalls writing to the stream but does not formerly
266 * get a signal that the other peer died.
267 */
268 struct GNUNET_TIME_Absolute timeout;
269
270 /**
271 * Is this plugin currently connected? The first time
272 * we transmit or send data to a peer via a particular
273 * plugin, we set this to GNUNET_YES. If we later get
274 * an error (disconnect notification or transmission
275 * failure), we set it back to GNUNET_NO. Each time the
276 * value is set to GNUNET_YES, we increment the
277 * "connect_attempts" counter. If that one reaches a
278 * particular threshold, we consider the plugin to not
279 * be working properly at this time for the given peer
280 * and remove it from the eligible list.
281 */
282 int connected;
283
284 /**
285 * How often have we tried to connect using this plugin?
286 */
287 unsigned int connect_attempts;
288
289 /**
290 * Is this plugin ready to transmit to the specific
291 * target? GNUNET_NO if not. Initially, all plugins
292 * are marked ready. If a transmission is in progress,
293 * "transmit_ready" is set to GNUNET_NO.
294 */
295 int transmit_ready;
296
297};
298
299
300/**
301 * Entry in linked list of all of our current neighbours.
302 */
303struct NeighbourList
304{
305
306 /**
307 * This is a linked list.
308 */
309 struct NeighbourList *next;
310
311 /**
312 * Which of our transports is connected to this peer
313 * and what is their status?
314 */
315 struct ReadyList *plugins;
316
317 /**
318 * List of messages we would like to send to this peer;
319 * must contain at most one message per client.
320 */
321 struct MessageQueue *messages;
322
323 /**
324 * Identity of this neighbour.
325 */
326 struct GNUNET_PeerIdentity id;
327
328 /**
329 * ID of task scheduled to run when this peer is about to
330 * time out (will free resources associated with the peer).
331 */
332 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
333
334 /**
335 * How long until we should consider this peer dead
336 * (if we don't receive another message in the
337 * meantime)?
338 */
339 struct GNUNET_TIME_Absolute peer_timeout;
340
341 /**
342 * At what time did we reset last_received last?
343 */
344 struct GNUNET_TIME_Absolute last_quota_update;
345
346 /**
347 * At what time should we try to again add plugins to
348 * our ready list?
349 */
350 struct GNUNET_TIME_Absolute retry_plugins_time;
351
352 /**
353 * How many bytes have we received since the "last_quota_update"
354 * timestamp?
355 */
356 uint64_t last_received;
357
358 /**
359 * Global quota for outbound traffic for the neighbour in bytes/ms.
360 */
361 uint32_t quota_in;
362
363 /**
364 * What is the latest version of our HELLO that we have
365 * sent to this neighbour?
366 */
367 unsigned int hello_version_sent;
368
369 /**
370 * How often has the other peer (recently) violated the
371 * inbound traffic limit? Incremented by 10 per violation,
372 * decremented by 1 per non-violation (for each
373 * time interval).
374 */
375 unsigned int quota_violation_count;
376
377 /**
378 * Have we seen an ACK from this neighbour in the past?
379 * (used to make up a fake ACK for clients connecting after
380 * the neighbour connected to us).
381 */
382 int saw_ack;
383
384};
385
386
387/**
388 * Linked list of messages to be transmitted to
389 * the client. Each entry is followed by the
390 * actual message.
391 */
392struct ClientMessageQueueEntry
393{
394 /**
395 * This is a linked list.
396 */
397 struct ClientMessageQueueEntry *next;
398};
399
400
401/**
402 * Client connected to the transport service.
403 */
404struct TransportClient
405{
406
407 /**
408 * This is a linked list.
409 */
410 struct TransportClient *next;
411
412 /**
413 * Handle to the client.
414 */
415 struct GNUNET_SERVER_Client *client;
416
417 /**
418 * Linked list of messages yet to be transmitted to
419 * the client.
420 */
421 struct ClientMessageQueueEntry *message_queue_head;
422
423 /**
424 * Tail of linked list of messages yet to be transmitted to the
425 * client.
426 */
427 struct ClientMessageQueueEntry *message_queue_tail;
428
429 /**
430 * Is a call to "transmit_send_continuation" pending? If so, we
431 * must not free this struct (even if the corresponding client
432 * disconnects) and instead only remove it from the linked list and
433 * set the "client" field to NULL.
434 */
435 int tcs_pending;
436
437 /**
438 * Length of the list of messages pending for this client.
439 */
440 unsigned int message_count;
441
442};
443
444
445/**
446 * Message used to ask a peer to validate receipt (to check an address
447 * from a HELLO). Followed by the address used. Note that the
448 * recipients response does not affirm that he has this address,
449 * only that he got the challenge message.
450 */
451struct ValidationChallengeMessage
452{
453
454 /**
455 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
456 */
457 struct GNUNET_MessageHeader header;
458
459 /**
460 * What are we signing and why?
461 */
462 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
463
464 /**
465 * Random challenge number (in network byte order).
466 */
467 uint32_t challenge GNUNET_PACKED;
468
469 /**
470 * Who is the intended recipient?
471 */
472 struct GNUNET_PeerIdentity target;
473};
474
475
476/**
477 * Message used to validate a HELLO. If this was
478 * the right recipient, the response is a signature
479 * of the original validation request. The
480 * challenge is included in the confirmation to make
481 * matching of replies to requests possible.
482 */
483struct ValidationChallengeResponse
484{
485
486 /**
487 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
488 */
489 struct GNUNET_MessageHeader header;
490
491 /**
492 * Random challenge number (in network byte order).
493 */
494 uint32_t challenge GNUNET_PACKED;
495
496 /**
497 * Who signed this message?
498 */
499 struct GNUNET_PeerIdentity sender;
500
501 /**
502 * Signature.
503 */
504 struct GNUNET_CRYPTO_RsaSignature signature;
505
506};
507
508
509/**
510 * For each HELLO, we may have to validate multiple addresses;
511 * each address gets its own request entry.
512 */
513struct ValidationAddress
514{
515 /**
516 * This is a linked list.
517 */
518 struct ValidationAddress *next;
519
520 /**
521 * Our challenge message. Points to after this
522 * struct, so this field should not be freed.
523 */
524 struct ValidationChallengeMessage *msg;
525
526 /**
527 * Name of the transport.
528 */
529 char *transport_name;
530
531 /**
532 * When should this validated address expire?
533 */
534 struct GNUNET_TIME_Absolute expiration;
535
536 /**
537 * Length of the address we are validating.
538 */
539 size_t addr_len;
540
541 /**
542 * Set to GNUNET_YES if the challenge was met,
543 * GNUNET_SYSERR if we know it failed, GNUNET_NO
544 * if we are waiting on a response.
545 */
546 int ok;
547};
548
549
550/**
551 * Entry in linked list of all HELLOs awaiting validation.
552 */
553struct ValidationList
554{
555
556 /**
557 * This is a linked list.
558 */
559 struct ValidationList *next;
560
561 /**
562 * Linked list with one entry per address from the HELLO
563 * that needs to be validated.
564 */
565 struct ValidationAddress *addresses;
566
567 /**
568 * The public key of the peer.
569 */
570 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
571
572 /**
573 * When does this record time-out? (assuming the
574 * challenge goes unanswered)
575 */
576 struct GNUNET_TIME_Absolute timeout;
577
578};
579
580
581/**
582 * HELLOs awaiting validation.
583 */
584static struct ValidationList *pending_validations;
585
586/**
587 * Our HELLO message.
588 */
589static struct GNUNET_HELLO_Message *our_hello;
590
591/**
592 * "version" of "our_hello". Used to see if a given
593 * neighbour has already been sent the latest version
594 * of our HELLO message.
595 */
596static unsigned int our_hello_version;
597
598/**
599 * Our public key.
600 */
601static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
602
603/**
604 * Our identity.
605 */
606static struct GNUNET_PeerIdentity my_identity;
607
608/**
609 * Our private key.
610 */
611static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
612
613/**
614 * Our scheduler.
615 */
616struct GNUNET_SCHEDULER_Handle *sched;
617
618/**
619 * Our configuration.
620 */
621struct GNUNET_CONFIGURATION_Handle *cfg;
622
623/**
624 * Linked list of all clients to this service.
625 */
626static struct TransportClient *clients;
627
628/**
629 * All loaded plugins.
630 */
631static struct TransportPlugin *plugins;
632
633/**
634 * Our server.
635 */
636static struct GNUNET_SERVER_Handle *server;
637
638/**
639 * All known neighbours and their HELLOs.
640 */
641static struct NeighbourList *neighbours;
642
643/**
644 * Default bandwidth quota for receiving for new peers in bytes/ms.
645 */
646static uint32_t default_quota_in;
647
648/**
649 * Default bandwidth quota for sending for new peers in bytes/ms.
650 */
651static uint32_t default_quota_out;
652
653/**
654 * Number of neighbours we'd like to have.
655 */
656static uint32_t max_connect_per_transport;
657
658
659/**
660 * Find an entry in the neighbour list for a particular peer.
661 *
662 * @return NULL if not found.
663 */
664static struct NeighbourList *
665find_neighbour (const struct GNUNET_PeerIdentity *key)
666{
667 struct NeighbourList *head = neighbours;
668 while ((head != NULL) &&
669 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
670 head = head->next;
671 return head;
672}
673
674
675/**
676 * Find an entry in the transport list for a particular transport.
677 *
678 * @return NULL if not found.
679 */
680static struct TransportPlugin *
681find_transport (const char *short_name)
682{
683 struct TransportPlugin *head = plugins;
684 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
685 head = head->next;
686 return head;
687}
688
689
690/**
691 * Update the quota values for the given neighbour now.
692 */
693static void
694update_quota (struct NeighbourList *n)
695{
696 struct GNUNET_TIME_Relative delta;
697 uint64_t allowed;
698 uint64_t remaining;
699
700 delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
701 if (delta.value < MIN_QUOTA_REFRESH_TIME)
702 return; /* not enough time passed for doing quota update */
703 allowed = delta.value * n->quota_in;
704 if (n->last_received < allowed)
705 {
706 remaining = allowed - n->last_received;
707 if (n->quota_in > 0)
708 remaining /= n->quota_in;
709 else
710 remaining = 0;
711 if (remaining > MAX_BANDWIDTH_CARRY)
712 remaining = MAX_BANDWIDTH_CARRY;
713 n->last_received = 0;
714 n->last_quota_update = GNUNET_TIME_absolute_get ();
715 n->last_quota_update.value -= remaining;
716 if (n->quota_violation_count > 0)
717 n->quota_violation_count--;
718 }
719 else
720 {
721 n->last_received -= allowed;
722 n->last_quota_update = GNUNET_TIME_absolute_get ();
723 if (n->last_received > allowed)
724 {
725 /* more than twice the allowed rate! */
726 n->quota_violation_count += 10;
727 }
728 }
729}
730
731
732/**
733 * Function called to notify a client about the socket
734 * being ready to queue more data. "buf" will be
735 * NULL and "size" zero if the socket was closed for
736 * writing in the meantime.
737 *
738 * @param cls closure
739 * @param size number of bytes available in buf
740 * @param buf where the callee should write the message
741 * @return number of bytes written to buf
742 */
743static size_t
744transmit_to_client_callback (void *cls, size_t size, void *buf)
745{
746 struct TransportClient *client = cls;
747 struct ClientMessageQueueEntry *q;
748 uint16_t msize;
749 size_t tsize;
750 const struct GNUNET_MessageHeader *msg;
751 struct GNUNET_NETWORK_TransmitHandle *th;
752 char *cbuf;
753
754 if (buf == NULL)
755 {
756 /* fatal error with client, free message queue! */
757 while (NULL != (q = client->message_queue_head))
758 {
759 client->message_queue_head = q->next;
760 GNUNET_free (q);
761 }
762 client->message_queue_tail = NULL;
763 client->message_count = 0;
764 return 0;
765 }
766 cbuf = buf;
767 tsize = 0;
768 while (NULL != (q = client->message_queue_head))
769 {
770 msg = (const struct GNUNET_MessageHeader *) &q[1];
771 msize = ntohs (msg->size);
772 if (msize + tsize > size)
773 break;
774 client->message_queue_head = q->next;
775 if (q->next == NULL)
776 client->message_queue_tail = NULL;
777 memcpy (&cbuf[tsize], msg, msize);
778 tsize += msize;
779 GNUNET_free (q);
780 client->message_count--;
781 }
782 GNUNET_assert (tsize > 0);
783 if (NULL != q)
784 {
785 th = GNUNET_SERVER_notify_transmit_ready (client->client,
786 msize,
787 GNUNET_TIME_UNIT_FOREVER_REL,
788 &transmit_to_client_callback,
789 client);
790 GNUNET_assert (th != NULL);
791 }
792 return tsize;
793}
794
795
796/**
797 * Send the specified message to the specified client. Since multiple
798 * messages may be pending for the same client at a time, this code
799 * makes sure that no message is lost.
800 *
801 * @param client client to transmit the message to
802 * @param msg the message to send
803 * @param may_drop can this message be dropped if the
804 * message queue for this client is getting far too large?
805 */
806static void
807transmit_to_client (struct TransportClient *client,
808 const struct GNUNET_MessageHeader *msg, int may_drop)
809{
810 struct ClientMessageQueueEntry *q;
811 uint16_t msize;
812 struct GNUNET_NETWORK_TransmitHandle *th;
813
814 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
815 {
816 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
817 _
818 ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
819 client->message_count, MAX_PENDING);
820 /* TODO: call to statistics... */
821 return;
822 }
823 client->message_count++;
824 msize = ntohs (msg->size);
825 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
826 memcpy (&q[1], msg, msize);
827 /* append to message queue */
828 if (client->message_queue_tail == NULL)
829 {
830 client->message_queue_tail = q;
831 }
832 else
833 {
834 client->message_queue_tail->next = q;
835 client->message_queue_tail = q;
836 }
837 if (client->message_queue_head == NULL)
838 {
839 client->message_queue_head = q;
840 th = GNUNET_SERVER_notify_transmit_ready (client->client,
841 msize,
842 GNUNET_TIME_UNIT_FOREVER_REL,
843 &transmit_to_client_callback,
844 client);
845 GNUNET_assert (th != NULL);
846 }
847}
848
849
850/**
851 * Find alternative plugins for communication.
852 *
853 * @param neighbour for which neighbour should we try to find
854 * more plugins?
855 */
856static void
857try_alternative_plugins (struct NeighbourList *neighbour)
858{
859 struct ReadyList *rl;
860
861 if ((neighbour->plugins != NULL) &&
862 (neighbour->retry_plugins_time.value >
863 GNUNET_TIME_absolute_get ().value))
864 return; /* don't try right now */
865 neighbour->retry_plugins_time
866 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
867
868 rl = neighbour->plugins;
869 while (rl != NULL)
870 {
871 if (rl->connect_attempts > 0)
872 rl->connect_attempts--; /* amnesty */
873 rl = rl->next;
874 }
875
876}
877
878
879/**
880 * Check the ready list for the given neighbour and
881 * if a plugin is ready for transmission (and if we
882 * have a message), do so!
883 *
884 * @param neighbour target peer for which to check the plugins
885 */
886static void try_transmission_to_peer (struct NeighbourList *neighbour);
887
888
889/**
890 * Function called by the GNUNET_TRANSPORT_TransmitFunction
891 * upon "completion" of a send request. This tells the API
892 * that it is now legal to send another message to the given
893 * peer.
894 *
895 * @param cls closure, identifies the entry on the
896 * message queue that was transmitted and the
897 * client responsible for queueing the message
898 * @param rl identifies plugin used for the transmission for
899 * this neighbour; needs to be re-enabled for
900 * future transmissions
901 * @param target the peer receiving the message
902 * @param result GNUNET_OK on success, if the transmission
903 * failed, we should not tell the client to transmit
904 * more messages
905 */
906static void
907transmit_send_continuation (void *cls,
908 struct ReadyList *rl,
909 const struct GNUNET_PeerIdentity *target,
910 int result)
911{
912 struct MessageQueue *mq = cls;
913 struct SendOkMessage send_ok_msg;
914 struct NeighbourList *n;
915
916 GNUNET_assert (mq != NULL);
917 n = mq->neighbour;
918 GNUNET_assert (0 ==
919 memcmp (&n->id, target,
920 sizeof (struct GNUNET_PeerIdentity)));
921 if (rl == NULL)
922 {
923 rl = n->plugins;
924 while ((rl != NULL) && (rl->plugin != mq->plugin))
925 rl = rl->next;
926 GNUNET_assert (rl != NULL);
927 }
928 if (result == GNUNET_OK)
929 rl->timeout = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
930 else
931 rl->connected = GNUNET_NO;
932 if (!mq->internal_msg)
933 rl->transmit_ready = GNUNET_YES;
934 if (mq->client != NULL)
935 {
936 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
937 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
938 send_ok_msg.success = htonl (result);
939 send_ok_msg.peer = n->id;
940 transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
941 }
942 GNUNET_free (mq->message);
943 GNUNET_free (mq);
944 /* one plugin just became ready again, try transmitting
945 another message (if available) */
946 try_transmission_to_peer (n);
947}
948
949
950
951
952/**
953 * We could not use an existing (or validated) connection to
954 * talk to a peer. Try addresses that have not yet been
955 * validated.
956 *
957 * @param n neighbour we want to communicate with
958 * @return plugin ready to talk, or NULL if none is available
959 */
960static struct ReadyList *
961try_unvalidated_addresses (struct NeighbourList *n)
962{
963 struct ValidationList *vl;
964 struct ValidationAddress *va;
965 struct GNUNET_PeerIdentity id;
966 struct GNUNET_TIME_Absolute now;
967 unsigned int total;
968 unsigned int cnt;
969 struct ReadyList *rl;
970 struct TransportPlugin *plugin;
971
972#if DEBUG_TRANSPORT
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 "Trying to connect to `%4s' using unvalidated addresses\n",
975 GNUNET_i2s (&n->id));
976#endif
977 /* NOTE: this function needs to not only identify the
978 plugin but also setup "plugin_handle", binding it to the
979 right address using the plugin's "send_to" API */
980 now = GNUNET_TIME_absolute_get ();
981 vl = pending_validations;
982 while (vl != NULL)
983 {
984 GNUNET_CRYPTO_hash (&vl->publicKey,
985 sizeof (struct
986 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
987 &id.hashPubKey);
988 if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
989 break;
990 vl = vl->next;
991 }
992 if (vl == NULL)
993 {
994#if DEBUG_TRANSPORT
995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996 "No unvalidated address found for peer `%4s'\n",
997 GNUNET_i2s (&n->id));
998#endif
999 return NULL;
1000 }
1001 total = 0;
1002 cnt = 0;
1003 va = vl->addresses;
1004 while (va != NULL)
1005 {
1006 cnt++;
1007 if (va->expiration.value > now.value)
1008 total++;
1009 va = va->next;
1010 }
1011 if (total == 0)
1012 {
1013#if DEBUG_TRANSPORT
1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015 "All %u unvalidated addresses for peer have expired\n",
1016 cnt);
1017#endif
1018 return NULL;
1019 }
1020 total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
1021 for (va = vl->addresses; va != NULL; va = va->next)
1022 {
1023 if (va->expiration.value <= now.value)
1024 continue;
1025 if (total > 0)
1026 {
1027 total--;
1028 continue;
1029 }
1030#if DEBUG_TRANSPORT
1031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1032 "Trying unvalidated address of `%s' transport\n",
1033 va->transport_name);
1034#endif
1035 plugin = find_transport (va->transport_name);
1036 if (plugin == NULL)
1037 {
1038 GNUNET_break (0);
1039 break;
1040 }
1041 rl = GNUNET_malloc (sizeof (struct ReadyList));
1042 rl->next = n->plugins;
1043 n->plugins = rl;
1044 rl->plugin = plugin;
1045 rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
1046 &n->id,
1047 NULL,
1048 NULL,
1049 GNUNET_TIME_UNIT_ZERO,
1050 &va->msg[1], va->addr_len);
1051 rl->transmit_ready = GNUNET_YES;
1052 return rl;
1053 }
1054 return NULL;
1055}
1056
1057
1058/**
1059 * Check the ready list for the given neighbour and
1060 * if a plugin is ready for transmission (and if we
1061 * have a message), do so!
1062 */
1063static void
1064try_transmission_to_peer (struct NeighbourList *neighbour)
1065{
1066 struct ReadyList *pos;
1067 struct GNUNET_TIME_Relative min_latency;
1068 struct ReadyList *rl;
1069 struct MessageQueue *mq;
1070 struct GNUNET_TIME_Absolute now;
1071
1072 if (neighbour->messages == NULL)
1073 return; /* nothing to do */
1074 try_alternative_plugins (neighbour);
1075 min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1076 rl = NULL;
1077 mq = neighbour->messages;
1078 now = GNUNET_TIME_absolute_get ();
1079 pos = neighbour->plugins;
1080 while (pos != NULL)
1081 {
1082 /* set plugins that are inactive for a long time back to disconnected */
1083 if ((pos->timeout.value < now.value) && (pos->connected == GNUNET_YES))
1084 {
1085#if DEBUG_TRANSPORT
1086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1087 "Marking long-time inactive connection to `%4s' as down.\n",
1088 GNUNET_i2s (&neighbour->id));
1089#endif
1090 pos->connected = GNUNET_NO;
1091 }
1092 if (((GNUNET_YES == pos->transmit_ready) ||
1093 (mq->internal_msg)) &&
1094 (pos->connect_attempts < MAX_CONNECT_RETRY) &&
1095 ((rl == NULL) || (min_latency.value > pos->latency.value)))
1096 {
1097 rl = pos;
1098 min_latency = pos->latency;
1099 }
1100 pos = pos->next;
1101 }
1102 if (rl == NULL)
1103 rl = try_unvalidated_addresses (neighbour);
1104 if (rl == NULL)
1105 {
1106#if DEBUG_TRANSPORT
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "No plugin ready to transmit message\n");
1109#endif
1110 return; /* nobody ready */
1111 }
1112 if (GNUNET_NO == rl->connected)
1113 {
1114 rl->connect_attempts++;
1115 rl->connected = GNUNET_YES;
1116 }
1117 neighbour->messages = mq->next;
1118 mq->plugin = rl->plugin;
1119 if (!mq->internal_msg)
1120 rl->transmit_ready = GNUNET_NO;
1121#if DEBUG_TRANSPORT
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1124 ntohs (mq->message->type),
1125 GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
1126#endif
1127 rl->plugin_handle
1128 = rl->plugin->api->send (rl->plugin->api->cls,
1129 rl->plugin_handle,
1130 rl,
1131 &neighbour->id,
1132 mq->message,
1133 IDLE_CONNECTION_TIMEOUT,
1134 &transmit_send_continuation, mq);
1135}
1136
1137
1138/**
1139 * Send the specified message to the specified peer.
1140 *
1141 * @param client source of the transmission request (can be NULL)
1142 * @param msg message to send
1143 * @param is_internal is this an internal message
1144 * @param neighbour handle to the neighbour for transmission
1145 */
1146static void
1147transmit_to_peer (struct TransportClient *client,
1148 const struct GNUNET_MessageHeader *msg,
1149 int is_internal, struct NeighbourList *neighbour)
1150{
1151 struct MessageQueue *mq;
1152 struct MessageQueue *mqe;
1153 struct GNUNET_MessageHeader *m;
1154
1155#if DEBUG_TRANSPORT
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 _("Sending message of type %u to peer `%4s'\n"),
1158 ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1159#endif
1160 if (client != NULL)
1161 {
1162 /* check for duplicate submission */
1163 mq = neighbour->messages;
1164 while (NULL != mq)
1165 {
1166 if (mq->client == client)
1167 {
1168 /* client transmitted to same peer twice
1169 before getting SendOk! */
1170 GNUNET_break (0);
1171 return;
1172 }
1173 mq = mq->next;
1174 }
1175 }
1176 mq = GNUNET_malloc (sizeof (struct MessageQueue));
1177 mq->client = client;
1178 m = GNUNET_malloc (ntohs (msg->size));
1179 memcpy (m, msg, ntohs (msg->size));
1180 mq->message = m;
1181 mq->neighbour = neighbour;
1182 mq->internal_msg = is_internal;
1183
1184 /* find tail */
1185 mqe = neighbour->messages;
1186 if (mqe != NULL)
1187 while (mqe->next != NULL)
1188 mqe = mqe->next;
1189 if (mqe == NULL)
1190 {
1191 /* new head */
1192 neighbour->messages = mq;
1193 try_transmission_to_peer (neighbour);
1194 }
1195 else
1196 {
1197 /* append */
1198 mqe->next = mq;
1199 }
1200}
1201
1202
1203struct GeneratorContext
1204{
1205 struct TransportPlugin *plug_pos;
1206 struct AddressList *addr_pos;
1207 struct GNUNET_TIME_Absolute expiration;
1208};
1209
1210
1211static size_t
1212address_generator (void *cls, size_t max, void *buf)
1213{
1214 struct GeneratorContext *gc = cls;
1215 size_t ret;
1216
1217 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1218 {
1219 gc->plug_pos = gc->plug_pos->next;
1220 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1221 }
1222 if (NULL == gc->plug_pos)
1223 return 0;
1224 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1225 gc->expiration,
1226 gc->addr_pos->addr,
1227 gc->addr_pos->addrlen, buf, max);
1228 gc->addr_pos = gc->addr_pos->next;
1229 return ret;
1230}
1231
1232
1233/**
1234 * Construct our HELLO message from all of the addresses of
1235 * all of the transports.
1236 */
1237static void
1238refresh_hello ()
1239{
1240 struct GNUNET_HELLO_Message *hello;
1241 struct TransportClient *cpos;
1242 struct NeighbourList *npos;
1243 struct GeneratorContext gc;
1244
1245#if DEBUG_TRANSPORT
1246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1247 "Refreshing my HELLO\n");
1248#endif
1249 gc.plug_pos = plugins;
1250 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1251 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1252 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1253 cpos = clients;
1254 while (cpos != NULL)
1255 {
1256 transmit_to_client (cpos,
1257 (const struct GNUNET_MessageHeader *) hello,
1258 GNUNET_NO);
1259 cpos = cpos->next;
1260 }
1261
1262 GNUNET_free_non_null (our_hello);
1263 our_hello = hello;
1264 our_hello_version++;
1265 npos = neighbours;
1266 while (npos != NULL)
1267 {
1268 transmit_to_peer (NULL,
1269 (const struct GNUNET_MessageHeader *) our_hello,
1270 GNUNET_YES, npos);
1271 npos = npos->next;
1272 }
1273}
1274
1275
1276/**
1277 * Task used to clean up expired addresses for a plugin.
1278 *
1279 * @param cls closure
1280 * @param tc context
1281 */
1282static void
1283expire_address_task (void *cls,
1284 const struct GNUNET_SCHEDULER_TaskContext *tc);
1285
1286
1287/**
1288 * Update the list of addresses for this plugin,
1289 * expiring those that are past their expiration date.
1290 *
1291 * @param plugin addresses of which plugin should be recomputed?
1292 * @param fresh set to GNUNET_YES if a new address was added
1293 * and we need to regenerate the HELLO even if nobody
1294 * expired
1295 */
1296static void
1297update_addresses (struct TransportPlugin *plugin, int fresh)
1298{
1299 struct GNUNET_TIME_Relative min_remaining;
1300 struct GNUNET_TIME_Relative remaining;
1301 struct GNUNET_TIME_Absolute now;
1302 struct AddressList *pos;
1303 struct AddressList *prev;
1304 struct AddressList *next;
1305 int expired;
1306
1307 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
1308 GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1309 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1310 now = GNUNET_TIME_absolute_get ();
1311 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1312 expired = GNUNET_NO;
1313 prev = NULL;
1314 pos = plugin->addresses;
1315 while (pos != NULL)
1316 {
1317 next = pos->next;
1318 if (pos->expires.value < now.value)
1319 {
1320 expired = GNUNET_YES;
1321 if (prev == NULL)
1322 plugin->addresses = pos->next;
1323 else
1324 prev->next = pos->next;
1325 GNUNET_free (pos);
1326 }
1327 else
1328 {
1329 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1330 if (remaining.value < min_remaining.value)
1331 min_remaining = remaining;
1332 prev = pos;
1333 }
1334 pos = next;
1335 }
1336
1337 if (expired || fresh)
1338 refresh_hello ();
1339 if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1340 plugin->address_update_task
1341 = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1342 GNUNET_NO,
1343 GNUNET_SCHEDULER_PRIORITY_IDLE,
1344 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1345 min_remaining,
1346 &expire_address_task, plugin);
1347
1348}
1349
1350
1351/**
1352 * Task used to clean up expired addresses for a plugin.
1353 *
1354 * @param cls closure
1355 * @param tc context
1356 */
1357static void
1358expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1359{
1360 struct TransportPlugin *plugin = cls;
1361 plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1362 update_addresses (plugin, GNUNET_NO);
1363}
1364
1365
1366/**
1367 * Function that must be called by each plugin to notify the
1368 * transport service about the addresses under which the transport
1369 * provided by the plugin can be reached.
1370 *
1371 * @param cls closure
1372 * @param name name of the transport that generated the address
1373 * @param addr one of the addresses of the host, NULL for the last address
1374 * the specific address format depends on the transport
1375 * @param addrlen length of the address
1376 * @param expires when should this address automatically expire?
1377 */
1378static void
1379plugin_env_notify_address (void *cls,
1380 const char *name,
1381 const void *addr,
1382 size_t addrlen,
1383 struct GNUNET_TIME_Relative expires)
1384{
1385 struct TransportPlugin *p = cls;
1386 struct AddressList *al;
1387 struct GNUNET_TIME_Absolute abex;
1388
1389#if DEBUG_TRANSPORT
1390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1391 "Plugin `%s' informs us about a new address\n", name);
1392#endif
1393 abex = GNUNET_TIME_relative_to_absolute (expires);
1394 GNUNET_assert (p == find_transport (name));
1395
1396 al = p->addresses;
1397 while (al != NULL)
1398 {
1399 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1400 {
1401 if (al->expires.value < abex.value)
1402 al->expires = abex;
1403 return;
1404 }
1405 al = al->next;
1406 }
1407 al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1408 al->addr = &al[1];
1409 al->next = p->addresses;
1410 p->addresses = al;
1411 al->expires = abex;
1412 al->addrlen = addrlen;
1413 memcpy (&al[1], addr, addrlen);
1414 update_addresses (p, GNUNET_YES);
1415}
1416
1417
1418struct LookupHelloContext
1419{
1420 GNUNET_TRANSPORT_AddressCallback iterator;
1421
1422 void *iterator_cls;
1423};
1424
1425
1426static int
1427lookup_address_callback (void *cls,
1428 const char *tname,
1429 struct GNUNET_TIME_Absolute expiration,
1430 const void *addr, size_t addrlen)
1431{
1432 struct LookupHelloContext *lhc = cls;
1433 lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
1434 return GNUNET_OK;
1435}
1436
1437
1438static void
1439lookup_hello_callback (void *cls,
1440 const struct GNUNET_PeerIdentity *peer,
1441 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1442{
1443 struct LookupHelloContext *lhc = cls;
1444
1445 if (peer == NULL)
1446 {
1447 lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
1448 GNUNET_free (lhc);
1449 return;
1450 }
1451 if (h == NULL)
1452 return;
1453 GNUNET_HELLO_iterate_addresses (h,
1454 GNUNET_NO, &lookup_address_callback, lhc);
1455}
1456
1457
1458/**
1459 * Function that allows a transport to query the known
1460 * network addresses for a given peer.
1461 *
1462 * @param cls closure
1463 * @param timeout after how long should we time out?
1464 * @param target which peer are we looking for?
1465 * @param iter function to call for each known address
1466 * @param iter_cls closure for iter
1467 */
1468static void
1469plugin_env_lookup_address (void *cls,
1470 struct GNUNET_TIME_Relative timeout,
1471 const struct GNUNET_PeerIdentity *target,
1472 GNUNET_TRANSPORT_AddressCallback iter,
1473 void *iter_cls)
1474{
1475 struct LookupHelloContext *lhc;
1476
1477 lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
1478 lhc->iterator = iter;
1479 lhc->iterator_cls = iter_cls;
1480 GNUNET_PEERINFO_for_all (cfg,
1481 sched,
1482 target, 0, timeout, &lookup_hello_callback, &lhc);
1483}
1484
1485
1486/**
1487 * Notify all of our clients about a peer connecting.
1488 */
1489static void
1490notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1491 struct GNUNET_TIME_Relative latency)
1492{
1493 struct ConnectInfoMessage cim;
1494 struct TransportClient *cpos;
1495
1496#if DEBUG_TRANSPORT
1497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1498 "Informing clients about peer `%4s' connecting to us\n",
1499 GNUNET_i2s (peer));
1500#endif
1501 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1502 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1503 cim.quota_out = htonl (default_quota_out);
1504 cim.latency = GNUNET_TIME_relative_hton (latency);
1505 memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1506 cpos = clients;
1507 while (cpos != NULL)
1508 {
1509 transmit_to_client (cpos, &cim.header, GNUNET_NO);
1510 cpos = cpos->next;
1511 }
1512}
1513
1514
1515/**
1516 * Notify all of our clients about a peer disconnecting.
1517 */
1518static void
1519notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1520{
1521 struct DisconnectInfoMessage dim;
1522 struct TransportClient *cpos;
1523
1524#if DEBUG_TRANSPORT
1525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1526 "Informing clients about peer `%4s' disconnecting\n",
1527 GNUNET_i2s (peer));
1528#endif
1529 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1530 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1531 dim.reserved = htonl (0);
1532 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1533 cpos = clients;
1534 while (cpos != NULL)
1535 {
1536 transmit_to_client (cpos, &dim.header, GNUNET_NO);
1537 cpos = cpos->next;
1538 }
1539}
1540
1541
1542/**
1543 * Copy any validated addresses to buf.
1544 *
1545 * @return 0 once all addresses have been
1546 * returned
1547 */
1548static size_t
1549list_validated_addresses (void *cls, size_t max, void *buf)
1550{
1551 struct ValidationAddress **va = cls;
1552 size_t ret;
1553
1554 while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1555 *va = (*va)->next;
1556 if (NULL == *va)
1557 return 0;
1558 ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1559 (*va)->expiration,
1560 &(*va)->msg[1], (*va)->addr_len, buf, max);
1561 *va = (*va)->next;
1562 return ret;
1563}
1564
1565
1566/**
1567 * HELLO validation cleanup task.
1568 */
1569static void
1570cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1571{
1572 struct ValidationAddress *va;
1573 struct ValidationList *pos;
1574 struct ValidationList *prev;
1575 struct GNUNET_TIME_Absolute now;
1576 struct GNUNET_HELLO_Message *hello;
1577 struct GNUNET_PeerIdentity pid;
1578
1579#if DEBUG_TRANSPORT
1580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1581 "HELLO validation cleanup background task running...\n");
1582#endif
1583 now = GNUNET_TIME_absolute_get ();
1584 prev = NULL;
1585 pos = pending_validations;
1586 while (pos != NULL)
1587 {
1588 if (pos->timeout.value < now.value)
1589 {
1590 if (prev == NULL)
1591 pending_validations = pos->next;
1592 else
1593 prev->next = pos->next;
1594 va = pos->addresses;
1595 hello = GNUNET_HELLO_create (&pos->publicKey,
1596 &list_validated_addresses, &va);
1597 GNUNET_CRYPTO_hash (&pos->publicKey,
1598 sizeof (struct
1599 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1600 &pid.hashPubKey);
1601#if DEBUG_TRANSPORT
1602 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1603 "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1604 "HELLO", GNUNET_i2s (&pid));
1605#endif
1606 GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1607 GNUNET_free (hello);
1608 while (NULL != (va = pos->addresses))
1609 {
1610 pos->addresses = va->next;
1611 GNUNET_free (va->transport_name);
1612 GNUNET_free (va);
1613 }
1614 GNUNET_free (pos);
1615 if (prev == NULL)
1616 pos = pending_validations;
1617 else
1618 pos = prev->next;
1619 continue;
1620 }
1621 prev = pos;
1622 pos = pos->next;
1623 }
1624
1625 /* finally, reschedule cleanup if needed; list is
1626 ordered by timeout, so we need the last element... */
1627 pos = pending_validations;
1628 while ((pos != NULL) && (pos->next != NULL))
1629 pos = pos->next;
1630 if (NULL != pos)
1631 GNUNET_SCHEDULER_add_delayed (sched,
1632 GNUNET_NO,
1633 GNUNET_SCHEDULER_PRIORITY_IDLE,
1634 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1635 GNUNET_TIME_absolute_get_remaining (pos->
1636 timeout),
1637 &cleanup_validation, NULL);
1638}
1639
1640
1641struct CheckHelloValidatedContext
1642{
1643 /**
1644 * Plugin for which we are validating.
1645 */
1646 struct TransportPlugin *plugin;
1647
1648 /**
1649 * Hello that we are validating.
1650 */
1651 struct GNUNET_HELLO_Message *hello;
1652
1653 /**
1654 * Validation list being build.
1655 */
1656 struct ValidationList *e;
1657};
1658
1659
1660/**
1661 * Append the given address to the list of entries
1662 * that need to be validated.
1663 */
1664static int
1665run_validation (void *cls,
1666 const char *tname,
1667 struct GNUNET_TIME_Absolute expiration,
1668 const void *addr, size_t addrlen)
1669{
1670 struct ValidationList *e = cls;
1671 struct TransportPlugin *tp;
1672 struct ValidationAddress *va;
1673 struct ValidationChallengeMessage *vcm;
1674
1675 tp = find_transport (tname);
1676 if (tp == NULL)
1677 {
1678 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1679 GNUNET_ERROR_TYPE_BULK,
1680 _
1681 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1682 tname);
1683 return GNUNET_OK;
1684 }
1685 va = GNUNET_malloc (sizeof (struct ValidationAddress) +
1686 sizeof (struct ValidationChallengeMessage) + addrlen);
1687 va->next = e->addresses;
1688 e->addresses = va;
1689 vcm = (struct ValidationChallengeMessage *) &va[1];
1690 va->msg = vcm;
1691 va->transport_name = GNUNET_strdup (tname);
1692 va->addr_len = addrlen;
1693 vcm->header.size =
1694 htons (sizeof (struct ValidationChallengeMessage) + addrlen);
1695 vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1696 vcm->purpose.size =
1697 htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
1698 sizeof (struct GNUNET_MessageHeader));
1699 vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
1700 vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1701 (unsigned int) -1);
1702 /* Note: vcm->target is set in check_hello_validated */
1703 memcpy (&vcm[1], addr, addrlen);
1704 return GNUNET_OK;
1705}
1706
1707
1708/**
1709 * Check if addresses in validated hello "h" overlap with
1710 * those in "chvc->hello" and update "chvc->hello" accordingly,
1711 * removing those addresses that have already been validated.
1712 */
1713static void
1714check_hello_validated (void *cls,
1715 const struct GNUNET_PeerIdentity *peer,
1716 const struct GNUNET_HELLO_Message *h, uint32_t trust)
1717{
1718 struct CheckHelloValidatedContext *chvc = cls;
1719 struct ValidationAddress *va;
1720 struct TransportPlugin *tp;
1721 int first_call;
1722
1723 first_call = GNUNET_NO;
1724 if (chvc->e == NULL)
1725 {
1726 first_call = GNUNET_YES;
1727 chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1728 GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello, &chvc->e->publicKey);
1729 chvc->e->timeout =
1730 GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1731 chvc->e->next = pending_validations;
1732 pending_validations = chvc->e;
1733 }
1734 if (h != NULL)
1735 {
1736 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1737 h,
1738 GNUNET_TIME_absolute_get (),
1739 &run_validation, chvc->e);
1740 }
1741 else if (GNUNET_YES == first_call)
1742 {
1743 /* no existing HELLO, all addresses are new */
1744 GNUNET_HELLO_iterate_addresses (chvc->hello,
1745 GNUNET_NO, &run_validation, chvc->e);
1746 }
1747 if (h != NULL)
1748 return; /* wait for next call */
1749 /* finally, transmit validation attempts */
1750 va = chvc->e->addresses;
1751 while (va != NULL)
1752 {
1753 GNUNET_CRYPTO_hash (&chvc->e->publicKey,
1754 sizeof (struct
1755 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1756 &va->msg->target.hashPubKey);
1757#if DEBUG_TRANSPORT
1758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1759 "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
1760 va->transport_name,
1761 "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
1762#endif
1763 tp = find_transport (va->transport_name);
1764 GNUNET_assert (tp != NULL);
1765 if (NULL ==
1766 tp->api->send_to (tp->api->cls,
1767 &va->msg->target,
1768 (const struct GNUNET_MessageHeader *) our_hello,
1769 &va->msg->header,
1770 HELLO_VERIFICATION_TIMEOUT,
1771 &va->msg[1], va->addr_len))
1772 va->ok = GNUNET_SYSERR;
1773 va = va->next;
1774 }
1775 if (chvc->e->next == NULL)
1776 GNUNET_SCHEDULER_add_delayed (sched,
1777 GNUNET_NO,
1778 GNUNET_SCHEDULER_PRIORITY_IDLE,
1779 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1780 GNUNET_TIME_absolute_get_remaining (chvc->
1781 e->
1782 timeout),
1783 &cleanup_validation, NULL);
1784 GNUNET_free (chvc);
1785}
1786
1787
1788/**
1789 * Process HELLO-message.
1790 *
1791 * @param plugin transport involved, may be NULL
1792 * @param message the actual message
1793 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1794 */
1795static int
1796process_hello (struct TransportPlugin *plugin,
1797 const struct GNUNET_MessageHeader *message)
1798{
1799 struct ValidationList *e;
1800 uint16_t hsize;
1801 struct GNUNET_PeerIdentity target;
1802 const struct GNUNET_HELLO_Message *hello;
1803 struct CheckHelloValidatedContext *chvc;
1804 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1805
1806 hsize = ntohs (message->size);
1807 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1808 (hsize < sizeof (struct GNUNET_MessageHeader)))
1809 {
1810 GNUNET_break (0);
1811 return GNUNET_SYSERR;
1812 }
1813 /* first, check if load is too high */
1814 if (GNUNET_OS_load_cpu_get (cfg) > 100)
1815 {
1816 /* TODO: call to stats? */
1817 return GNUNET_OK;
1818 }
1819 hello = (const struct GNUNET_HELLO_Message *) message;
1820 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1821 {
1822 GNUNET_break_op (0);
1823 return GNUNET_SYSERR;
1824 }
1825 GNUNET_CRYPTO_hash (&publicKey,
1826 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1827 &target.hashPubKey);
1828#if DEBUG_TRANSPORT
1829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830 "Processing `%s' message for `%4s'\n",
1831 "HELLO", GNUNET_i2s (&target));
1832#endif
1833 /* check if a HELLO for this peer is already on the validation list */
1834 e = pending_validations;
1835 while (e != NULL)
1836 {
1837 if (0 == memcmp (&e->publicKey,
1838 &publicKey,
1839 sizeof (struct
1840 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1841 {
1842 /* TODO: call to stats? */
1843 return GNUNET_OK;
1844 }
1845 e = e->next;
1846 }
1847 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1848 chvc->plugin = plugin;
1849 chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1850 memcpy (chvc->hello, hello, hsize);
1851 /* finally, check if HELLO was previously validated
1852 (continuation will then schedule actual validation) */
1853 GNUNET_PEERINFO_for_all (cfg,
1854 sched,
1855 &target,
1856 0,
1857 HELLO_VERIFICATION_TIMEOUT,
1858 &check_hello_validated, chvc);
1859 return GNUNET_OK;
1860}
1861
1862
1863/**
1864 * Handle PING-message. If the plugin that gave us the message is
1865 * able to queue the PONG immediately, we only queue one PONG.
1866 * Otherwise we send at most TWO PONG messages, one via an unconfirmed
1867 * transport and one via a confirmed transport. Both addresses are
1868 * selected randomly among those available.
1869 *
1870 * @param plugin plugin that gave us the message
1871 * @param sender claimed sender of the PING
1872 * @param plugin_context context that might be used to send response
1873 * @param message the actual message
1874 */
1875static void
1876process_ping (struct TransportPlugin *plugin,
1877 const struct GNUNET_PeerIdentity *sender,
1878 void *plugin_context,
1879 const struct GNUNET_MessageHeader *message)
1880{
1881 const struct ValidationChallengeMessage *vcm;
1882 struct ValidationChallengeResponse vcr;
1883 uint16_t msize;
1884 struct NeighbourList *n;
1885
1886#if DEBUG_TRANSPORT
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1888 "Processing PING\n");
1889#endif
1890 msize = ntohs (message->size);
1891 if (msize < sizeof (struct ValidationChallengeMessage))
1892 {
1893 GNUNET_break_op (0);
1894 return;
1895 }
1896 vcm = (const struct ValidationChallengeMessage *) message;
1897 if (0 != memcmp (&vcm->target,
1898 &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1899 {
1900 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1901 _("Received `%s' message not destined for me!\n"), "PING");
1902 /* TODO: call statistics */
1903 return;
1904 }
1905 if ((ntohl (vcm->purpose.size) !=
1906 msize - sizeof (struct GNUNET_MessageHeader))
1907 || (ntohl (vcm->purpose.purpose) !=
1908 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
1909 {
1910 GNUNET_break_op (0);
1911 return;
1912 }
1913 msize -= sizeof (struct ValidationChallengeMessage);
1914 if (GNUNET_OK !=
1915 plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
1916 {
1917 GNUNET_break_op (0);
1918 return;
1919 }
1920 vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
1921 vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1922 vcr.challenge = vcm->challenge;
1923 vcr.sender = my_identity;
1924 GNUNET_assert (GNUNET_OK ==
1925 GNUNET_CRYPTO_rsa_sign (my_private_key,
1926 &vcm->purpose, &vcr.signature));
1927#if EXTRA_CHECKS
1928 GNUNET_assert (GNUNET_OK ==
1929 GNUNET_CRYPTO_rsa_verify
1930 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
1931 &vcr.signature, &my_public_key));
1932#endif
1933#if DEBUG_TRANSPORT
1934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1935 "Trying to transmit PONG using inbound connection\n");
1936#endif
1937 n = find_neighbour (sender);
1938 transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n);
1939}
1940
1941
1942/**
1943 * Handle PONG-message.
1944 *
1945 * @param message the actual message
1946 */
1947static void
1948process_pong (struct TransportPlugin *plugin,
1949 const struct GNUNET_MessageHeader *message)
1950{
1951 const struct ValidationChallengeResponse *vcr;
1952 struct ValidationList *pos;
1953 struct GNUNET_PeerIdentity peer;
1954 struct ValidationAddress *va;
1955 int all_done;
1956 int matched;
1957
1958#if DEBUG_TRANSPORT
1959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1960 "Processing PONG\n");
1961#endif
1962 vcr = (const struct ValidationChallengeResponse *) message;
1963 pos = pending_validations;
1964 while (pos != NULL)
1965 {
1966 GNUNET_CRYPTO_hash (&pos->publicKey,
1967 sizeof (struct
1968 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1969 &peer.hashPubKey);
1970 if (0 ==
1971 memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
1972 break;
1973 pos = pos->next;
1974 }
1975 if (pos == NULL)
1976 {
1977 /* TODO: call statistics (unmatched PONG) */
1978 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1979 _
1980 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1981 "PONG", "PING");
1982 return;
1983 }
1984 all_done = GNUNET_YES;
1985 matched = GNUNET_NO;
1986 va = pos->addresses;
1987 while (va != NULL)
1988 {
1989 if (va->msg->challenge == vcr->challenge)
1990 {
1991 if (GNUNET_OK !=
1992 GNUNET_CRYPTO_rsa_verify
1993 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
1994 &vcr->signature, &pos->publicKey))
1995 {
1996 /* this could rarely happen if we used the same
1997 challenge number for the peer for two different
1998 transports / addresses, but the likelihood is
1999 very small... */
2000 GNUNET_break_op (0);
2001 }
2002 else
2003 {
2004#if DEBUG_TRANSPORT
2005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2006 "Confirmed validity of peer address.\n");
2007#endif
2008 va->ok = GNUNET_YES;
2009 va->expiration =
2010 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2011 matched = GNUNET_YES;
2012 }
2013 }
2014 if (va->ok != GNUNET_YES)
2015 all_done = GNUNET_NO;
2016 va = va->next;
2017 }
2018 if (GNUNET_NO == matched)
2019 {
2020 /* TODO: call statistics (unmatched PONG) */
2021 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2022 _
2023 ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
2024 "PONG", "PING");
2025 }
2026 if (GNUNET_YES == all_done)
2027 {
2028 pos->timeout.value = 0;
2029 GNUNET_SCHEDULER_add_delayed (sched,
2030 GNUNET_NO,
2031 GNUNET_SCHEDULER_PRIORITY_IDLE,
2032 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2033 GNUNET_TIME_UNIT_ZERO,
2034 &cleanup_validation, NULL);
2035 }
2036}
2037
2038
2039/**
2040 * The peer specified by the given neighbour has timed-out. Update
2041 * our state and do the necessary notifications. Also notifies
2042 * our clients that the neighbour is now officially gone.
2043 *
2044 * @param n the neighbour list entry for the peer
2045 */
2046static void
2047disconnect_neighbour (struct NeighbourList *n)
2048{
2049 struct ReadyList *rpos;
2050 struct NeighbourList *npos;
2051 struct NeighbourList *nprev;
2052 struct MessageQueue *mq;
2053
2054#if DEBUG_TRANSPORT
2055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2056 "Disconnecting from neighbour\n");
2057#endif
2058 /* remove n from neighbours list */
2059 nprev = NULL;
2060 npos = neighbours;
2061 while ((npos != NULL) && (npos != n))
2062 {
2063 nprev = npos;
2064 npos = npos->next;
2065 }
2066 GNUNET_assert (npos != NULL);
2067 if (nprev == NULL)
2068 neighbours = n->next;
2069 else
2070 nprev->next = n->next;
2071
2072 /* notify all clients about disconnect */
2073 notify_clients_disconnect (&n->id);
2074
2075 /* clean up all plugins, cancel connections & pending transmissions */
2076 while (NULL != (rpos = n->plugins))
2077 {
2078 n->plugins = rpos->next;
2079 GNUNET_assert (rpos->neighbour == n);
2080 rpos->plugin->api->cancel (rpos->plugin->api->cls,
2081 rpos->plugin_handle, rpos, &n->id);
2082 GNUNET_free (rpos);
2083 }
2084
2085 /* free all messages on the queue */
2086 while (NULL != (mq = n->messages))
2087 {
2088 n->messages = mq->next;
2089 GNUNET_assert (mq->neighbour == n);
2090 GNUNET_free (mq);
2091 }
2092
2093 /* finally, free n itself */
2094 GNUNET_free (n);
2095}
2096
2097
2098/**
2099 * Add an entry for each of our transport plugins
2100 * (that are able to send) to the list of plugins
2101 * for this neighbour.
2102 *
2103 * @param neighbour to initialize
2104 */
2105static void
2106add_plugins (struct NeighbourList *neighbour)
2107{
2108 struct TransportPlugin *tp;
2109 struct ReadyList *rl;
2110
2111 neighbour->retry_plugins_time
2112 = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2113 tp = plugins;
2114 while (tp != NULL)
2115 {
2116 if (tp->api->send != NULL)
2117 {
2118 rl = GNUNET_malloc (sizeof (struct ReadyList));
2119 rl->next = neighbour->plugins;
2120 neighbour->plugins = rl;
2121 rl->plugin = tp;
2122 rl->neighbour = neighbour;
2123 rl->transmit_ready = GNUNET_YES;
2124 }
2125 tp = tp->next;
2126 }
2127}
2128
2129
2130static void
2131neighbour_timeout_task (void *cls,
2132 const struct GNUNET_SCHEDULER_TaskContext *tc)
2133{
2134 struct NeighbourList *n = cls;
2135
2136#if DEBUG_TRANSPORT
2137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2138 "Neighbour has timed out!\n");
2139#endif
2140 n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
2141 disconnect_neighbour (n);
2142}
2143
2144
2145
2146/**
2147 * Create a fresh entry in our neighbour list for the given peer.
2148 * Will try to transmit our current HELLO to the new neighbour. Also
2149 * notifies our clients about the new "connection".
2150 *
2151 * @param peer the peer for which we create the entry
2152 * @return the new neighbour list entry
2153 */
2154static struct NeighbourList *
2155setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2156{
2157 struct NeighbourList *n;
2158
2159#if DEBUG_TRANSPORT
2160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2161 "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
2162 GNUNET_i2s (peer));
2163#endif
2164 GNUNET_assert (our_hello != NULL);
2165 n = GNUNET_malloc (sizeof (struct NeighbourList));
2166 n->next = neighbours;
2167 neighbours = n;
2168 n->id = *peer;
2169 n->last_quota_update = GNUNET_TIME_absolute_get ();
2170 n->peer_timeout =
2171 GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2172 n->quota_in = default_quota_in;
2173 add_plugins (n);
2174 n->hello_version_sent = our_hello_version;
2175 n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2176 GNUNET_NO,
2177 GNUNET_SCHEDULER_PRIORITY_IDLE,
2178 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2179 IDLE_CONNECTION_TIMEOUT,
2180 &neighbour_timeout_task, n);
2181 transmit_to_peer (NULL,
2182 (const struct GNUNET_MessageHeader *) our_hello,
2183 GNUNET_YES, n);
2184 notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2185 return n;
2186}
2187
2188
2189/**
2190 * Function called by the plugin for each received message.
2191 * Update data volumes, possibly notify plugins about
2192 * reducing the rate at which they read from the socket
2193 * and generally forward to our receive callback.
2194 *
2195 * @param plugin_context value to pass to this plugin
2196 * to respond to the given peer (use is optional,
2197 * but may speed up processing)
2198 * @param service_context value passed to the transport-service
2199 * to identify the neighbour; will be NULL on the first
2200 * call for a given peer
2201 * @param latency estimated latency for communicating with the
2202 * given peer
2203 * @param peer (claimed) identity of the other peer
2204 * @param message the message, NULL if peer was disconnected
2205 * @return the new service_context that the plugin should use
2206 * for future receive calls for messages from this
2207 * particular peer
2208 */
2209static struct ReadyList *
2210plugin_env_receive (void *cls,
2211 void *plugin_context,
2212 struct ReadyList *service_context,
2213 struct GNUNET_TIME_Relative latency,
2214 const struct GNUNET_PeerIdentity *peer,
2215 const struct GNUNET_MessageHeader *message)
2216{
2217 const struct GNUNET_MessageHeader ack = {
2218 htons (sizeof (struct GNUNET_MessageHeader)),
2219 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2220 };
2221 struct TransportPlugin *plugin = cls;
2222 struct TransportClient *cpos;
2223 struct InboundMessage *im;
2224 uint16_t msize;
2225 struct NeighbourList *n;
2226
2227 if (service_context != NULL)
2228 {
2229 n = service_context->neighbour;
2230 GNUNET_assert (n != NULL);
2231 }
2232 else
2233 {
2234 n = find_neighbour (peer);
2235 if (n == NULL)
2236 {
2237 if (message == NULL)
2238 return NULL; /* disconnect of peer already marked down */
2239 n = setup_new_neighbour (peer);
2240 }
2241 service_context = n->plugins;
2242 while ((service_context != NULL) && (plugin != service_context->plugin))
2243 service_context = service_context->next;
2244 GNUNET_assert ((plugin->api->send == NULL) ||
2245 (service_context != NULL));
2246 }
2247 if (message == NULL)
2248 {
2249 if ((service_context != NULL) &&
2250 (service_context->plugin_handle == plugin_context))
2251 {
2252 service_context->connected = GNUNET_NO;
2253 service_context->plugin_handle = NULL;
2254 }
2255 /* TODO: call stats */
2256 return NULL;
2257 }
2258#if DEBUG_TRANSPORT
2259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2260 "Processing message of type `%u' received by plugin...\n",
2261 ntohs (message->type));
2262#endif
2263 if (service_context != NULL)
2264 {
2265 if (service_context->connected == GNUNET_NO)
2266 {
2267 service_context->connected = GNUNET_YES;
2268 service_context->transmit_ready = GNUNET_YES;
2269 service_context->connect_attempts++;
2270 }
2271 service_context->timeout
2272 = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2273 service_context->plugin_handle = plugin_context;
2274 service_context->latency = latency;
2275 }
2276 /* update traffic received amount ... */
2277 msize = ntohs (message->size);
2278 n->last_received += msize;
2279 GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2280 n->peer_timeout =
2281 GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
2282 n->timeout_task =
2283 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
2284 GNUNET_SCHEDULER_PRIORITY_IDLE,
2285 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2286 IDLE_CONNECTION_TIMEOUT,
2287 &neighbour_timeout_task, n);
2288 update_quota (n);
2289 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2290 {
2291 /* dropping message due to frequent inbound volume violations! */
2292 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2293 GNUNET_ERROR_TYPE_BULK,
2294 _
2295 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2296 /* TODO: call stats */
2297 return service_context;
2298 }
2299 switch (ntohs (message->type))
2300 {
2301 case GNUNET_MESSAGE_TYPE_HELLO:
2302#if DEBUG_TRANSPORT
2303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2304 "Receiving `%s' message from other peer.\n", "HELLO");
2305#endif
2306 process_hello (plugin, message);
2307#if DEBUG_TRANSPORT
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2309 "Sending `%s' message to connecting peer.\n", "ACK");
2310#endif
2311 transmit_to_peer (NULL, &ack, GNUNET_YES, n);
2312 break;
2313 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2314 process_ping (plugin, peer, plugin_context, message);
2315 break;
2316 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2317 process_pong (plugin, message);
2318 break;
2319 case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2320 n->saw_ack = GNUNET_YES;
2321 /* intentional fall-through! */
2322 default:
2323#if DEBUG_TRANSPORT
2324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2325 "Received message of type %u from other peer, sending to all clients.\n",
2326 ntohs (message->type));
2327#endif
2328 /* transmit message to all clients */
2329 im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2330 im->header.size = htons (sizeof (struct InboundMessage) + msize);
2331 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2332 im->latency = GNUNET_TIME_relative_hton (latency);
2333 im->peer = *peer;
2334 memcpy (&im[1], message, msize);
2335
2336 cpos = clients;
2337 while (cpos != NULL)
2338 {
2339 transmit_to_client (cpos, &im->header, GNUNET_YES);
2340 cpos = cpos->next;
2341 }
2342 GNUNET_free (im);
2343 }
2344 return service_context;
2345}
2346
2347
2348/**
2349 * Handle START-message. This is the first message sent to us
2350 * by any client which causes us to add it to our list.
2351 *
2352 * @param cls closure (always NULL)
2353 * @param server the server handling the message
2354 * @param client identification of the client
2355 * @param message the actual message
2356 */
2357static void
2358handle_start (void *cls,
2359 struct GNUNET_SERVER_Handle *server,
2360 struct GNUNET_SERVER_Client *client,
2361 const struct GNUNET_MessageHeader *message)
2362{
2363 struct TransportClient *c;
2364 struct ConnectInfoMessage cim;
2365 struct NeighbourList *n;
2366 struct InboundMessage *im;
2367 struct GNUNET_MessageHeader *ack;
2368
2369#if DEBUG_TRANSPORT
2370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2371 "Received `%s' request from client\n", "START");
2372#endif
2373 c = clients;
2374 while (c != NULL)
2375 {
2376 if (c->client == client)
2377 {
2378 /* client already on our list! */
2379 GNUNET_break (0);
2380 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2381 return;
2382 }
2383 c = c->next;
2384 }
2385 c = GNUNET_malloc (sizeof (struct TransportClient));
2386 c->next = clients;
2387 clients = c;
2388 c->client = client;
2389 if (our_hello != NULL)
2390 {
2391#if DEBUG_TRANSPORT
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393 "Sending our own HELLO to new client\n");
2394#endif
2395 transmit_to_client (c,
2396 (const struct GNUNET_MessageHeader *) our_hello,
2397 GNUNET_NO);
2398 /* tell new client about all existing connections */
2399 cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2400 cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2401 cim.quota_out = htonl (default_quota_out);
2402 cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2403 im = GNUNET_malloc (sizeof (struct InboundMessage) +
2404 sizeof (struct GNUNET_MessageHeader));
2405 im->header.size = htons (sizeof (struct InboundMessage) +
2406 sizeof (struct GNUNET_MessageHeader));
2407 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2408 im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */
2409 ack = (struct GNUNET_MessageHeader *) &im[1];
2410 ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2411 ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2412 for (n = neighbours; n != NULL; n = n->next)
2413 {
2414 cim.id = n->id;
2415 transmit_to_client (c, &cim.header, GNUNET_NO);
2416 if (n->saw_ack)
2417 {
2418 im->peer = n->id;
2419 transmit_to_client (c, &im->header, GNUNET_NO);
2420 }
2421 }
2422 GNUNET_free (im);
2423 }
2424 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2425}
2426
2427
2428/**
2429 * Handle HELLO-message.
2430 *
2431 * @param cls closure (always NULL)
2432 * @param server the server handling the message
2433 * @param client identification of the client
2434 * @param message the actual message
2435 */
2436static void
2437handle_hello (void *cls,
2438 struct GNUNET_SERVER_Handle *server,
2439 struct GNUNET_SERVER_Client *client,
2440 const struct GNUNET_MessageHeader *message)
2441{
2442 int ret;
2443
2444#if DEBUG_TRANSPORT
2445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446 "Received `%s' request from client\n", "HELLO");
2447#endif
2448 ret = process_hello (NULL, message);
2449 GNUNET_SERVER_receive_done (client, ret);
2450}
2451
2452
2453/**
2454 * Handle SEND-message.
2455 *
2456 * @param cls closure (always NULL)
2457 * @param server the server handling the message
2458 * @param client identification of the client
2459 * @param message the actual message
2460 */
2461static void
2462handle_send (void *cls,
2463 struct GNUNET_SERVER_Handle *server,
2464 struct GNUNET_SERVER_Client *client,
2465 const struct GNUNET_MessageHeader *message)
2466{
2467 struct TransportClient *tc;
2468 struct NeighbourList *n;
2469 const struct OutboundMessage *obm;
2470 const struct GNUNET_MessageHeader *obmm;
2471 uint16_t size;
2472 uint16_t msize;
2473
2474 size = ntohs (message->size);
2475 if (size <
2476 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2477 {
2478 GNUNET_break (0);
2479 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2480 return;
2481 }
2482 obm = (const struct OutboundMessage *) message;
2483#if DEBUG_TRANSPORT
2484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2485 "Received `%s' request from client with target `%4s'\n",
2486 "SEND", GNUNET_i2s (&obm->peer));
2487#endif
2488 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2489 msize = ntohs (obmm->size);
2490 if (size != msize + sizeof (struct OutboundMessage))
2491 {
2492 GNUNET_break (0);
2493 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2494 return;
2495 }
2496 n = find_neighbour (&obm->peer);
2497 if (n == NULL)
2498 n = setup_new_neighbour (&obm->peer);
2499 tc = clients;
2500 while ((tc != NULL) && (tc->client != client))
2501 tc = tc->next;
2502
2503#if DEBUG_TRANSPORT
2504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2505 "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2506 ntohs (obmm->size),
2507 ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2508#endif
2509 transmit_to_peer (tc, obmm, GNUNET_NO, n);
2510 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2511}
2512
2513
2514/**
2515 * Handle SET_QUOTA-message.
2516 *
2517 * @param cls closure (always NULL)
2518 * @param server the server handling the message
2519 * @param client identification of the client
2520 * @param message the actual message
2521 */
2522static void
2523handle_set_quota (void *cls,
2524 struct GNUNET_SERVER_Handle *server,
2525 struct GNUNET_SERVER_Client *client,
2526 const struct GNUNET_MessageHeader *message)
2527{
2528 const struct QuotaSetMessage *qsm =
2529 (const struct QuotaSetMessage *) message;
2530 struct NeighbourList *n;
2531 struct TransportPlugin *p;
2532 struct ReadyList *rl;
2533
2534#if DEBUG_TRANSPORT
2535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2536 "Received `%s' request from client for peer `%4s'\n",
2537 "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2538#endif
2539 n = find_neighbour (&qsm->peer);
2540 if (n == NULL)
2541 {
2542 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2543 return;
2544 }
2545 update_quota (n);
2546 if (n->quota_in < ntohl (qsm->quota_in))
2547 n->last_quota_update = GNUNET_TIME_absolute_get ();
2548 n->quota_in = ntohl (qsm->quota_in);
2549 rl = n->plugins;
2550 while (rl != NULL)
2551 {
2552 p = rl->plugin;
2553 p->api->set_receive_quota (p->api->cls,
2554 &qsm->peer, ntohl (qsm->quota_in));
2555 rl = rl->next;
2556 }
2557 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2558}
2559
2560
2561/**
2562 * Handle TRY_CONNECT-message.
2563 *
2564 * @param cls closure (always NULL)
2565 * @param server the server handling the message
2566 * @param client identification of the client
2567 * @param message the actual message
2568 */
2569static void
2570handle_try_connect (void *cls,
2571 struct GNUNET_SERVER_Handle *server,
2572 struct GNUNET_SERVER_Client *client,
2573 const struct GNUNET_MessageHeader *message)
2574{
2575 const struct TryConnectMessage *tcm;
2576
2577 tcm = (const struct TryConnectMessage *) message;
2578#if DEBUG_TRANSPORT
2579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2580 "Received `%s' request from client asking to connect to `%4s'\n",
2581 "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2582#endif
2583 if (NULL == find_neighbour (&tcm->peer))
2584 setup_new_neighbour (&tcm->peer);
2585 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2586}
2587
2588
2589/**
2590 * List of handlers for the messages understood by this
2591 * service.
2592 */
2593static struct GNUNET_SERVER_MessageHandler handlers[] = {
2594 {&handle_start, NULL,
2595 GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2596 {&handle_hello, NULL,
2597 GNUNET_MESSAGE_TYPE_HELLO, 0},
2598 {&handle_send, NULL,
2599 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2600 {&handle_set_quota, NULL,
2601 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2602 {&handle_try_connect, NULL,
2603 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2604 sizeof (struct TryConnectMessage)},
2605 {NULL, NULL, 0, 0}
2606};
2607
2608
2609/**
2610 * Setup the environment for this plugin.
2611 */
2612static void
2613create_environment (struct TransportPlugin *plug)
2614{
2615 plug->env.cfg = cfg;
2616 plug->env.sched = sched;
2617 plug->env.my_public_key = &my_public_key;
2618 plug->env.cls = plug;
2619 plug->env.receive = &plugin_env_receive;
2620 plug->env.lookup = &plugin_env_lookup_address;
2621 plug->env.notify_address = &plugin_env_notify_address;
2622 plug->env.default_quota_in = default_quota_in;
2623 plug->env.max_connections = max_connect_per_transport;
2624}
2625
2626
2627/**
2628 * Start the specified transport (load the plugin).
2629 */
2630static void
2631start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2632{
2633 struct TransportPlugin *plug;
2634 char *libname;
2635
2636 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2637 _("Loading `%s' transport plugin\n"), name);
2638 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2639 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2640 create_environment (plug);
2641 plug->short_name = GNUNET_strdup (name);
2642 plug->lib_name = libname;
2643 plug->next = plugins;
2644 plugins = plug;
2645 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2646 if (plug->api == NULL)
2647 {
2648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2649 _("Failed to load transport plugin for `%s'\n"), name);
2650 GNUNET_free (plug->short_name);
2651 plugins = plug->next;
2652 GNUNET_free (libname);
2653 GNUNET_free (plug);
2654 }
2655}
2656
2657
2658/**
2659 * Called whenever a client is disconnected. Frees our
2660 * resources associated with that client.
2661 *
2662 * @param cls closure
2663 * @param client identification of the client
2664 */
2665static void
2666client_disconnect_notification (void *cls,
2667 struct GNUNET_SERVER_Client *client)
2668{
2669 struct TransportClient *pos;
2670 struct TransportClient *prev;
2671 struct ClientMessageQueueEntry *mqe;
2672
2673#if DEBUG_TRANSPORT
2674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2675 "Client disconnected, cleaning up.\n");
2676#endif
2677 prev = NULL;
2678 pos = clients;
2679 while ((pos != NULL) && (pos->client != client))
2680 {
2681 prev = pos;
2682 pos = pos->next;
2683 }
2684 if (pos == NULL)
2685 return;
2686 while (NULL != (mqe = pos->message_queue_head))
2687 {
2688 pos->message_queue_head = mqe->next;
2689 GNUNET_free (mqe);
2690 }
2691 pos->message_queue_head = NULL;
2692 if (prev == NULL)
2693 clients = pos->next;
2694 else
2695 prev->next = pos->next;
2696 if (GNUNET_YES == pos->tcs_pending)
2697 {
2698 pos->client = NULL;
2699 return;
2700 }
2701 GNUNET_free (pos);
2702}
2703
2704
2705/**
2706 * Initiate transport service.
2707 *
2708 * @param cls closure
2709 * @param s scheduler to use
2710 * @param serv the initialized server
2711 * @param c configuration to use
2712 */
2713static void
2714run (void *cls,
2715 struct GNUNET_SCHEDULER_Handle *s,
2716 struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
2717{
2718 char *plugs;
2719 char *pos;
2720 int no_transports;
2721 unsigned long long qin;
2722 unsigned long long qout;
2723 unsigned long long tneigh;
2724 char *keyfile;
2725
2726 sched = s;
2727 cfg = c;
2728 /* parse configuration */
2729 if ((GNUNET_OK !=
2730 GNUNET_CONFIGURATION_get_value_number (c,
2731 "TRANSPORT",
2732 "DEFAULT_QUOTA_IN",
2733 &qin)) ||
2734 (GNUNET_OK !=
2735 GNUNET_CONFIGURATION_get_value_number (c,
2736 "TRANSPORT",
2737 "DEFAULT_QUOTA_OUT",
2738 &qout)) ||
2739 (GNUNET_OK !=
2740 GNUNET_CONFIGURATION_get_value_number (c,
2741 "TRANSPORT",
2742 "NEIGHBOUR_LIMIT",
2743 &tneigh)) ||
2744 (GNUNET_OK !=
2745 GNUNET_CONFIGURATION_get_value_filename (c,
2746 "GNUNETD",
2747 "HOSTKEY", &keyfile)))
2748 {
2749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2750 _
2751 ("Transport service is lacking key configuration settings. Exiting.\n"));
2752 GNUNET_SCHEDULER_shutdown (s);
2753 return;
2754 }
2755 max_connect_per_transport = (uint32_t) tneigh;
2756 default_quota_in = (uint32_t) qin;
2757 default_quota_out = (uint32_t) qout;
2758 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2759 GNUNET_free (keyfile);
2760 if (my_private_key == NULL)
2761 {
2762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2763 _
2764 ("Transport service could not access hostkey. Exiting.\n"));
2765 GNUNET_SCHEDULER_shutdown (s);
2766 return;
2767 }
2768 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2769 GNUNET_CRYPTO_hash (&my_public_key,
2770 sizeof (my_public_key), &my_identity.hashPubKey);
2771 /* setup notification */
2772 server = serv;
2773 GNUNET_SERVER_disconnect_notify (server,
2774 &client_disconnect_notification, NULL);
2775 /* load plugins... */
2776 no_transports = 1;
2777 if (GNUNET_OK ==
2778 GNUNET_CONFIGURATION_get_value_string (c,
2779 "TRANSPORT", "PLUGINS", &plugs))
2780 {
2781 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2782 _("Starting transport plugins `%s'\n"), plugs);
2783 pos = strtok (plugs, " ");
2784 while (pos != NULL)
2785 {
2786 start_transport (server, pos);
2787 no_transports = 0;
2788 pos = strtok (NULL, " ");
2789 }
2790 GNUNET_free (plugs);
2791 }
2792 if (no_transports)
2793 refresh_hello ();
2794 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
2795 /* process client requests */
2796 GNUNET_SERVER_add_handlers (server, handlers);
2797}
2798
2799
2800/**
2801 * Function called when the service shuts
2802 * down. Unloads our plugins.
2803 *
2804 * @param cls closure
2805 * @param cfg configuration to use
2806 */
2807static void
2808unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
2809{
2810 struct TransportPlugin *plug;
2811 struct AddressList *al;
2812
2813#if DEBUG_TRANSPORT
2814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2815 "Transport service is unloading plugins...\n");
2816#endif
2817 while (NULL != (plug = plugins))
2818 {
2819 plugins = plug->next;
2820 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2821 GNUNET_free (plug->lib_name);
2822 GNUNET_free (plug->short_name);
2823 while (NULL != (al = plug->addresses))
2824 {
2825 plug->addresses = al->next;
2826 GNUNET_free (al);
2827 }
2828 GNUNET_free (plug);
2829 }
2830 if (my_private_key != NULL)
2831 GNUNET_CRYPTO_rsa_key_free (my_private_key);
2832}
2833
2834
2835/**
2836 * The main function for the transport service.
2837 *
2838 * @param argc number of arguments from the command line
2839 * @param argv command line arguments
2840 * @return 0 ok, 1 on error
2841 */
2842int
2843main (int argc, char *const *argv)
2844{
2845 return (GNUNET_OK ==
2846 GNUNET_SERVICE_run (argc,
2847 argv,
2848 "transport",
2849 &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
2850}
2851
2852/* end of gnunet-service-transport.c */