fixing disconnect handling, making TCP plugin ready for bi-di use
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
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  * BUGS:
27  * - bi-directional nature of TCP is not exploited
28  *
29  * NOTE:
30  * - This code uses 'GNUNET_a2s' for debug printing in many places,
31  *   which is technically wrong since it assumes we have IP+Port 
32  *   (v4/v6) addresses.  Once we add transports like http or smtp
33  *   this will have to be changed!
34  */
35 #include "platform.h"
36 #include "gnunet_client_lib.h"
37 #include "gnunet_container_lib.h"
38 #include "gnunet_constants.h"
39 #include "gnunet_getopt_lib.h"
40 #include "gnunet_hello_lib.h"
41 #include "gnunet_os_lib.h"
42 #include "gnunet_peerinfo_service.h"
43 #include "gnunet_plugin_lib.h"
44 #include "gnunet_protocols.h"
45 #include "gnunet_service_lib.h"
46 #include "gnunet_signatures.h"
47 #include "plugin_transport.h"
48 #include "transport.h"
49
50 /**
51  * Should we do some additional checks (to validate behavior
52  * of clients)?
53  */
54 #define EXTRA_CHECKS GNUNET_YES
55
56 /**
57  * How many messages can we have pending for a given client process
58  * before we start to drop incoming messages?  We typically should
59  * have only one client and so this would be the primary buffer for
60  * messages, so the number should be chosen rather generously.
61  *
62  * The expectation here is that most of the time the queue is large
63  * enough so that a drop is virtually never required.
64  */
65 #define MAX_PENDING 128
66
67 /**
68  * How often should we try to reconnect to a peer using a particular
69  * transport plugin before giving up?  Note that the plugin may be
70  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
71  */
72 #define MAX_CONNECT_RETRY 3
73
74 /**
75  * Limit on the number of ready-to-run tasks when validating 
76  * HELLOs.  If more tasks are ready to run, we will drop 
77  * HELLOs instead of validating them.
78  */
79 #define MAX_HELLO_LOAD 4
80
81 /**
82  * How often must a peer violate bandwidth quotas before we start
83  * to simply drop its messages?
84  */
85 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
86
87 /**
88  * How long until a HELLO verification attempt should time out?
89  * Must be rather small, otherwise a partially successful HELLO
90  * validation (some addresses working) might not be available
91  * before a client's request for a connection fails for good.
92  * Besides, if a single request to an address takes a long time,
93  * then the peer is unlikely worthwhile anyway.
94  */
95 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
96
97 /**
98  * How long will we allow sending of a ping to be delayed?
99  */
100 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
101
102 /**
103  * Priority to use for PONG messages.
104  */
105 #define TRANSPORT_PONG_PRIORITY 4
106
107 /**
108  * How often do we re-add (cheaper) plugins to our list of plugins
109  * to try for a given connected peer?
110  */
111 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
112
113 /**
114  * After how long do we expire an address in a HELLO that we just
115  * validated?  This value is also used for our own addresses when we
116  * create a HELLO.
117  */
118 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
119
120
121 /**
122  * How long before an existing address expires should we again try to
123  * validate it?  Must be (significantly) smaller than
124  * HELLO_ADDRESS_EXPIRATION.
125  */
126 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
127
128 /**
129  * Maximum frequency for re-evaluating latencies for all transport addresses.
130  */
131 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
132
133 /**
134  * Maximum frequency for re-evaluating latencies for connected addresses.
135  */
136 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
137
138
139 /**
140  * List of addresses of other peers
141  */
142 struct ForeignAddressList
143 {
144   /**
145    * This is a linked list.
146    */
147   struct ForeignAddressList *next;
148
149   /**
150    * Which ready list does this entry belong to.
151    */
152   struct ReadyList *ready_list;
153
154   /**
155    * How long until we auto-expire this address (unless it is
156    * re-confirmed by the transport)?
157    */
158   struct GNUNET_TIME_Absolute expires;
159
160   /**
161    * Task used to re-validate addresses, updates latencies and
162    * verifies liveness.
163    */
164   GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
165
166   /**
167    * Length of addr.
168    */
169   size_t addrlen;
170
171   /**
172    * The address.
173    */
174   const void *addr;
175
176   /**
177    * What was the last latency observed for this address, plugin and peer?
178    */
179   struct GNUNET_TIME_Relative latency;
180
181   /**
182    * If we did not successfully transmit a message to the given peer
183    * via this connection during the specified time, we should consider
184    * the connection to be dead.  This is used in the case that a TCP
185    * transport simply stalls writing to the stream but does not
186    * formerly get a signal that the other peer died.
187    */
188   struct GNUNET_TIME_Absolute timeout;
189
190   /**
191    * How often have we tried to connect using this plugin?  Used to
192    * discriminate against addresses that do not work well.
193    * FIXME: not yet used, but should be!
194    */
195   unsigned int connect_attempts;
196
197   /**
198    * DV distance to this peer (1 if no DV is used). 
199    * FIXME: need to set this from transport plugins!
200    */
201   uint32_t distance;
202
203   /**
204    * Have we ever estimated the latency of this address?  Used to
205    * ensure that the first time we add an address, we immediately
206    * probe its latency.
207    */
208   int8_t estimated;
209
210   /**
211    * Are we currently connected via this address?  The first time we
212    * successfully transmit or receive data to a peer via a particular
213    * address, we set this to GNUNET_YES.  If we later get an error
214    * (disconnect notification, transmission failure, timeout), we set
215    * it back to GNUNET_NO.  
216    */
217   int8_t connected;
218
219   /**
220    * Is this plugin currently busy transmitting to the specific target?
221    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
222    * messages do not count as 'in transmit'.
223    */
224   int8_t in_transmit;
225
226   /**
227    * Has this address been validated yet?
228    */
229   int8_t validated;
230
231 };
232
233
234 /**
235  * Entry in linked list of network addresses for ourselves.
236  */
237 struct OwnAddressList
238 {
239   /**
240    * This is a linked list.
241    */
242   struct OwnAddressList *next;
243
244   /**
245    * The address, actually a pointer to the end
246    * of this struct.  Do not free!
247    */
248   const void *addr;
249   
250   /**
251    * How long until we auto-expire this address (unless it is
252    * re-confirmed by the transport)?
253    */
254   struct GNUNET_TIME_Absolute expires;
255
256   /**
257    * Length of addr.
258    */
259   size_t addrlen;
260
261 };
262
263
264 /**
265  * Entry in linked list of all of our plugins.
266  */
267 struct TransportPlugin
268 {
269
270   /**
271    * This is a linked list.
272    */
273   struct TransportPlugin *next;
274
275   /**
276    * API of the transport as returned by the plugin's
277    * initialization function.
278    */
279   struct GNUNET_TRANSPORT_PluginFunctions *api;
280
281   /**
282    * Short name for the plugin (i.e. "tcp").
283    */
284   char *short_name;
285
286   /**
287    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
288    */
289   char *lib_name;
290
291   /**
292    * List of our known addresses for this transport.
293    */
294   struct OwnAddressList *addresses;
295
296   /**
297    * Environment this transport service is using
298    * for this plugin.
299    */
300   struct GNUNET_TRANSPORT_PluginEnvironment env;
301
302   /**
303    * ID of task that is used to clean up expired addresses.
304    */
305   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
306
307   /**
308    * Set to GNUNET_YES if we need to scrap the existing list of
309    * "addresses" and start fresh when we receive the next address
310    * update from a transport.  Set to GNUNET_NO if we should just add
311    * the new address to the list and wait for the commit call.
312    */
313   int rebuild;
314
315 };
316
317 struct NeighbourList;
318
319 /**
320  * For each neighbour we keep a list of messages
321  * that we still want to transmit to the neighbour.
322  */
323 struct MessageQueue
324 {
325
326   /**
327    * This is a doubly linked list.
328    */
329   struct MessageQueue *next;
330
331   /**
332    * This is a doubly linked list.
333    */
334   struct MessageQueue *prev;
335
336   /**
337    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
338    * stuck together in memory.  Allocated at the end of this struct.
339    */
340   const char *message_buf;
341
342   /**
343    * Size of the message buf
344    */
345   size_t message_buf_size;
346
347   /**
348    * Client responsible for queueing the message;
349    * used to check that a client has no two messages
350    * pending for the same target.  Can be NULL.
351    */
352   struct TransportClient *client;
353
354   /**
355    * Using which specific address should we send this message?
356    */
357   struct ForeignAddressList *specific_address;
358
359   /**
360    * Peer ID of the Neighbour this entry belongs to.
361    */
362   struct GNUNET_PeerIdentity neighbour_id;
363
364   /**
365    * Plugin that we used for the transmission.
366    * NULL until we scheduled a transmission.
367    */
368   struct TransportPlugin *plugin;
369
370   /**
371    * At what time should we fail?
372    */
373   struct GNUNET_TIME_Absolute timeout;
374
375   /**
376    * Internal message of the transport system that should not be
377    * included in the usual SEND-SEND_OK transmission confirmation
378    * traffic management scheme.  Typically, "internal_msg" will
379    * be set whenever "client" is NULL (but it is not strictly
380    * required).
381    */
382   int internal_msg;
383
384   /**
385    * How important is the message?
386    */
387   unsigned int priority;
388
389 };
390
391
392 /**
393  * For a given Neighbour, which plugins are available
394  * to talk to this peer and what are their costs?
395  */
396 struct ReadyList
397 {
398   /**
399    * This is a linked list.
400    */
401   struct ReadyList *next;
402
403   /**
404    * Which of our transport plugins does this entry
405    * represent?
406    */
407   struct TransportPlugin *plugin;
408
409   /**
410    * Transport addresses, latency, and readiness for
411    * this particular plugin.
412    */
413   struct ForeignAddressList *addresses;
414
415   /**
416    * To which neighbour does this ready list belong to?
417    */
418   struct NeighbourList *neighbour;
419
420 };
421
422
423 /**
424  * Entry in linked list of all of our current neighbours.
425  */
426 struct NeighbourList
427 {
428
429   /**
430    * This is a linked list.
431    */
432   struct NeighbourList *next;
433
434   /**
435    * Which of our transports is connected to this peer
436    * and what is their status?
437    */
438   struct ReadyList *plugins;
439
440   /**
441    * Head of list of messages we would like to send to this peer;
442    * must contain at most one message per client.
443    */
444   struct MessageQueue *messages_head;
445
446   /**
447    * Tail of list of messages we would like to send to this peer; must
448    * contain at most one message per client.
449    */
450   struct MessageQueue *messages_tail;
451
452   /**
453    * Context for peerinfo iteration.
454    * NULL after we are done processing peerinfo's information.
455    */
456   struct GNUNET_PEERINFO_IteratorContext *piter;
457
458   /**
459    * Public key for this peer.   Valid only if the respective flag is set below.
460    */
461   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
462
463   /**
464    * Identity of this neighbour.
465    */
466   struct GNUNET_PeerIdentity id;
467
468   /**
469    * ID of task scheduled to run when this peer is about to
470    * time out (will free resources associated with the peer).
471    */
472   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
473
474   /**
475    * ID of task scheduled to run when we should retry transmitting
476    * the head of the message queue.  Actually triggered when the
477    * transmission is timing out (we trigger instantly when we have
478    * a chance of success).
479    */
480   GNUNET_SCHEDULER_TaskIdentifier retry_task;
481
482   /**
483    * How long until we should consider this peer dead
484    * (if we don't receive another message in the
485    * meantime)?
486    */
487   struct GNUNET_TIME_Absolute peer_timeout;
488
489   /**
490    * Tracker for inbound bandwidth.
491    */
492   struct GNUNET_BANDWIDTH_Tracker in_tracker;
493
494   /**
495    * The latency we have seen for this particular address for
496    * this particular peer.  This latency may have been calculated
497    * over multiple transports.  This value reflects how long it took
498    * us to receive a response when SENDING via this particular
499    * transport/neighbour/address combination!
500    *
501    * FIXME: we need to periodically send PINGs to update this
502    * latency (at least more often than the current "huge" (11h?)
503    * update interval).
504    */
505   struct GNUNET_TIME_Relative latency;
506
507   /**
508    * How often has the other peer (recently) violated the
509    * inbound traffic limit?  Incremented by 10 per violation,
510    * decremented by 1 per non-violation (for each
511    * time interval).
512    */
513   unsigned int quota_violation_count;
514
515   /**
516    * DV distance to this peer (1 if no DV is used). 
517    */
518   uint32_t distance;
519
520   /**
521    * Have we seen an PONG from this neighbour in the past (and
522    * not had a disconnect since)?
523    */
524   int received_pong;
525
526   /**
527    * Do we have a valid public key for this neighbour?
528    */
529   int public_key_valid;
530
531 };
532
533 /**
534  * Message used to ask a peer to validate receipt (to check an address
535  * from a HELLO).  
536  */
537 struct TransportPingMessage
538 {
539
540   /**
541    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
542    */
543   struct GNUNET_MessageHeader header;
544
545   /**
546    * Random challenge number (in network byte order).
547    */
548   uint32_t challenge GNUNET_PACKED;
549
550   /**
551    * Who is the intended recipient?
552    */
553   struct GNUNET_PeerIdentity target;
554
555 };
556
557
558 /**
559  * Message used to validate a HELLO.  The challenge is included in the
560  * confirmation to make matching of replies to requests possible.  The
561  * signature signs the original challenge number, our public key, the
562  * sender's address (so that the sender can check that the address we
563  * saw is plausible for him and possibly detect a MiM attack) and a
564  * timestamp (to limit replay).<p>
565  *
566  * This message is followed by the address of the
567  * client that we are observing (which is part of what
568  * is being signed).
569  */
570 struct TransportPongMessage
571 {
572
573   /**
574    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
575    */
576   struct GNUNET_MessageHeader header;
577
578   /**
579    * For padding, always zero.
580    */
581   uint32_t reserved GNUNET_PACKED;
582
583   /**
584    * Signature.
585    */
586   struct GNUNET_CRYPTO_RsaSignature signature;
587
588   /**
589    * What are we signing and why?
590    */
591   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
592
593   /**
594    * Random challenge number (in network byte order).
595    */
596   uint32_t challenge GNUNET_PACKED;
597
598   /**
599    * Who signed this message?
600    */
601   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
602
603   /**
604    * Size of address appended to this message
605    */
606   size_t addrlen;
607
608 };
609
610
611 /**
612  * Linked list of messages to be transmitted to the client.  Each
613  * entry is followed by the actual message.
614  */
615 struct ClientMessageQueueEntry
616 {
617   /**
618    * This is a doubly-linked list.
619    */
620   struct ClientMessageQueueEntry *next;
621
622   /**
623    * This is a doubly-linked list.
624    */
625   struct ClientMessageQueueEntry *prev;
626 };
627
628
629 /**
630  * Client connected to the transport service.
631  */
632 struct TransportClient
633 {
634
635   /**
636    * This is a linked list.
637    */
638   struct TransportClient *next;
639
640   /**
641    * Handle to the client.
642    */
643   struct GNUNET_SERVER_Client *client;
644
645   /**
646    * Linked list of messages yet to be transmitted to
647    * the client.
648    */
649   struct ClientMessageQueueEntry *message_queue_head;
650
651   /**
652    * Tail of linked list of messages yet to be transmitted to the
653    * client.
654    */
655   struct ClientMessageQueueEntry *message_queue_tail;
656
657   /**
658    * Current transmit request handle.
659    */ 
660   struct GNUNET_CONNECTION_TransmitHandle *th;
661
662   /**
663    * Is a call to "transmit_send_continuation" pending?  If so, we
664    * must not free this struct (even if the corresponding client
665    * disconnects) and instead only remove it from the linked list and
666    * set the "client" field to NULL.
667    */
668   int tcs_pending;
669
670   /**
671    * Length of the list of messages pending for this client.
672    */
673   unsigned int message_count;
674
675 };
676
677
678 /**
679  * Entry in map of all HELLOs awaiting validation.
680  */
681 struct ValidationEntry
682 {
683
684   /**
685    * The address, actually a pointer to the end
686    * of this struct.  Do not free!
687    */
688   const void *addr;
689
690   /**
691    * Name of the transport.
692    */
693   char *transport_name;
694
695   /**
696    * The public key of the peer.
697    */
698   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
699
700   /**
701    * ID of task that will clean up this entry if we don't succeed
702    * with the validation first.
703    */
704   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
705
706   /**
707    * At what time did we send this validation?
708    */
709   struct GNUNET_TIME_Absolute send_time;
710
711   /**
712    * Length of addr.
713    */
714   size_t addrlen;
715
716   /**
717    * Challenge number we used.
718    */
719   uint32_t challenge;
720
721 };
722
723
724 /**
725  * Context of currently active requests to peerinfo
726  * for validation of HELLOs.
727  */
728 struct CheckHelloValidatedContext
729 {
730
731   /**
732    * This is a doubly-linked list.
733    */
734   struct CheckHelloValidatedContext *next;
735
736   /**
737    * This is a doubly-linked list.
738    */
739   struct CheckHelloValidatedContext *prev;
740
741   /**
742    * Hello that we are validating.
743    */
744   const struct GNUNET_HELLO_Message *hello;
745
746   /**
747    * Context for peerinfo iteration.
748    * NULL after we are done processing peerinfo's information.
749    */
750   struct GNUNET_PEERINFO_IteratorContext *piter;
751   
752   /**
753    * Was a HELLO known for this peer to peerinfo?
754    */
755   int hello_known;
756
757 };
758
759
760 /**
761  * Our HELLO message.
762  */
763 static struct GNUNET_HELLO_Message *our_hello;
764
765 /**
766  * "version" of "our_hello".  Used to see if a given neighbour has
767  * already been sent the latest version of our HELLO message.
768  */
769 static unsigned int our_hello_version;
770
771 /**
772  * Our public key.
773  */
774 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
775
776 /**
777  * Our identity.
778  */
779 static struct GNUNET_PeerIdentity my_identity;
780
781 /**
782  * Our private key.
783  */
784 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
785
786 /**
787  * Our scheduler.
788  */
789 struct GNUNET_SCHEDULER_Handle *sched;
790
791 /**
792  * Our configuration.
793  */
794 const struct GNUNET_CONFIGURATION_Handle *cfg;
795
796 /**
797  * Linked list of all clients to this service.
798  */
799 static struct TransportClient *clients;
800
801 /**
802  * All loaded plugins.
803  */
804 static struct TransportPlugin *plugins;
805
806 /**
807  * Our server.
808  */
809 static struct GNUNET_SERVER_Handle *server;
810
811 /**
812  * All known neighbours and their HELLOs.
813  */
814 static struct NeighbourList *neighbours;
815
816 /**
817  * Number of neighbours we'd like to have.
818  */
819 static uint32_t max_connect_per_transport;
820
821 /**
822  * Head of linked list.
823  */
824 static struct CheckHelloValidatedContext *chvc_head;
825
826 /**
827  * Tail of linked list.
828  */
829 static struct CheckHelloValidatedContext *chvc_tail;
830
831 /**
832  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
833  * of the given peer that we are currently validating).
834  */
835 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
836
837 /**
838  * Handle for reporting statistics.
839  */
840 static struct GNUNET_STATISTICS_Handle *stats;
841
842
843 /**
844  * The peer specified by the given neighbour has timed-out or a plugin
845  * has disconnected.  We may either need to do nothing (other plugins
846  * still up), or trigger a full disconnect and clean up.  This
847  * function updates our state and do the necessary notifications.
848  * Also notifies our clients that the neighbour is now officially
849  * gone.
850  *
851  * @param n the neighbour list entry for the peer
852  * @param check should we just check if all plugins
853  *        disconnected or must we ask all plugins to
854  *        disconnect?
855  */
856 static void disconnect_neighbour (struct NeighbourList *n, int check);
857
858 /**
859  * Check the ready list for the given neighbour and if a plugin is
860  * ready for transmission (and if we have a message), do so!
861  *
862  * @param neighbour target peer for which to transmit
863  */
864 static void try_transmission_to_peer (struct NeighbourList *neighbour);
865
866
867 /**
868  * Find an entry in the neighbour list for a particular peer.
869  * if sender_address is not specified (NULL) then return the
870  * first matching entry.  If sender_address is specified, then
871  * make sure that the address and address_len also matches.
872  * 
873  * FIXME: This description does not fit the function.
874  *  
875  * @return NULL if not found.
876  */
877 static struct NeighbourList *
878 find_neighbour (const struct GNUNET_PeerIdentity *key)
879 {
880   struct NeighbourList *head = neighbours;
881
882   while ((head != NULL) &&
883         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
884     head = head->next;
885   return head;
886 }
887
888
889 /**
890  * Find an entry in the transport list for a particular transport.
891  *
892  * @return NULL if not found.
893  */
894 static struct TransportPlugin *
895 find_transport (const char *short_name)
896 {
897   struct TransportPlugin *head = plugins;
898   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
899     head = head->next;
900   return head;
901 }
902
903
904 /**
905  * Function called to notify a client about the socket being ready to
906  * queue more data.  "buf" will be NULL and "size" zero if the socket
907  * was closed for writing in the meantime.
908  *
909  * @param cls closure
910  * @param size number of bytes available in buf
911  * @param buf where the callee should write the message
912  * @return number of bytes written to buf
913  */
914 static size_t
915 transmit_to_client_callback (void *cls, size_t size, void *buf)
916 {
917   struct TransportClient *client = cls;
918   struct ClientMessageQueueEntry *q;
919   uint16_t msize;
920   size_t tsize;
921   const struct GNUNET_MessageHeader *msg;
922   char *cbuf;
923
924   client->th = NULL;
925   if (buf == NULL)
926     {
927       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928                   "Transmission to client failed, closing connection.\n");
929       /* fatal error with client, free message queue! */
930       while (NULL != (q = client->message_queue_head))
931         {
932           GNUNET_STATISTICS_update (stats,
933                                     gettext_noop ("# bytes discarded (could not transmit to client)"),
934                                     ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
935                                     GNUNET_NO);      
936           GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
937                                        client->message_queue_tail,
938                                        q);
939           GNUNET_free (q);
940         }
941       client->message_count = 0;
942       return 0;
943     }
944   cbuf = buf;
945   tsize = 0;
946   while (NULL != (q = client->message_queue_head))
947     {
948       msg = (const struct GNUNET_MessageHeader *) &q[1];
949       msize = ntohs (msg->size);
950       if (msize + tsize > size)
951         break;
952 #if DEBUG_TRANSPORT
953       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954                   "Transmitting message of type %u to client.\n",
955                   ntohs (msg->type));
956 #endif
957       GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
958                                    client->message_queue_tail,
959                                    q);
960       memcpy (&cbuf[tsize], msg, msize);
961       tsize += msize;
962       GNUNET_free (q);
963       client->message_count--;
964     }
965   if (NULL != q)
966     {
967       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
968       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
969                                                         msize,
970                                                         GNUNET_TIME_UNIT_FOREVER_REL,
971                                                         &transmit_to_client_callback,
972                                                         client);
973       GNUNET_assert (client->th != NULL);
974     }
975   return tsize;
976 }
977
978
979 /**
980  * Send the specified message to the specified client.  Since multiple
981  * messages may be pending for the same client at a time, this code
982  * makes sure that no message is lost.
983  *
984  * @param client client to transmit the message to
985  * @param msg the message to send
986  * @param may_drop can this message be dropped if the
987  *        message queue for this client is getting far too large?
988  */
989 static void
990 transmit_to_client (struct TransportClient *client,
991                     const struct GNUNET_MessageHeader *msg, int may_drop)
992 {
993   struct ClientMessageQueueEntry *q;
994   uint16_t msize;
995
996   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
997     {
998       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
999                   _
1000                   ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1001                   client->message_count, MAX_PENDING);
1002       /* TODO: call to statistics... */
1003       return;
1004     }
1005   msize = ntohs (msg->size);
1006   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1007   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1008   memcpy (&q[1], msg, msize);
1009   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1010                                      client->message_queue_tail,
1011                                      client->message_queue_tail,
1012                                      q);                                     
1013   client->message_count++;
1014   if (client->th == NULL)
1015     {
1016       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1017                                                         msize,
1018                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1019                                                         &transmit_to_client_callback,
1020                                                         client);
1021       GNUNET_assert (client->th != NULL);
1022     }
1023 }
1024
1025
1026 /**
1027  * Transmit a 'SEND_OK' notification to the given client for the
1028  * given neighbour.
1029  *
1030  * @param client who to notify
1031  * @param n neighbour to notify about
1032  * @param result status code for the transmission request
1033  */
1034 static void
1035 transmit_send_ok (struct TransportClient *client,
1036                   struct NeighbourList *n,
1037                   int result)
1038 {
1039   struct SendOkMessage send_ok_msg;
1040
1041   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1042   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1043   send_ok_msg.success = htonl (result);
1044   send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1045   send_ok_msg.peer = n->id;
1046   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO); 
1047 }
1048
1049
1050 /**
1051  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1052  * upon "completion" of a send request.  This tells the API
1053  * that it is now legal to send another message to the given
1054  * peer.
1055  *
1056  * @param cls closure, identifies the entry on the
1057  *            message queue that was transmitted and the
1058  *            client responsible for queueing the message
1059  * @param target the peer receiving the message
1060  * @param result GNUNET_OK on success, if the transmission
1061  *           failed, we should not tell the client to transmit
1062  *           more messages
1063  */
1064 static void
1065 transmit_send_continuation (void *cls,
1066                             const struct GNUNET_PeerIdentity *target,
1067                             int result)
1068 {
1069   struct MessageQueue *mq = cls;
1070   struct NeighbourList *n;
1071   
1072   GNUNET_STATISTICS_update (stats,
1073                             gettext_noop ("# bytes pending with plugins"),
1074                             - (int64_t) mq->message_buf_size,
1075                             GNUNET_NO);
1076   if (result == GNUNET_OK)
1077     {
1078       GNUNET_STATISTICS_update (stats,
1079                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1080                                 mq->message_buf_size,
1081                                 GNUNET_NO);      
1082     }
1083   else
1084     {
1085       GNUNET_STATISTICS_update (stats,
1086                                 gettext_noop ("# bytes with transmission failure by plugins"),
1087                                 mq->message_buf_size,
1088                                 GNUNET_NO);      
1089     }  
1090   n = find_neighbour(&mq->neighbour_id);
1091   GNUNET_assert (n != NULL);
1092   if (mq->specific_address != NULL)
1093     {
1094       if (result == GNUNET_OK)    
1095         {
1096           mq->specific_address->timeout =
1097             GNUNET_TIME_relative_to_absolute
1098             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1099           if (mq->specific_address->connected != GNUNET_YES)
1100             {
1101               GNUNET_STATISTICS_update (stats,
1102                                         gettext_noop ("# connected addresses"),
1103                                         1,
1104                                         GNUNET_NO);
1105               mq->specific_address->connected = GNUNET_YES;
1106             }
1107         }    
1108       else
1109         {
1110           if (mq->specific_address->connected != GNUNET_NO)
1111             {
1112               GNUNET_STATISTICS_update (stats,
1113                                         gettext_noop ("# connected addresses"),
1114                                         -1,
1115                                         GNUNET_NO);
1116               mq->specific_address->connected = GNUNET_NO;
1117             }
1118         }    
1119       if (! mq->internal_msg) 
1120         mq->specific_address->in_transmit = GNUNET_NO;
1121     }
1122   if (mq->client != NULL)
1123     transmit_send_ok (mq->client, n, result);
1124   GNUNET_free (mq);
1125   try_transmission_to_peer (n);
1126 }
1127
1128
1129 /**
1130  * Find an address in any of the available transports for
1131  * the given neighbour that would be good for message
1132  * transmission.  This is essentially the transport selection
1133  * routine.
1134  *
1135  * @param neighbour for whom to select an address
1136  * @return selected address, NULL if we have none
1137  */
1138 struct ForeignAddressList *
1139 find_ready_address(struct NeighbourList *neighbour)
1140 {
1141   struct ReadyList *head = neighbour->plugins;
1142   struct ForeignAddressList *addresses;
1143   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1144   struct ForeignAddressList *best_address;
1145
1146   best_address = NULL;
1147   while (head != NULL)
1148     {
1149       addresses = head->addresses;
1150       while (addresses != NULL)
1151         {
1152           if ( (addresses->timeout.value < now.value) && 
1153                (addresses->connected == GNUNET_YES) )
1154             {
1155 #if DEBUG_TRANSPORT
1156               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157                           "Marking long-time inactive connection to `%4s' as down.\n",
1158                           GNUNET_i2s (&neighbour->id));
1159 #endif
1160               GNUNET_STATISTICS_update (stats,
1161                                         gettext_noop ("# connected addresses"),
1162                                         -1,
1163                                         GNUNET_NO);
1164               addresses->connected = GNUNET_NO;
1165             }
1166           addresses = addresses->next;
1167         }
1168
1169       addresses = head->addresses;
1170       while (addresses != NULL)
1171         {
1172           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173                       "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1174                       GNUNET_a2s (addresses->addr,
1175                                   addresses->addrlen),
1176                       GNUNET_i2s (&neighbour->id),
1177                       addresses->connected,
1178                       addresses->in_transmit,
1179                       addresses->validated,
1180                       addresses->connect_attempts,
1181                       (unsigned long long) addresses->timeout.value,
1182                       (unsigned int) addresses->distance);
1183           if ( ( (best_address == NULL) || 
1184                  (addresses->connected == GNUNET_YES) ||
1185                  (best_address->connected == GNUNET_NO) ) &&
1186                (addresses->in_transmit == GNUNET_NO) &&
1187                ( (best_address == NULL) || 
1188                  (addresses->latency.value < best_address->latency.value)) )
1189             best_address = addresses;            
1190           /* FIXME: also give lower-latency addresses that are not
1191              connected a chance some times... */
1192           addresses = addresses->next;
1193         }
1194       head = head->next;
1195     }
1196   if (best_address != NULL)
1197     {
1198 #if DEBUG_TRANSPORT
1199       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1200                   "Best address found has latency of %llu ms.\n",
1201                   best_address->latency.value);
1202 #endif
1203     }
1204   else
1205     {
1206       GNUNET_STATISTICS_update (stats,
1207                                 gettext_noop ("# transmission attempts failed (no address)"),
1208                                 1,
1209                                 GNUNET_NO);
1210     }
1211   return best_address;
1212
1213 }
1214
1215
1216 /**
1217  * We should re-try transmitting to the given peer,
1218  * hopefully we've learned something in the meantime.
1219  */
1220 static void
1221 retry_transmission_task (void *cls,
1222                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1223 {
1224   struct NeighbourList *n = cls;
1225
1226   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1227   try_transmission_to_peer (n);
1228 }
1229
1230
1231 /**
1232  * Check the ready list for the given neighbour and if a plugin is
1233  * ready for transmission (and if we have a message), do so!
1234  *
1235  * @param neighbour target peer for which to transmit
1236  */
1237 static void
1238 try_transmission_to_peer (struct NeighbourList *neighbour)
1239 {
1240   struct ReadyList *rl;
1241   struct MessageQueue *mq;
1242   struct GNUNET_TIME_Relative timeout;
1243   ssize_t ret;
1244
1245   if (neighbour->messages_head == NULL)
1246     {
1247       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1248                   "Transmission queue for `%4s' is empty\n",
1249                   GNUNET_i2s (&neighbour->id));
1250       return;                     /* nothing to do */
1251     }
1252   rl = NULL;
1253   mq = neighbour->messages_head;
1254   /* FIXME: support bi-directional use of TCP */
1255   if (mq->specific_address == NULL)
1256     {
1257       mq->specific_address = find_ready_address(neighbour); 
1258       GNUNET_STATISTICS_update (stats,
1259                                 gettext_noop ("# transport selected peer address freely"),
1260                                 1,
1261                                 GNUNET_NO); 
1262     }
1263   if (mq->specific_address == NULL)
1264     {
1265       GNUNET_STATISTICS_update (stats,
1266                                 gettext_noop ("# transport failed to selected peer address"),
1267                                 1,
1268                                 GNUNET_NO); 
1269       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1270       if (timeout.value == 0)
1271         {
1272 #if DEBUG_TRANSPORT
1273           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1274                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1275                       mq->message_buf_size,
1276                       GNUNET_i2s (&mq->neighbour_id));
1277 #endif
1278           GNUNET_STATISTICS_update (stats,
1279                                     gettext_noop ("# bytes in message queue for other peers"),
1280                                     - (int64_t) mq->message_buf_size,
1281                                     GNUNET_NO);
1282           GNUNET_STATISTICS_update (stats,
1283                                     gettext_noop ("# bytes discarded (no destination address available)"),
1284                                     mq->message_buf_size,
1285                                     GNUNET_NO);      
1286           if (mq->client != NULL)
1287             transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1288           GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1289                                        neighbour->messages_tail,
1290                                        mq);
1291           GNUNET_free (mq);
1292           return;               /* nobody ready */ 
1293         }
1294       GNUNET_STATISTICS_update (stats,
1295                                 gettext_noop ("# message delivery deferred (no address)"),
1296                                 1,
1297                                 GNUNET_NO);
1298       if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1299         GNUNET_SCHEDULER_cancel (sched,
1300                                  neighbour->retry_task);
1301       neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1302                                                             timeout,
1303                                                             &retry_transmission_task,
1304                                                             neighbour);
1305 #if DEBUG_TRANSPORT
1306       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1308                   mq->message_buf_size,
1309                   GNUNET_i2s (&mq->neighbour_id),
1310                   timeout.value);
1311 #endif
1312       /* FIXME: might want to trigger peerinfo lookup here
1313          (unless that's already pending...) */
1314       return;    
1315     }
1316   GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1317                                neighbour->messages_tail,
1318                                mq);
1319   if (mq->specific_address->connected == GNUNET_NO)
1320     mq->specific_address->connect_attempts++;
1321   rl = mq->specific_address->ready_list;
1322   mq->plugin = rl->plugin;
1323   if (!mq->internal_msg)
1324     mq->specific_address->in_transmit = GNUNET_YES;
1325 #if DEBUG_TRANSPORT
1326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1328               mq->message_buf_size,
1329               GNUNET_i2s (&neighbour->id), 
1330               GNUNET_a2s (mq->specific_address->addr,
1331                           mq->specific_address->addrlen),
1332               rl->plugin->short_name);
1333 #endif
1334   GNUNET_STATISTICS_update (stats,
1335                             gettext_noop ("# bytes in message queue for other peers"),
1336                             - (int64_t) mq->message_buf_size,
1337                             GNUNET_NO);
1338   GNUNET_STATISTICS_update (stats,
1339                             gettext_noop ("# bytes pending with plugins"),
1340                             mq->message_buf_size,
1341                             GNUNET_NO);
1342   ret = rl->plugin->api->send (rl->plugin->api->cls,
1343                                &mq->neighbour_id,
1344                                mq->message_buf,
1345                                mq->message_buf_size,
1346                                mq->priority,
1347                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1348                                mq->specific_address->addr,
1349                                mq->specific_address->addrlen,
1350                                GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1351                                &transmit_send_continuation, mq);
1352   if (ret == -1)
1353     {
1354       /* failure, but 'send' would not call continuation in this case,
1355          so we need to do it here! */
1356       transmit_send_continuation (mq, 
1357                                   &mq->neighbour_id,
1358                                   GNUNET_SYSERR);
1359     }
1360 }
1361
1362
1363 /**
1364  * Send the specified message to the specified peer.
1365  *
1366  * @param client source of the transmission request (can be NULL)
1367  * @param peer_address ForeignAddressList where we should send this message
1368  * @param priority how important is the message
1369  * @param timeout how long do we have to transmit?
1370  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1371  * @param message_buf_size total size of all messages in message_buf
1372  * @param is_internal is this an internal message; these are pre-pended and
1373  *                    also do not count for plugins being "ready" to transmit
1374  * @param neighbour handle to the neighbour for transmission
1375  */
1376 static void
1377 transmit_to_peer (struct TransportClient *client,
1378                   struct ForeignAddressList *peer_address,
1379                   unsigned int priority,
1380                   struct GNUNET_TIME_Relative timeout,
1381                   const char *message_buf,
1382                   size_t message_buf_size,
1383                   int is_internal, struct NeighbourList *neighbour)
1384 {
1385   struct MessageQueue *mq;
1386
1387 #if EXTRA_CHECKS
1388   if (client != NULL)
1389     {
1390       /* check for duplicate submission */
1391       mq = neighbour->messages_head;
1392       while (NULL != mq)
1393         {
1394           if (mq->client == client)
1395             {
1396               /* client transmitted to same peer twice
1397                  before getting SEND_OK! */
1398               GNUNET_break (0);
1399               return;
1400             }
1401           mq = mq->next;
1402         }
1403     }
1404 #endif
1405   GNUNET_STATISTICS_update (stats,
1406                             gettext_noop ("# bytes in message queue for other peers"),
1407                             message_buf_size,
1408                             GNUNET_NO);
1409   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1410   mq->specific_address = peer_address;
1411   mq->client = client;
1412   memcpy (&mq[1], message_buf, message_buf_size);
1413   mq->message_buf = (const char*) &mq[1];
1414   mq->message_buf_size = message_buf_size;
1415   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1416   mq->internal_msg = is_internal;
1417   mq->priority = priority;
1418   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1419   if (is_internal)    
1420     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1421                                  neighbour->messages_tail,
1422                                  mq);
1423   else
1424     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1425                                        neighbour->messages_tail,
1426                                        neighbour->messages_tail,
1427                                        mq);
1428   try_transmission_to_peer (neighbour);
1429 }
1430
1431
1432 /**
1433  * FIXME: document.
1434  */
1435 struct GeneratorContext
1436 {
1437   struct TransportPlugin *plug_pos;
1438   struct OwnAddressList *addr_pos;
1439   struct GNUNET_TIME_Absolute expiration;
1440 };
1441
1442
1443 /**
1444  * FIXME: document.
1445  */
1446 static size_t
1447 address_generator (void *cls, size_t max, void *buf)
1448 {
1449   struct GeneratorContext *gc = cls;
1450   size_t ret;
1451
1452   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1453     {
1454       gc->plug_pos = gc->plug_pos->next;
1455       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1456     }
1457   if (NULL == gc->plug_pos)
1458     {
1459
1460       return 0;
1461     }
1462   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1463                                   gc->expiration,
1464                                   gc->addr_pos->addr,
1465                                   gc->addr_pos->addrlen, buf, max);
1466   gc->addr_pos = gc->addr_pos->next;
1467   return ret;
1468 }
1469
1470
1471 /**
1472  * Construct our HELLO message from all of the addresses of
1473  * all of the transports.
1474  */
1475 static void
1476 refresh_hello ()
1477 {
1478   struct GNUNET_HELLO_Message *hello;
1479   struct TransportClient *cpos;
1480   struct NeighbourList *npos;
1481   struct GeneratorContext gc;
1482
1483   gc.plug_pos = plugins;
1484   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1485   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1486   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1487 #if DEBUG_TRANSPORT
1488   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1489               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1490 #endif
1491   GNUNET_STATISTICS_update (stats,
1492                             gettext_noop ("# refreshed my HELLO"),
1493                             1,
1494                             GNUNET_NO);
1495   cpos = clients;
1496   while (cpos != NULL)
1497     {
1498       transmit_to_client (cpos,
1499                           (const struct GNUNET_MessageHeader *) hello,
1500                           GNUNET_NO);
1501       cpos = cpos->next;
1502     }
1503
1504   GNUNET_free_non_null (our_hello);
1505   our_hello = hello;
1506   our_hello_version++;
1507   GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1508   npos = neighbours;
1509   while (npos != NULL)
1510     {
1511 #if DEBUG_TRANSPORT
1512       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1513                   "Transmitting updated `%s' to neighbour `%4s'\n",
1514                   "HELLO", GNUNET_i2s (&npos->id));
1515 #endif
1516       GNUNET_STATISTICS_update (stats,
1517                                 gettext_noop ("# transmitted my HELLO to other peers"),
1518                                 1,
1519                                 GNUNET_NO);
1520       transmit_to_peer (NULL, NULL, 0,
1521                         HELLO_ADDRESS_EXPIRATION,
1522                         (const char *) our_hello, 
1523                         GNUNET_HELLO_size(our_hello),
1524                         GNUNET_NO, npos);
1525       npos = npos->next;
1526     }
1527 }
1528
1529
1530 /**
1531  * Task used to clean up expired addresses for a plugin.
1532  *
1533  * @param cls closure
1534  * @param tc context
1535  */
1536 static void
1537 expire_address_task (void *cls,
1538                      const struct GNUNET_SCHEDULER_TaskContext *tc);
1539
1540
1541 /**
1542  * Update the list of addresses for this plugin,
1543  * expiring those that are past their expiration date.
1544  *
1545  * @param plugin addresses of which plugin should be recomputed?
1546  * @param fresh set to GNUNET_YES if a new address was added
1547  *        and we need to regenerate the HELLO even if nobody
1548  *        expired
1549  */
1550 static void
1551 update_addresses (struct TransportPlugin *plugin, int fresh)
1552 {
1553   struct GNUNET_TIME_Relative min_remaining;
1554   struct GNUNET_TIME_Relative remaining;
1555   struct GNUNET_TIME_Absolute now;
1556   struct OwnAddressList *pos;
1557   struct OwnAddressList *prev;
1558   struct OwnAddressList *next;
1559   int expired;
1560
1561   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1562     GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1563   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1564   now = GNUNET_TIME_absolute_get ();
1565   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1566   expired = GNUNET_NO;
1567   prev = NULL;
1568   pos = plugin->addresses;
1569   while (pos != NULL)
1570     {
1571       next = pos->next;
1572       if (pos->expires.value < now.value)
1573         {
1574           expired = GNUNET_YES;
1575           if (prev == NULL)
1576             plugin->addresses = pos->next;
1577           else
1578             prev->next = pos->next;
1579
1580           
1581           GNUNET_free (pos);
1582         }
1583       else
1584         {
1585           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1586           if (remaining.value < min_remaining.value)
1587             min_remaining = remaining;
1588           prev = pos;
1589         }
1590       pos = next;
1591     }
1592
1593   if (expired || fresh)
1594     refresh_hello ();
1595   if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1596     plugin->address_update_task
1597       = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1598                                       min_remaining,
1599                                       &expire_address_task, plugin);
1600
1601 }
1602
1603
1604 /**
1605  * Task used to clean up expired addresses for a plugin.
1606  *
1607  * @param cls closure
1608  * @param tc context
1609  */
1610 static void
1611 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1612 {
1613   struct TransportPlugin *plugin = cls;
1614   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1615   update_addresses (plugin, GNUNET_NO);
1616 }
1617
1618
1619 /**
1620  * Function that must be called by each plugin to notify the
1621  * transport service about the addresses under which the transport
1622  * provided by the plugin can be reached.
1623  *
1624  * @param cls closure
1625  * @param name name of the transport that generated the address
1626  * @param addr one of the addresses of the host, NULL for the last address
1627  *        the specific address format depends on the transport
1628  * @param addrlen length of the address
1629  * @param expires when should this address automatically expire?
1630  */
1631 static void
1632 plugin_env_notify_address (void *cls,
1633                            const char *name,
1634                            const void *addr,
1635                            size_t addrlen,
1636                            struct GNUNET_TIME_Relative expires)
1637 {
1638   struct TransportPlugin *p = cls;
1639   struct OwnAddressList *al;
1640   struct GNUNET_TIME_Absolute abex;
1641
1642   abex = GNUNET_TIME_relative_to_absolute (expires);
1643   GNUNET_assert (p == find_transport (name));
1644
1645   al = p->addresses;
1646   while (al != NULL)
1647     {
1648       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1649         {
1650           if (al->expires.value < abex.value)
1651             al->expires = abex;
1652           return;
1653         }
1654       al = al->next;
1655     }
1656
1657   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1658   al->addr = &al[1];
1659   al->next = p->addresses;
1660   p->addresses = al;
1661   al->expires = abex;
1662   al->addrlen = addrlen;
1663   memcpy (&al[1], addr, addrlen);
1664   update_addresses (p, GNUNET_YES);
1665 }
1666
1667
1668 /**
1669  * Notify all of our clients about a peer connecting.
1670  */
1671 static void
1672 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1673                         struct GNUNET_TIME_Relative latency,
1674                         uint32_t distance)
1675 {
1676   struct ConnectInfoMessage cim;
1677   struct TransportClient *cpos;
1678
1679 #if DEBUG_TRANSPORT
1680   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1681               "Notifying clients about connection from `%s'\n",
1682               GNUNET_i2s (peer));
1683 #endif
1684   GNUNET_STATISTICS_update (stats,
1685                             gettext_noop ("# peers connected"),
1686                             1,
1687                             GNUNET_NO);
1688   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1689   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1690   cim.distance = htonl (distance);
1691   cim.latency = GNUNET_TIME_relative_hton (latency);
1692   memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1693   cpos = clients;
1694   while (cpos != NULL)
1695     {
1696       transmit_to_client (cpos, &cim.header, GNUNET_NO);
1697       cpos = cpos->next;
1698     }
1699 }
1700
1701
1702 /**
1703  * Notify all of our clients about a peer disconnecting.
1704  */
1705 static void
1706 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1707 {
1708   struct DisconnectInfoMessage dim;
1709   struct TransportClient *cpos;
1710
1711 #if DEBUG_TRANSPORT
1712   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1713               "Notifying clients about lost connection to `%s'\n",
1714               GNUNET_i2s (peer));
1715 #endif
1716   GNUNET_STATISTICS_update (stats,
1717                             gettext_noop ("# peers connected"),
1718                             -1,
1719                             GNUNET_NO);
1720   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1721   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1722   dim.reserved = htonl (0);
1723   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1724   cpos = clients;
1725   while (cpos != NULL)
1726     {
1727       transmit_to_client (cpos, &dim.header, GNUNET_NO);
1728       cpos = cpos->next;
1729     }
1730 }
1731
1732
1733 /**
1734  * Find a ForeignAddressList entry for the given neighbour
1735  * that matches the given address and transport.
1736  *
1737  * @param neighbour which peer we care about
1738  * @param tname name of the transport plugin
1739  * @param addr binary address
1740  * @param addrlen length of addr
1741  * @return NULL if no such entry exists
1742  */
1743 static struct ForeignAddressList *
1744 find_peer_address(struct NeighbourList *neighbour,
1745                   const char *tname,
1746                   const char *addr,
1747                   size_t addrlen)
1748 {
1749   struct ReadyList *head;
1750   struct ForeignAddressList *address_head;
1751
1752   head = neighbour->plugins;
1753   while (head != NULL)
1754     {
1755       if (0 == strcmp (tname, head->plugin->short_name))
1756         break;
1757       head = head->next;
1758     }
1759   if (head == NULL)
1760     return NULL;
1761
1762   address_head = head->addresses;
1763   while ( (address_head != NULL) &&
1764           ( (address_head->addrlen != addrlen) ||
1765             (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1766     address_head = address_head->next;
1767   return address_head;
1768 }
1769
1770
1771 /**
1772  * Get the peer address struct for the given neighbour and
1773  * address.  If it doesn't yet exist, create it.
1774  *
1775  * @param neighbour which peer we care about
1776  * @param tname name of the transport plugin
1777  * @param addr binary address
1778  * @param addrlen length of addr
1779  * @return NULL if we do not have a transport plugin for 'tname'
1780  */
1781 static struct ForeignAddressList *
1782 add_peer_address (struct NeighbourList *neighbour,
1783                   const char *tname,
1784                   const char *addr, 
1785                   size_t addrlen)
1786 {
1787   struct ReadyList *head;
1788   struct ForeignAddressList *ret;
1789
1790   ret = find_peer_address (neighbour, tname, addr, addrlen);
1791   if (ret != NULL)
1792     return ret;
1793   head = neighbour->plugins;
1794   while (head != NULL)
1795     {
1796       if (0 == strcmp (tname, head->plugin->short_name))
1797         break;
1798       head = head->next;
1799     }
1800   if (head == NULL)
1801     return NULL;
1802   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1803   ret->addr = (const char*) &ret[1];
1804   memcpy (&ret[1], addr, addrlen);
1805   ret->addrlen = addrlen;
1806   ret->expires = GNUNET_TIME_relative_to_absolute
1807     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1808   ret->latency = GNUNET_TIME_relative_get_forever();
1809   ret->distance = -1;
1810   ret->timeout = GNUNET_TIME_relative_to_absolute
1811     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); 
1812   ret->ready_list = head;
1813   ret->next = head->addresses;
1814   head->addresses = ret;
1815   return ret;
1816 }
1817
1818
1819 /**
1820  * Closure for 'add_validated_address'.
1821  */
1822 struct AddValidatedAddressContext
1823 {
1824   /**
1825    * Entry that has been validated.
1826    */
1827   const struct ValidationEntry *ve;
1828
1829   /**
1830    * Flag set after we have added the address so
1831    * that we terminate the iteration next time.
1832    */
1833   int done;
1834 };
1835
1836
1837 /**
1838  * Callback function used to fill a buffer of max bytes with a list of
1839  * addresses in the format used by HELLOs.  Should use
1840  * "GNUNET_HELLO_add_address" as a helper function.
1841  *
1842  * @param cls the 'struct AddValidatedAddressContext' with the validated address
1843  * @param max maximum number of bytes that can be written to buf
1844  * @param buf where to write the address information
1845  * @return number of bytes written, 0 to signal the
1846  *         end of the iteration.
1847  */
1848 static size_t
1849 add_validated_address (void *cls,
1850                        size_t max, void *buf)
1851 {
1852   struct AddValidatedAddressContext *avac = cls;
1853   const struct ValidationEntry *ve = avac->ve;
1854
1855   if (GNUNET_YES == avac->done)
1856     return 0;
1857   avac->done = GNUNET_YES;
1858   return GNUNET_HELLO_add_address (ve->transport_name,
1859                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1860                                    ve->addr,
1861                                    ve->addrlen,
1862                                    buf,
1863                                    max);
1864 }
1865
1866
1867
1868 /**
1869  * Closure for 'check_address_exists'.
1870  */
1871 struct CheckAddressExistsClosure
1872 {
1873   /**
1874    * Address to check for.
1875    */
1876   const void *addr;
1877
1878   /**
1879    * Name of the transport.
1880    */
1881   const char *tname;
1882
1883   /**
1884    * Length of addr.
1885    */
1886   size_t addrlen;
1887
1888   /**
1889    * Set to GNUNET_YES if the address exists.
1890    */
1891   int exists;
1892 };
1893
1894
1895 /**
1896  * Iterator over hash map entries.  Checks if the given
1897  * validation entry is for the same address as what is given
1898  * in the closure.
1899  *
1900  * @param cls the 'struct CheckAddressExistsClosure*'
1901  * @param key current key code (ignored)
1902  * @param value value in the hash map ('struct ValidationEntry')
1903  * @return GNUNET_YES if we should continue to
1904  *         iterate (mismatch), GNUNET_NO if not (entry matched)
1905  */
1906 static int
1907 check_address_exists (void *cls,
1908                       const GNUNET_HashCode * key,
1909                       void *value)
1910 {
1911   struct CheckAddressExistsClosure *caec = cls;
1912   struct ValidationEntry *ve = value;
1913   if ( (0 == strcmp (caec->tname,
1914                      ve->transport_name)) &&
1915        (caec->addrlen == ve->addrlen) &&
1916        (0 == memcmp (caec->addr,
1917                      ve->addr,
1918                      caec->addrlen)) )
1919     {
1920       caec->exists = GNUNET_YES;
1921       return GNUNET_NO;
1922     }
1923   return GNUNET_YES;
1924 }
1925
1926
1927 /**
1928  * HELLO validation cleanup task (validation failed).
1929  *
1930  * @param cls the 'struct ValidationEntry' that failed
1931  * @param tc scheduler context (unused)
1932  */
1933 static void
1934 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1935 {
1936   struct ValidationEntry *va = cls;
1937   struct GNUNET_PeerIdentity pid;
1938
1939   GNUNET_STATISTICS_update (stats,
1940                             gettext_noop ("# address validation timeouts"),
1941                             1,
1942                             GNUNET_NO);
1943   GNUNET_CRYPTO_hash (&va->publicKey,
1944                       sizeof (struct
1945                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1946                       &pid.hashPubKey);
1947   GNUNET_CONTAINER_multihashmap_remove (validation_map,
1948                                         &pid.hashPubKey,
1949                                         va);
1950   GNUNET_free (va->transport_name);
1951   GNUNET_free (va);
1952 }
1953
1954
1955 static void
1956 neighbour_timeout_task (void *cls,
1957                        const struct GNUNET_SCHEDULER_TaskContext *tc)
1958 {
1959   struct NeighbourList *n = cls;
1960
1961 #if DEBUG_TRANSPORT
1962   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1963               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1964 #endif
1965   GNUNET_STATISTICS_update (stats,
1966                             gettext_noop ("# disconnects due to timeout"),
1967                             1,
1968                             GNUNET_NO);
1969   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1970   disconnect_neighbour (n, GNUNET_NO);
1971 }
1972
1973
1974 /**
1975  * Schedule the job that will cause us to send a PING to the
1976  * foreign address to evaluate its validity and latency.
1977  *
1978  * @param fal address to PING
1979  */
1980 static void
1981 schedule_next_ping (struct ForeignAddressList *fal);
1982
1983
1984 /**
1985  * Add the given address to the list of foreign addresses
1986  * available for the given peer (check for duplicates).
1987  *
1988  * @param cls the respective 'struct NeighbourList' to update
1989  * @param tname name of the transport
1990  * @param expiration expiration time
1991  * @param addr the address
1992  * @param addrlen length of the address
1993  * @return GNUNET_OK (always)
1994  */
1995 static int
1996 add_to_foreign_address_list (void *cls,
1997                              const char *tname,
1998                              struct GNUNET_TIME_Absolute expiration,
1999                              const void *addr, size_t addrlen)
2000 {
2001   struct NeighbourList *n = cls;
2002   struct ForeignAddressList *fal;
2003   int try;
2004
2005   GNUNET_STATISTICS_update (stats,
2006                             gettext_noop ("# valid peer addresses returned by peerinfo"),
2007                             1,
2008                             GNUNET_NO);      
2009   try = GNUNET_NO;
2010   fal = find_peer_address (n, tname, addr, addrlen);
2011   if (fal == NULL)
2012     {
2013 #if DEBUG_TRANSPORT
2014       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2015                   "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2016                   GNUNET_a2s (addr, addrlen),
2017                   tname,
2018                   GNUNET_i2s (&n->id),
2019                   expiration.value);
2020 #endif
2021       fal = add_peer_address (n, tname, addr, addrlen);
2022       if (fal == NULL)
2023         {
2024           GNUNET_STATISTICS_update (stats,
2025                                     gettext_noop ("# previously validated addresses lacking transport"),
2026                                     1,
2027                                     GNUNET_NO); 
2028         }
2029       else
2030         {
2031           fal->expires = GNUNET_TIME_absolute_max (expiration,
2032                                                    fal->expires);
2033           schedule_next_ping (fal);
2034         }
2035       try = GNUNET_YES;
2036     }
2037   else
2038     {
2039       fal->expires = GNUNET_TIME_absolute_max (expiration,
2040                                                fal->expires);
2041     }
2042   if (fal == NULL)
2043     {
2044       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2045                   "Failed to add new address for `%4s'\n",
2046                   GNUNET_i2s (&n->id));
2047       return GNUNET_OK;
2048     }
2049   if (fal->validated == GNUNET_NO)
2050     {
2051       fal->validated = GNUNET_YES;  
2052       GNUNET_STATISTICS_update (stats,
2053                                 gettext_noop ("# peer addresses considered valid"),
2054                                 1,
2055                                 GNUNET_NO);      
2056     }
2057   if (try == GNUNET_YES)
2058     {
2059       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2060                   "Have new addresses, will try to trigger transmissions.\n");
2061       try_transmission_to_peer (n);
2062     }
2063   return GNUNET_OK;
2064 }
2065
2066
2067 /**
2068  * Add addresses in validated HELLO "h" to the set of addresses
2069  * we have for this peer.
2070  *
2071  * @param cls closure ('struct NeighbourList*')
2072  * @param peer id of the peer, NULL for last call
2073  * @param h hello message for the peer (can be NULL)
2074  * @param trust amount of trust we have in the peer (not used)
2075  */
2076 static void
2077 add_hello_for_peer (void *cls,
2078                     const struct GNUNET_PeerIdentity *peer,
2079                     const struct GNUNET_HELLO_Message *h, 
2080                     uint32_t trust)
2081 {
2082   struct NeighbourList *n = cls;
2083
2084   if (peer == NULL)
2085     {
2086       n->piter = NULL;
2087       return;
2088     } 
2089   if (h == NULL)
2090     return; /* no HELLO available */
2091 #if DEBUG_TRANSPORT
2092   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2093               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2094               "HELLO",
2095               GNUNET_i2s (peer));
2096 #endif
2097   if (GNUNET_YES != n->public_key_valid)
2098     {
2099       GNUNET_HELLO_get_key (h, &n->publicKey);
2100       n->public_key_valid = GNUNET_YES;
2101     }
2102   GNUNET_HELLO_iterate_addresses (h,
2103                                   GNUNET_NO,
2104                                   &add_to_foreign_address_list,
2105                                   n);
2106 }
2107
2108
2109 /**
2110  * Create a fresh entry in our neighbour list for the given peer.
2111  * Will try to transmit our current HELLO to the new neighbour.
2112  *
2113  * @param peer the peer for which we create the entry
2114  * @return the new neighbour list entry
2115  */
2116 static struct NeighbourList *
2117 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2118 {
2119   struct NeighbourList *n;
2120   struct TransportPlugin *tp;
2121   struct ReadyList *rl;
2122
2123   GNUNET_assert (our_hello != NULL);
2124   GNUNET_STATISTICS_update (stats,
2125                             gettext_noop ("# active neighbours"),
2126                             1,
2127                             GNUNET_NO);
2128   n = GNUNET_malloc (sizeof (struct NeighbourList));
2129   n->next = neighbours;
2130   neighbours = n;
2131   n->id = *peer;
2132   n->peer_timeout =
2133     GNUNET_TIME_relative_to_absolute
2134     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2135   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2136                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2137                                  MAX_BANDWIDTH_CARRY_S);
2138   tp = plugins;
2139   while (tp != NULL)
2140     {
2141       if (tp->api->send != NULL)
2142         {
2143           rl = GNUNET_malloc (sizeof (struct ReadyList));
2144           rl->neighbour = n;
2145           rl->next = n->plugins;
2146           n->plugins = rl;
2147           rl->plugin = tp;
2148           rl->addresses = NULL;
2149         }
2150       tp = tp->next;
2151     }
2152   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2153   n->distance = -1;
2154   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2155                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2156                                                   &neighbour_timeout_task, n);
2157   n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2158                                       0, GNUNET_TIME_UNIT_FOREVER_REL,
2159                                       &add_hello_for_peer, n);
2160   transmit_to_peer (NULL, NULL, 0,
2161                     HELLO_ADDRESS_EXPIRATION,
2162                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2163                     GNUNET_NO, n);
2164   return n;
2165 }
2166
2167
2168 /**
2169  * Send periodic PING messages to a give foreign address.
2170  *
2171  * @param cls our 'struct PeriodicValidationContext*'
2172  * @param tc task context
2173  */
2174 static void 
2175 send_periodic_ping (void *cls, 
2176                     const struct GNUNET_SCHEDULER_TaskContext *tc)
2177 {
2178   struct ForeignAddressList *peer_address = cls;
2179   struct TransportPlugin *tp;
2180   struct ValidationEntry *va;
2181   struct NeighbourList *neighbour;
2182   struct TransportPingMessage ping;
2183   struct CheckAddressExistsClosure caec;
2184   char * message_buf;
2185   uint16_t hello_size;
2186   size_t tsize;
2187
2188   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2189   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2190     return; 
2191   tp = peer_address->ready_list->plugin;
2192   neighbour = peer_address->ready_list->neighbour;
2193   if (GNUNET_YES != neighbour->public_key_valid)
2194     {
2195       /* no public key yet, try again later */
2196       schedule_next_ping (peer_address);     
2197       return;
2198     }
2199   caec.addr = peer_address->addr;
2200   caec.addrlen = peer_address->addrlen;
2201   caec.tname = tp->short_name;
2202   caec.exists = GNUNET_NO;
2203   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2204                                          &check_address_exists,
2205                                          &caec);
2206   if (caec.exists == GNUNET_YES)
2207     {
2208       /* During validation attempts we will likely trigger the other
2209          peer trying to validate our address which in turn will cause
2210          it to send us its HELLO, so we expect to hit this case rather
2211          frequently.  Only print something if we are very verbose. */
2212 #if DEBUG_TRANSPORT > 1
2213       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2214                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2215                   GNUNET_a2s (peer_address->addr,
2216                               peer_address->addrlen),
2217                   tp->short_name,
2218                   GNUNET_i2s (&neighbour->id));
2219 #endif
2220       schedule_next_ping (peer_address);     
2221       return;
2222     }
2223   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2224   va->transport_name = GNUNET_strdup (tp->short_name);
2225   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2226                                             (unsigned int) -1);
2227   va->send_time = GNUNET_TIME_absolute_get();
2228   va->addr = (const void*) &va[1];
2229   memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2230   va->addrlen = peer_address->addrlen;
2231
2232   memcpy(&va->publicKey,
2233          &neighbour->publicKey, 
2234          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2235
2236   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2237                                                    HELLO_VERIFICATION_TIMEOUT,
2238                                                    &timeout_hello_validation,
2239                                                    va);
2240   GNUNET_CONTAINER_multihashmap_put (validation_map,
2241                                      &neighbour->id.hashPubKey,
2242                                      va,
2243                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2244   hello_size = GNUNET_HELLO_size(our_hello);
2245   tsize = sizeof(struct TransportPingMessage) + hello_size;
2246   message_buf = GNUNET_malloc(tsize);
2247   ping.challenge = htonl(va->challenge);
2248   ping.header.size = htons(sizeof(struct TransportPingMessage));
2249   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2250   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2251   memcpy(message_buf, our_hello, hello_size);
2252   memcpy(&message_buf[hello_size],
2253          &ping,
2254          sizeof(struct TransportPingMessage));
2255 #if DEBUG_TRANSPORT_REVALIDATION
2256   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2257               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2258               GNUNET_a2s (peer_address->addr,
2259                           peer_address->addrlen),
2260               tp->short_name,
2261               GNUNET_i2s (&neighbour->id),
2262               "HELLO", hello_size,
2263               "PING", sizeof (struct TransportPingMessage));
2264 #endif
2265   GNUNET_STATISTICS_update (stats,
2266                             gettext_noop ("# PING messages sent for re-validation"),
2267                             1,
2268                             GNUNET_NO);
2269   transmit_to_peer (NULL, peer_address,
2270                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2271                     HELLO_VERIFICATION_TIMEOUT,
2272                     message_buf, tsize,
2273                     GNUNET_YES, neighbour);
2274   GNUNET_free(message_buf);
2275   schedule_next_ping (peer_address);
2276 }
2277
2278
2279 /**
2280  * Schedule the job that will cause us to send a PING to the
2281  * foreign address to evaluate its validity and latency.
2282  *
2283  * @param fal address to PING
2284  */
2285 static void
2286 schedule_next_ping (struct ForeignAddressList *fal)
2287 {
2288   struct GNUNET_TIME_Relative delay;
2289
2290   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2291     return;
2292   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2293   delay.value /= 2; /* do before expiration */
2294   delay = GNUNET_TIME_relative_min (delay,
2295                                     LATENCY_EVALUATION_MAX_DELAY);
2296   if (GNUNET_YES != fal->estimated)
2297     {
2298       delay = GNUNET_TIME_UNIT_ZERO;
2299       fal->estimated = GNUNET_YES;
2300     }                               
2301   if (GNUNET_YES == fal->connected)
2302     {
2303       delay = GNUNET_TIME_relative_min (delay,
2304                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2305     }  
2306   /* FIXME: also adjust delay based on how close the last
2307      observed latency is to the latency of the best alternative */
2308   /* bound how fast we can go */
2309   delay = GNUNET_TIME_relative_max (delay,
2310                                     GNUNET_TIME_UNIT_SECONDS);
2311   /* randomize a bit (to avoid doing all at the same time) */
2312   delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2313   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
2314                                                       delay,
2315                                                       &send_periodic_ping, 
2316                                                       fal);
2317 }
2318
2319
2320 /**
2321  * Iterator over hash map entries.  Checks if the given validation
2322  * entry is for the same challenge as what is given in the PONG.
2323  *
2324  * @param cls the 'struct TransportPongMessage*'
2325  * @param key peer identity
2326  * @param value value in the hash map ('struct ValidationEntry')
2327  * @return GNUNET_YES if we should continue to
2328  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2329  */
2330 static int
2331 check_pending_validation (void *cls,
2332                           const GNUNET_HashCode * key,
2333                           void *value)
2334 {
2335   const struct TransportPongMessage *pong = cls;
2336   struct ValidationEntry *ve = value;
2337   struct AddValidatedAddressContext avac;
2338   unsigned int challenge = ntohl(pong->challenge);
2339   struct GNUNET_HELLO_Message *hello;
2340   struct GNUNET_PeerIdentity target;
2341   struct NeighbourList *n;
2342   struct ForeignAddressList *fal;
2343
2344   if (ve->challenge != challenge)
2345     return GNUNET_YES;
2346
2347 #if DEBUG_TRANSPORT
2348   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2349               "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2350               GNUNET_h2s (key),
2351               GNUNET_a2s ((const struct sockaddr *) ve->addr,
2352                           ve->addrlen),
2353               ve->transport_name);
2354 #endif
2355   GNUNET_STATISTICS_update (stats,
2356                             gettext_noop ("# address validation successes"),
2357                             1,
2358                             GNUNET_NO);
2359   /* create the updated HELLO */
2360   GNUNET_CRYPTO_hash (&ve->publicKey,
2361                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2362                       &target.hashPubKey);
2363   avac.done = GNUNET_NO;
2364   avac.ve = ve;
2365   hello = GNUNET_HELLO_create (&ve->publicKey,
2366                                &add_validated_address,
2367                                &avac);
2368   GNUNET_PEERINFO_add_peer (cfg, sched,
2369                             &target,
2370                             hello);
2371   GNUNET_free (hello);
2372   n = find_neighbour (&target);
2373   if (n != NULL)
2374     {
2375       n->publicKey = ve->publicKey;
2376       n->public_key_valid = GNUNET_YES;
2377       fal = add_peer_address (n,
2378                               ve->transport_name,
2379                               ve->addr,
2380                               ve->addrlen);
2381       GNUNET_assert (fal != NULL);
2382       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2383       fal->validated = GNUNET_YES;
2384       GNUNET_STATISTICS_update (stats,
2385                                 gettext_noop ("# peer addresses considered valid"),
2386                                 1,
2387                                 GNUNET_NO);      
2388       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2389       schedule_next_ping (fal);
2390       if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2391         n->latency = fal->latency;
2392       else
2393         n->latency.value = (fal->latency.value + n->latency.value) / 2;
2394       n->distance = fal->distance;
2395       if (GNUNET_NO == n->received_pong)
2396         {
2397           notify_clients_connect (&target, n->latency, n->distance);
2398           n->received_pong = GNUNET_YES;
2399         }
2400       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2401         {
2402           GNUNET_SCHEDULER_cancel (sched,
2403                                    n->retry_task);
2404           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2405           try_transmission_to_peer (n);
2406         }
2407     }
2408
2409   /* clean up validation entry */
2410   GNUNET_assert (GNUNET_YES ==
2411                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
2412                                                        key,
2413                                                        ve));
2414   GNUNET_SCHEDULER_cancel (sched,
2415                            ve->timeout_task);
2416   GNUNET_free (ve->transport_name);
2417   GNUNET_free (ve);
2418   return GNUNET_NO;
2419 }
2420
2421
2422 /**
2423  * Function that will be called if we receive a validation
2424  * of an address challenge that we transmitted to another
2425  * peer.  Note that the validation should only be considered
2426  * acceptable if the challenge matches AND if the sender
2427  * address is at least a plausible address for this peer
2428  * (otherwise we may be seeing a MiM attack).
2429  *
2430  * @param cls closure
2431  * @param message the pong message
2432  * @param peer who responded to our challenge
2433  * @param sender_address string describing our sender address (as observed
2434  *         by the other peer in binary format)
2435  * @param sender_address_len number of bytes in 'sender_address'
2436  */
2437 static void
2438 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2439              const struct GNUNET_PeerIdentity *peer,
2440              const char *sender_address,
2441              size_t sender_address_len)
2442 {
2443 #if DEBUG_TRANSPORT > 1
2444   /* we get tons of these that just get discarded, only log
2445      if we are quite verbose */
2446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2447               "Receiving `%s' message from `%4s'.\n", "PONG",
2448               GNUNET_i2s (peer));
2449 #endif
2450   GNUNET_STATISTICS_update (stats,
2451                             gettext_noop ("# PONG messages received"),
2452                             1,
2453                             GNUNET_NO);
2454   if (GNUNET_SYSERR !=
2455       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2456                                                   &peer->hashPubKey,
2457                                                   &check_pending_validation,
2458                                                   (void*) message))
2459     {
2460       /* This is *expected* to happen a lot since we send
2461          PONGs to *all* known addresses of the sender of
2462          the PING, so most likely we get multiple PONGs
2463          per PING, and all but the first PONG will end up
2464          here. So really we should not print anything here
2465          unless we want to be very, very verbose... */
2466 #if DEBUG_TRANSPORT > 2
2467       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2468                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2469                   "PONG",
2470                   GNUNET_i2s (peer),
2471                   "PING");
2472 #endif
2473       return;
2474     }
2475
2476 #if 0
2477   /* FIXME: add given address to potential pool of our addresses
2478      (for voting) */
2479   GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2480               _("Another peer saw us using the address `%s' via `%s'.\n"),
2481               GNUNET_a2s ((const struct sockaddr *) &pong[1],
2482                           ntohs(pong->addrlen)),
2483               va->transport_name);
2484 #endif
2485 }
2486
2487
2488 /**
2489  * Check if the given address is already being validated; if not,
2490  * append the given address to the list of entries that are being be
2491  * validated and initiate validation.
2492  *
2493  * @param cls closure ('struct CheckHelloValidatedContext *')
2494  * @param tname name of the transport
2495  * @param expiration expiration time
2496  * @param addr the address
2497  * @param addrlen length of the address
2498  * @return GNUNET_OK (always)
2499  */
2500 static int
2501 run_validation (void *cls,
2502                 const char *tname,
2503                 struct GNUNET_TIME_Absolute expiration,
2504                 const void *addr, size_t addrlen)
2505 {
2506   struct CheckHelloValidatedContext *chvc = cls;
2507   struct GNUNET_PeerIdentity id;
2508   struct TransportPlugin *tp;
2509   struct ValidationEntry *va;
2510   struct NeighbourList *neighbour;
2511   struct ForeignAddressList *peer_address;
2512   struct TransportPingMessage ping;
2513   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2514   struct CheckAddressExistsClosure caec;
2515   char * message_buf;
2516   uint16_t hello_size;
2517   size_t tsize;
2518
2519   GNUNET_STATISTICS_update (stats,
2520                             gettext_noop ("# peer addresses scheduled for validation"),
2521                             1,
2522                             GNUNET_NO);      
2523   tp = find_transport (tname);
2524   if (tp == NULL)
2525     {
2526       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2527                   GNUNET_ERROR_TYPE_BULK,
2528                   _
2529                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2530                   tname);
2531       GNUNET_STATISTICS_update (stats,
2532                                 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2533                                 1,
2534                                 GNUNET_NO);      
2535       return GNUNET_OK;
2536     }
2537   GNUNET_HELLO_get_key (chvc->hello, &pk);
2538   GNUNET_CRYPTO_hash (&pk,
2539                       sizeof (struct
2540                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2541                       &id.hashPubKey);
2542   caec.addr = addr;
2543   caec.addrlen = addrlen;
2544   caec.tname = tname;
2545   caec.exists = GNUNET_NO;
2546   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2547                                          &check_address_exists,
2548                                          &caec);
2549   if (caec.exists == GNUNET_YES)
2550     {
2551       /* During validation attempts we will likely trigger the other
2552          peer trying to validate our address which in turn will cause
2553          it to send us its HELLO, so we expect to hit this case rather
2554          frequently.  Only print something if we are very verbose. */
2555 #if DEBUG_TRANSPORT > 1
2556       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2557                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2558                   GNUNET_a2s (addr, addrlen),
2559                   tname,
2560                   GNUNET_i2s (&id));
2561 #endif
2562       GNUNET_STATISTICS_update (stats,
2563                                 gettext_noop ("# peer addresses not validated (in progress)"),
2564                                 1,
2565                                 GNUNET_NO);      
2566       return GNUNET_OK;
2567     }
2568   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2569   va->transport_name = GNUNET_strdup (tname);
2570   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2571                                             (unsigned int) -1);
2572   va->send_time = GNUNET_TIME_absolute_get();
2573   va->addr = (const void*) &va[1];
2574   memcpy (&va[1], addr, addrlen);
2575   va->addrlen = addrlen;
2576   GNUNET_HELLO_get_key (chvc->hello,
2577                         &va->publicKey);
2578   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2579                                                    HELLO_VERIFICATION_TIMEOUT,
2580                                                    &timeout_hello_validation,
2581                                                    va);
2582   GNUNET_CONTAINER_multihashmap_put (validation_map,
2583                                      &id.hashPubKey,
2584                                      va,
2585                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2586   neighbour = find_neighbour(&id);
2587   if (neighbour == NULL)
2588     neighbour = setup_new_neighbour(&id);
2589   neighbour->publicKey = va->publicKey;
2590   neighbour->public_key_valid = GNUNET_YES;
2591   peer_address = add_peer_address(neighbour, tname, addr, addrlen);
2592   GNUNET_assert(peer_address != NULL);
2593   hello_size = GNUNET_HELLO_size(our_hello);
2594   tsize = sizeof(struct TransportPingMessage) + hello_size;
2595   message_buf = GNUNET_malloc(tsize);
2596   ping.challenge = htonl(va->challenge);
2597   ping.header.size = htons(sizeof(struct TransportPingMessage));
2598   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2599   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2600   memcpy(message_buf, our_hello, hello_size);
2601   memcpy(&message_buf[hello_size],
2602          &ping,
2603          sizeof(struct TransportPingMessage));
2604 #if DEBUG_TRANSPORT
2605   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2607               GNUNET_a2s (addr, addrlen),
2608               tname,
2609               GNUNET_i2s (&id),
2610               "HELLO", hello_size,
2611               "PING", sizeof (struct TransportPingMessage));
2612 #endif
2613   GNUNET_STATISTICS_update (stats,
2614                             gettext_noop ("# PING messages sent for initial validation"),
2615                             1,
2616                             GNUNET_NO);      
2617   transmit_to_peer (NULL, peer_address,
2618                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2619                     HELLO_VERIFICATION_TIMEOUT,
2620                     message_buf, tsize,
2621                     GNUNET_YES, neighbour);
2622   GNUNET_free(message_buf);
2623   return GNUNET_OK;
2624 }
2625
2626
2627 /**
2628  * Check if addresses in validated hello "h" overlap with
2629  * those in "chvc->hello" and validate the rest.
2630  *
2631  * @param cls closure
2632  * @param peer id of the peer, NULL for last call
2633  * @param h hello message for the peer (can be NULL)
2634  * @param trust amount of trust we have in the peer (not used)
2635  */
2636 static void
2637 check_hello_validated (void *cls,
2638                        const struct GNUNET_PeerIdentity *peer,
2639                        const struct GNUNET_HELLO_Message *h, 
2640                        uint32_t trust)
2641 {
2642   struct CheckHelloValidatedContext *chvc = cls;
2643   struct GNUNET_HELLO_Message *plain_hello;
2644   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2645   struct GNUNET_PeerIdentity target;
2646   struct NeighbourList *n;
2647
2648   if (peer == NULL)
2649     {
2650       chvc->piter = NULL;
2651       GNUNET_CONTAINER_DLL_remove (chvc_head,
2652                                    chvc_tail,
2653                                    chvc);
2654       if (GNUNET_NO == chvc->hello_known)
2655         {
2656           /* notify PEERINFO about the peer now, so that we at least
2657              have the public key if some other component needs it */
2658           GNUNET_HELLO_get_key (chvc->hello, &pk);
2659           GNUNET_CRYPTO_hash (&pk,
2660                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2661                               &target.hashPubKey);
2662           plain_hello = GNUNET_HELLO_create (&pk,
2663                                              NULL, 
2664                                              NULL);
2665           GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2666           GNUNET_free (plain_hello);
2667 #if DEBUG_TRANSPORT
2668           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2669                       "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2670                       "HELLO",
2671                       GNUNET_i2s (&target));
2672 #endif
2673           GNUNET_STATISTICS_update (stats,
2674                                     gettext_noop ("# new HELLOs requiring full validation"),
2675                                     1,
2676                                     GNUNET_NO);      
2677           GNUNET_HELLO_iterate_addresses (chvc->hello,
2678                                           GNUNET_NO, 
2679                                           &run_validation, 
2680                                           chvc);
2681         }
2682       else
2683         {
2684           GNUNET_STATISTICS_update (stats,
2685                                     gettext_noop ("# duplicate HELLO (peer known)"),
2686                                     1,
2687                                     GNUNET_NO);      
2688         }
2689       GNUNET_free (chvc);
2690       return;
2691     } 
2692   if (h == NULL)
2693     return;
2694 #if DEBUG_TRANSPORT
2695   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2696               "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2697               "HELLO",
2698               GNUNET_i2s (peer));
2699 #endif
2700   chvc->hello_known = GNUNET_YES;
2701   n = find_neighbour (peer);
2702   if (n != NULL)
2703     {
2704       GNUNET_HELLO_iterate_addresses (h,
2705                                       GNUNET_NO,
2706                                       &add_to_foreign_address_list,
2707                                       n);
2708       try_transmission_to_peer (n);
2709     }
2710   else
2711     {
2712       GNUNET_STATISTICS_update (stats,
2713                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
2714                                 1,
2715                                 GNUNET_NO);      
2716     }
2717   GNUNET_STATISTICS_update (stats,
2718                             gettext_noop ("# HELLO validations (update case)"),
2719                             1,
2720                             GNUNET_NO);      
2721   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2722                                       h,
2723                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2724                                       &run_validation, 
2725                                       chvc);
2726 }
2727
2728 /**
2729  * Process HELLO-message.
2730  *
2731  * @param plugin transport involved, may be NULL
2732  * @param message the actual message
2733  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2734  */
2735 static int
2736 process_hello (struct TransportPlugin *plugin,
2737                const struct GNUNET_MessageHeader *message)
2738 {
2739   uint16_t hsize;
2740   struct GNUNET_PeerIdentity target;
2741   const struct GNUNET_HELLO_Message *hello;
2742   struct CheckHelloValidatedContext *chvc;
2743   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2744
2745   hsize = ntohs (message->size);
2746   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2747       (hsize < sizeof (struct GNUNET_MessageHeader)))
2748     {
2749       GNUNET_break (0);
2750       return GNUNET_SYSERR;
2751     }
2752   GNUNET_STATISTICS_update (stats,
2753                             gettext_noop ("# HELLOs received for validation"),
2754                             1,
2755                             GNUNET_NO);      
2756   /* first, check if load is too high */
2757   if (GNUNET_SCHEDULER_get_load (sched,
2758                                  GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2759     {
2760       GNUNET_STATISTICS_update (stats,
2761                                 gettext_noop ("# HELLOs ignored due to high load"),
2762                                 1,
2763                                 GNUNET_NO);      
2764       return GNUNET_OK;
2765     }
2766   hello = (const struct GNUNET_HELLO_Message *) message;
2767   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2768     {
2769       GNUNET_break_op (0);
2770       return GNUNET_SYSERR;
2771     }
2772   GNUNET_CRYPTO_hash (&publicKey,
2773                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2774                       &target.hashPubKey);
2775   if (0 == memcmp (&my_identity,
2776                    &target,
2777                    sizeof (struct GNUNET_PeerIdentity)))
2778     {
2779       GNUNET_STATISTICS_update (stats,
2780                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2781                                 1,
2782                                 GNUNET_NO);      
2783       return GNUNET_OK;      
2784     }
2785 #if DEBUG_TRANSPORT > 1
2786   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2787               "Processing `%s' message for `%4s' of size %u\n",
2788               "HELLO", 
2789               GNUNET_i2s (&target), 
2790               GNUNET_HELLO_size(hello));
2791 #endif
2792   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2793   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2794   memcpy (&chvc[1], hello, hsize);
2795   GNUNET_CONTAINER_DLL_insert (chvc_head,
2796                                chvc_tail,
2797                                chvc);
2798   /* finally, check if HELLO was previously validated
2799      (continuation will then schedule actual validation) */
2800   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2801                                          sched,
2802                                          &target,
2803                                          0,
2804                                          HELLO_VERIFICATION_TIMEOUT,
2805                                          &check_hello_validated, chvc);
2806   return GNUNET_OK;
2807 }
2808
2809
2810 /**
2811  * The peer specified by the given neighbour has timed-out or a plugin
2812  * has disconnected.  We may either need to do nothing (other plugins
2813  * still up), or trigger a full disconnect and clean up.  This
2814  * function updates our state and does the necessary notifications.
2815  * Also notifies our clients that the neighbour is now officially
2816  * gone.
2817  *
2818  * @param n the neighbour list entry for the peer
2819  * @param check should we just check if all plugins
2820  *        disconnected or must we ask all plugins to
2821  *        disconnect?
2822  */
2823 static void
2824 disconnect_neighbour (struct NeighbourList *n, int check)
2825 {
2826   struct ReadyList *rpos;
2827   struct NeighbourList *npos;
2828   struct NeighbourList *nprev;
2829   struct MessageQueue *mq;
2830   struct ForeignAddressList *peer_addresses;
2831   struct ForeignAddressList *peer_pos;
2832
2833   if (GNUNET_YES == check)
2834     {
2835       rpos = n->plugins;
2836       while (NULL != rpos)
2837         {
2838           peer_addresses = rpos->addresses;
2839           while (peer_addresses != NULL)
2840             {
2841               if (GNUNET_YES == peer_addresses->connected)
2842                 return;             /* still connected */
2843               peer_addresses = peer_addresses->next;
2844             }
2845           rpos = rpos->next;
2846         }
2847     }
2848 #if DEBUG_TRANSPORT
2849   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2850               "Disconnecting from `%4s'\n",
2851               GNUNET_i2s (&n->id));
2852 #endif
2853   /* remove n from neighbours list */
2854   nprev = NULL;
2855   npos = neighbours;
2856   while ((npos != NULL) && (npos != n))
2857     {
2858       nprev = npos;
2859       npos = npos->next;
2860     }
2861   GNUNET_assert (npos != NULL);
2862   if (nprev == NULL)
2863     neighbours = n->next;
2864   else
2865     nprev->next = n->next;
2866
2867   /* notify all clients about disconnect */
2868   if (GNUNET_YES == n->received_pong)
2869     notify_clients_disconnect (&n->id);
2870
2871   /* clean up all plugins, cancel connections and pending transmissions */
2872   while (NULL != (rpos = n->plugins))
2873     {
2874       n->plugins = rpos->next;
2875       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2876       while (rpos->addresses != NULL)
2877         {
2878           peer_pos = rpos->addresses;
2879           rpos->addresses = peer_pos->next;
2880           if (peer_pos->connected == GNUNET_YES)
2881             GNUNET_STATISTICS_update (stats,
2882                                       gettext_noop ("# connected addresses"),
2883                                       -1,
2884                                       GNUNET_NO); 
2885           if (GNUNET_YES == peer_pos->validated)
2886             GNUNET_STATISTICS_update (stats,
2887                                       gettext_noop ("# peer addresses considered valid"),
2888                                       -1,
2889                                       GNUNET_NO);      
2890           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
2891             {
2892               GNUNET_SCHEDULER_cancel (sched,
2893                                        peer_pos->revalidate_task);
2894               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2895             }
2896           GNUNET_free(peer_pos);
2897         }
2898       GNUNET_free (rpos);
2899     }
2900
2901   /* free all messages on the queue */
2902   while (NULL != (mq = n->messages_head))
2903     {
2904       GNUNET_STATISTICS_update (stats,
2905                                 gettext_noop ("# bytes in message queue for other peers"),
2906                                 - (int64_t) mq->message_buf_size,
2907                                 GNUNET_NO);
2908       GNUNET_STATISTICS_update (stats,
2909                                 gettext_noop ("# bytes discarded due to disconnect"),
2910                                 mq->message_buf_size,
2911                                 GNUNET_NO);
2912       GNUNET_CONTAINER_DLL_remove (n->messages_head,
2913                                    n->messages_tail,
2914                                    mq);
2915       GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
2916                                  &n->id,
2917                                  sizeof(struct GNUNET_PeerIdentity)));
2918       GNUNET_free (mq);
2919     }
2920   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2921     {
2922       GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2923       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2924     }
2925   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2926     {
2927       GNUNET_SCHEDULER_cancel (sched, n->retry_task);
2928       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2929     }
2930   if (n->piter != NULL)
2931     {
2932       GNUNET_PEERINFO_iterate_cancel (n->piter);
2933       n->piter = NULL;
2934     }
2935   /* finally, free n itself */
2936   GNUNET_STATISTICS_update (stats,
2937                             gettext_noop ("# active neighbours"),
2938                             -1,
2939                             GNUNET_NO);
2940   GNUNET_free (n);
2941 }
2942
2943
2944 /**
2945  * We have received a PING message from someone.  Need to send a PONG message
2946  * in response to the peer by any means necessary. 
2947  *
2948  * FIXME: With something like TCP where a connection exists, we may
2949  * want to send it that way.  But the current API does not seem to
2950  * allow us to do so (can't tell this to the transport!)
2951  */
2952 static int 
2953 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2954             const struct GNUNET_PeerIdentity *peer,
2955             const char *sender_address,
2956             size_t sender_address_len)
2957 {
2958   struct TransportPlugin *plugin = cls;
2959   struct TransportPingMessage *ping;
2960   struct TransportPongMessage *pong;
2961   struct NeighbourList *n;
2962   struct ReadyList *rl;
2963   struct ForeignAddressList *fal;
2964
2965   if (ntohs (message->size) != sizeof (struct TransportPingMessage))
2966     {
2967       GNUNET_break_op (0);
2968       return GNUNET_SYSERR;
2969     }
2970   ping = (struct TransportPingMessage *) message;
2971   if (0 != memcmp (&ping->target,
2972                    plugin->env.my_identity,
2973                    sizeof (struct GNUNET_PeerIdentity)))
2974     {
2975       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2976                   _("Received `%s' message not destined for me!\n"), 
2977                   "PING");
2978       return GNUNET_SYSERR;
2979     }
2980 #if DEBUG_TRANSPORT
2981   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2982               "Processing `%s' from `%s'\n",
2983               "PING", 
2984               GNUNET_a2s ((const struct sockaddr *)sender_address, 
2985                           sender_address_len));
2986 #endif
2987   GNUNET_STATISTICS_update (stats,
2988                             gettext_noop ("# PING messages received"),
2989                             1,
2990                             GNUNET_NO);
2991   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2992   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2993   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2994   pong->purpose.size =
2995     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2996            sizeof (uint32_t) +
2997            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2998   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2999   pong->challenge = ping->challenge;
3000   pong->addrlen = htons(sender_address_len);
3001   memcpy(&pong->signer, 
3002          &my_public_key, 
3003          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3004   memcpy (&pong[1], sender_address, sender_address_len);
3005   GNUNET_assert (GNUNET_OK ==
3006                  GNUNET_CRYPTO_rsa_sign (my_private_key,
3007                                          &pong->purpose, &pong->signature));
3008
3009   n = find_neighbour(peer);
3010   if (n == NULL)
3011     n = setup_new_neighbour(peer);
3012   /* broadcast 'PONG' to all available addresses */
3013   rl = n->plugins;
3014   while (rl != NULL)
3015     {
3016       fal = rl->addresses;
3017       while (fal != NULL)
3018         {
3019           transmit_to_peer(NULL, fal,
3020                            TRANSPORT_PONG_PRIORITY, 
3021                            HELLO_VERIFICATION_TIMEOUT,
3022                            (const char *)pong, 
3023                            ntohs(pong->header.size), 
3024                            GNUNET_YES, 
3025                            n);
3026           fal = fal->next;
3027         }
3028       rl = rl->next;
3029     }
3030   GNUNET_free(pong);
3031   return GNUNET_OK;
3032 }
3033
3034
3035 /**
3036  * Function called by the plugin for each received message.
3037  * Update data volumes, possibly notify plugins about
3038  * reducing the rate at which they read from the socket
3039  * and generally forward to our receive callback.
3040  *
3041  * @param cls the "struct TransportPlugin *" we gave to the plugin
3042  * @param peer (claimed) identity of the other peer
3043  * @param message the message, NULL if we only care about
3044  *                learning about the delay until we should receive again
3045  * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3046  * @param sender_address binary address of the sender (if observed)
3047  * @param sender_address_len number of bytes in sender_address
3048  * @return how long the plugin should wait until receiving more data
3049  *         (plugins that do not support this, can ignore the return value)
3050  */
3051 static struct GNUNET_TIME_Relative
3052 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3053                     const struct GNUNET_MessageHeader *message,
3054                     unsigned int distance, const char *sender_address,
3055                     size_t sender_address_len)
3056 {
3057   struct ReadyList *service_context;
3058   struct TransportPlugin *plugin = cls;
3059   struct TransportClient *cpos;
3060   struct InboundMessage *im;
3061   struct ForeignAddressList *peer_address;
3062   uint16_t msize;
3063   struct NeighbourList *n;
3064   struct GNUNET_TIME_Relative ret;
3065
3066   n = find_neighbour (peer);
3067   if (n == NULL)
3068     n = setup_new_neighbour (peer);    
3069   service_context = n->plugins;
3070   while ((service_context != NULL) && (plugin != service_context->plugin))
3071     service_context = service_context->next;
3072   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3073   if (message != NULL)
3074     {
3075       peer_address = add_peer_address(n, 
3076                                       plugin->short_name,
3077                                       sender_address, 
3078                                       sender_address_len);  
3079       if (peer_address != NULL)
3080         {
3081           peer_address->distance = distance;
3082           if (peer_address->connected == GNUNET_NO)
3083             {
3084               /* FIXME: be careful here to not mark
3085                  MULTIPLE addresses as connected! */
3086               peer_address->connected = GNUNET_YES;
3087               GNUNET_STATISTICS_update (stats,
3088                                         gettext_noop ("# connected addresses"),
3089                                         1,
3090                                         GNUNET_NO);
3091             }
3092           peer_address->timeout
3093             =
3094             GNUNET_TIME_relative_to_absolute
3095             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3096           schedule_next_ping (peer_address);
3097         }
3098       /* update traffic received amount ... */
3099       msize = ntohs (message->size);      
3100       GNUNET_STATISTICS_update (stats,
3101                                 gettext_noop ("# bytes received from other peers"),
3102                                 msize,
3103                                 GNUNET_NO);
3104       n->distance = distance;
3105       n->peer_timeout =
3106         GNUNET_TIME_relative_to_absolute
3107         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3108       GNUNET_SCHEDULER_cancel (sched,
3109                                n->timeout_task);
3110       n->timeout_task =
3111         GNUNET_SCHEDULER_add_delayed (sched,
3112                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3113                                       &neighbour_timeout_task, n);
3114       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3115         {
3116           /* dropping message due to frequent inbound volume violations! */
3117           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3118                       GNUNET_ERROR_TYPE_BULK,
3119                       _
3120                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
3121                       n->in_tracker.available_bytes_per_s__,
3122                       n->quota_violation_count);
3123           GNUNET_STATISTICS_update (stats,
3124                                     gettext_noop ("# bandwidth quota violations by other peers"),
3125                                     1,
3126                                     GNUNET_NO);
3127           return GNUNET_TIME_UNIT_MINUTES; /* minimum penalty, likely ignored (UDP...) */
3128         }
3129       switch (ntohs (message->type))
3130         {
3131         case GNUNET_MESSAGE_TYPE_HELLO:
3132           GNUNET_STATISTICS_update (stats,
3133                                     gettext_noop ("# HELLO messages received from other peers"),
3134                                     1,
3135                                     GNUNET_NO);
3136           process_hello (plugin, message);
3137           break;
3138         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3139           handle_ping(plugin, message, peer, sender_address, sender_address_len);
3140           break;
3141         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3142           handle_pong(plugin, message, peer, sender_address, sender_address_len);
3143           break;
3144         default:
3145 #if DEBUG_TRANSPORT
3146           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147                       "Received message of type %u from `%4s', sending to all clients.\n",
3148                       ntohs (message->type), GNUNET_i2s (peer));
3149 #endif
3150           if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3151                                                               msize))
3152             n->quota_violation_count++;
3153           else 
3154             n->quota_violation_count = 0; /* back within limits */
3155           GNUNET_STATISTICS_update (stats,
3156                                     gettext_noop ("# payload received from other peers"),
3157                                     msize,
3158                                     GNUNET_NO);
3159           /* transmit message to all clients */
3160           im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3161           im->header.size = htons (sizeof (struct InboundMessage) + msize);
3162           im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3163           im->latency = GNUNET_TIME_relative_hton (n->latency);
3164           im->peer = *peer;
3165           memcpy (&im[1], message, msize);
3166           cpos = clients;
3167           while (cpos != NULL)
3168             {
3169               transmit_to_client (cpos, &im->header, GNUNET_YES);
3170               cpos = cpos->next;
3171             }
3172           GNUNET_free (im);
3173         }
3174     }  
3175   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3176   if (ret.value > 0)
3177     {
3178       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3179                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3180                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
3181                   (unsigned int) n->in_tracker.available_bytes_per_s__,
3182                   (unsigned long long) ret.value);
3183       GNUNET_STATISTICS_update (stats,
3184                                 gettext_noop ("# ms throttling suggested"),
3185                                 (int64_t) ret.value,
3186                                 GNUNET_NO);      
3187     }
3188   return ret;
3189 }
3190
3191
3192 /**
3193  * Handle START-message.  This is the first message sent to us
3194  * by any client which causes us to add it to our list.
3195  *
3196  * @param cls closure (always NULL)
3197  * @param client identification of the client
3198  * @param message the actual message
3199  */
3200 static void
3201 handle_start (void *cls,
3202               struct GNUNET_SERVER_Client *client,
3203               const struct GNUNET_MessageHeader *message)
3204 {
3205   struct TransportClient *c;
3206   struct ConnectInfoMessage cim;
3207   struct NeighbourList *n;
3208
3209 #if DEBUG_TRANSPORT
3210   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211               "Received `%s' request from client\n", "START");
3212 #endif
3213   c = clients;
3214   while (c != NULL)
3215     {
3216       if (c->client == client)
3217         {
3218           /* client already on our list! */
3219           GNUNET_break (0);
3220           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3221           return;
3222         }
3223       c = c->next;
3224     }
3225   c = GNUNET_malloc (sizeof (struct TransportClient));
3226   c->next = clients;
3227   clients = c;
3228   c->client = client;
3229   if (our_hello != NULL)
3230     {
3231 #if DEBUG_TRANSPORT
3232       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3233                   "Sending our own `%s' to new client\n", "HELLO");
3234 #endif
3235       transmit_to_client (c,
3236                           (const struct GNUNET_MessageHeader *) our_hello,
3237                           GNUNET_NO);
3238       /* tell new client about all existing connections */
3239       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3240       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3241       n = neighbours; 
3242       while (n != NULL)
3243         {
3244           if (GNUNET_YES == n->received_pong)
3245             {
3246               cim.id = n->id;
3247               cim.latency = GNUNET_TIME_relative_hton (n->latency);
3248               cim.distance = htonl (n->distance);
3249               transmit_to_client (c, &cim.header, GNUNET_NO);
3250             }
3251             n = n->next;
3252         }
3253     }
3254   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3255 }
3256
3257
3258 /**
3259  * Handle HELLO-message.
3260  *
3261  * @param cls closure (always NULL)
3262  * @param client identification of the client
3263  * @param message the actual message
3264  */
3265 static void
3266 handle_hello (void *cls,
3267               struct GNUNET_SERVER_Client *client,
3268               const struct GNUNET_MessageHeader *message)
3269 {
3270   int ret;
3271
3272   GNUNET_STATISTICS_update (stats,
3273                             gettext_noop ("# HELLOs received from clients"),
3274                             1,
3275                             GNUNET_NO);      
3276   ret = process_hello (NULL, message);
3277   GNUNET_SERVER_receive_done (client, ret);
3278 }
3279
3280
3281 /**
3282  * Handle SEND-message.
3283  *
3284  * @param cls closure (always NULL)
3285  * @param client identification of the client
3286  * @param message the actual message
3287  */
3288 static void
3289 handle_send (void *cls,
3290              struct GNUNET_SERVER_Client *client,
3291              const struct GNUNET_MessageHeader *message)
3292 {
3293   struct TransportClient *tc;
3294   struct NeighbourList *n;
3295   const struct OutboundMessage *obm;
3296   const struct GNUNET_MessageHeader *obmm;
3297   uint16_t size;
3298   uint16_t msize;
3299
3300   size = ntohs (message->size);
3301   if (size <
3302       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3303     {
3304       GNUNET_break (0);
3305       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3306       return;
3307     }
3308   GNUNET_STATISTICS_update (stats,
3309                             gettext_noop ("# payload received for other peers"),
3310                             size,
3311                             GNUNET_NO);      
3312   obm = (const struct OutboundMessage *) message;
3313 #if DEBUG_TRANSPORT
3314   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3315               "Received `%s' request from client with target `%4s'\n",
3316               "SEND", GNUNET_i2s (&obm->peer));
3317 #endif
3318   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3319   msize = ntohs (obmm->size);
3320   if (size != msize + sizeof (struct OutboundMessage))
3321     {
3322       GNUNET_break (0);
3323       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3324       return;
3325     }
3326   n = find_neighbour (&obm->peer);
3327   if (n == NULL)
3328     n = setup_new_neighbour (&obm->peer);
3329   tc = clients;
3330   while ((tc != NULL) && (tc->client != client))
3331     tc = tc->next;
3332
3333 #if DEBUG_TRANSPORT
3334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3335               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3336               ntohs (obmm->size),
3337               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3338 #endif
3339   transmit_to_peer (tc, NULL, ntohl (obm->priority), 
3340                     GNUNET_TIME_relative_ntoh (obm->timeout),
3341                     (char *)obmm, 
3342                     ntohs (obmm->size), GNUNET_NO, n);
3343   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3344 }
3345
3346
3347 /**
3348  * Handle SET_QUOTA-message.
3349  *
3350  * @param cls closure (always NULL)
3351  * @param client identification of the client
3352  * @param message the actual message
3353  */
3354 static void
3355 handle_set_quota (void *cls,
3356                   struct GNUNET_SERVER_Client *client,
3357                   const struct GNUNET_MessageHeader *message)
3358 {
3359   const struct QuotaSetMessage *qsm =
3360     (const struct QuotaSetMessage *) message;
3361   struct NeighbourList *n;
3362   
3363   GNUNET_STATISTICS_update (stats,
3364                             gettext_noop ("# SET QUOTA messages received"),
3365                             1,
3366                             GNUNET_NO);      
3367   n = find_neighbour (&qsm->peer);
3368   if (n == NULL)
3369     {
3370       GNUNET_SERVER_receive_done (client, GNUNET_OK);
3371       GNUNET_STATISTICS_update (stats,
3372                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3373                                 1,
3374                                 GNUNET_NO);      
3375       return;
3376     }
3377 #if DEBUG_TRANSPORT
3378   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3379               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3380               "SET_QUOTA", 
3381               (unsigned int) ntohl (qsm->quota.value__),
3382               (unsigned int) n->in_tracker.available_bytes_per_s__,
3383               GNUNET_i2s (&qsm->peer));
3384 #endif
3385   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3386                                          qsm->quota);
3387   if (0 == ntohl (qsm->quota.value__)) 
3388     disconnect_neighbour (n, GNUNET_NO);    
3389   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3390 }
3391
3392
3393 /**
3394  * Take the given address and append it to the set of results send back to
3395  * the client.
3396  * 
3397  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3398  * @param address the resolved name, NULL to indicate the last response
3399  */
3400 static void
3401 transmit_address_to_client (void *cls, const char *address)
3402 {
3403   struct GNUNET_SERVER_TransmitContext *tc = cls;
3404   size_t slen;
3405
3406   if (NULL == address)
3407     slen = 0;
3408   else
3409     slen = strlen (address) + 1;
3410   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3411                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3412   if (NULL == address)
3413     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3414 }
3415
3416
3417 /**
3418  * Handle AddressLookup-message.
3419  *
3420  * @param cls closure (always NULL)
3421  * @param client identification of the client
3422  * @param message the actual message
3423  */
3424 static void
3425 handle_address_lookup (void *cls,
3426                        struct GNUNET_SERVER_Client *client,
3427                        const struct GNUNET_MessageHeader *message)
3428 {
3429   const struct AddressLookupMessage *alum;
3430   struct TransportPlugin *lsPlugin;
3431   const char *nameTransport;
3432   const char *address;
3433   uint16_t size;
3434   struct GNUNET_SERVER_TransmitContext *tc;
3435   struct GNUNET_TIME_Absolute timeout;
3436   struct GNUNET_TIME_Relative rtimeout;
3437   int32_t numeric;
3438
3439   size = ntohs (message->size);
3440   if (size < sizeof (struct AddressLookupMessage))
3441     {
3442       GNUNET_break_op (0);
3443       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3444       return;
3445     }
3446   alum = (const struct AddressLookupMessage *) message;
3447   uint32_t addressLen = ntohl (alum->addrlen);
3448   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3449     {
3450       GNUNET_break_op (0);
3451       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3452       return;
3453     }
3454   address = (const char *) &alum[1];
3455   nameTransport = (const char *) &address[addressLen];
3456   if (nameTransport
3457       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3458     {
3459       GNUNET_break_op (0);
3460       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3461       return;
3462     }
3463   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
3464   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
3465   numeric = ntohl (alum->numeric_only);
3466   lsPlugin = find_transport (nameTransport);
3467   if (NULL == lsPlugin)
3468     {
3469       tc = GNUNET_SERVER_transmit_context_create (client);
3470       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3471                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3472       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3473       return;
3474     }
3475   tc = GNUNET_SERVER_transmit_context_create (client);
3476   lsPlugin->api->address_pretty_printer (cls, nameTransport,
3477                                          address, addressLen, 
3478                                          numeric,
3479                                          rtimeout,
3480                                          &transmit_address_to_client, tc);
3481 }
3482
3483 /**
3484  * List of handlers for the messages understood by this
3485  * service.
3486  */
3487 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3488   {&handle_start, NULL,
3489    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3490   {&handle_hello, NULL,
3491    GNUNET_MESSAGE_TYPE_HELLO, 0},
3492   {&handle_send, NULL,
3493    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3494   {&handle_set_quota, NULL,
3495    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3496   {&handle_address_lookup, NULL,
3497    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3498    0},
3499   {NULL, NULL, 0, 0}
3500 };
3501
3502
3503 /**
3504  * Setup the environment for this plugin.
3505  */
3506 static void
3507 create_environment (struct TransportPlugin *plug)
3508 {
3509   plug->env.cfg = cfg;
3510   plug->env.sched = sched;
3511   plug->env.my_identity = &my_identity;
3512   plug->env.cls = plug;
3513   plug->env.receive = &plugin_env_receive;
3514   plug->env.notify_address = &plugin_env_notify_address;
3515   plug->env.max_connections = max_connect_per_transport;
3516   plug->env.stats = stats;
3517 }
3518
3519
3520 /**
3521  * Start the specified transport (load the plugin).
3522  */
3523 static void
3524 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
3525 {
3526   struct TransportPlugin *plug;
3527   char *libname;
3528
3529   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3530               _("Loading `%s' transport plugin\n"), name);
3531   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3532   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3533   create_environment (plug);
3534   plug->short_name = GNUNET_strdup (name);
3535   plug->lib_name = libname;
3536   plug->next = plugins;
3537   plugins = plug;
3538   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3539   if (plug->api == NULL)
3540     {
3541       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3542                   _("Failed to load transport plugin for `%s'\n"), name);
3543       GNUNET_free (plug->short_name);
3544       plugins = plug->next;
3545       GNUNET_free (libname);
3546       GNUNET_free (plug);
3547     }
3548 }
3549
3550
3551 /**
3552  * Called whenever a client is disconnected.  Frees our
3553  * resources associated with that client.
3554  *
3555  * @param cls closure
3556  * @param client identification of the client
3557  */
3558 static void
3559 client_disconnect_notification (void *cls,
3560                                 struct GNUNET_SERVER_Client *client)
3561 {
3562   struct TransportClient *pos;
3563   struct TransportClient *prev;
3564   struct ClientMessageQueueEntry *mqe;
3565
3566   if (client == NULL)
3567     return;
3568 #if DEBUG_TRANSPORT
3569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3570               "Client disconnected, cleaning up.\n");
3571 #endif
3572   prev = NULL;
3573   pos = clients;
3574   while ((pos != NULL) && (pos->client != client))
3575     {
3576       prev = pos;
3577       pos = pos->next;
3578     }
3579   if (pos == NULL)
3580     return;
3581   while (NULL != (mqe = pos->message_queue_head))
3582     {
3583       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3584                                    pos->message_queue_tail,
3585                                    mqe);
3586       pos->message_count--;
3587       GNUNET_free (mqe);
3588     }
3589   if (prev == NULL)
3590     clients = pos->next;
3591   else
3592     prev->next = pos->next;
3593   if (GNUNET_YES == pos->tcs_pending)
3594     {
3595       pos->client = NULL;
3596       return;
3597     }
3598   if (pos->th != NULL)
3599     {
3600       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3601       pos->th = NULL;
3602     }
3603   GNUNET_break (0 == pos->message_count);
3604   GNUNET_free (pos);
3605 }
3606
3607
3608 /**
3609  * Iterator to free entries in the validation_map.
3610  *
3611  * @param cls closure (unused)
3612  * @param key current key code
3613  * @param value value in the hash map (validation to abort)
3614  * @return GNUNET_YES (always)
3615  */
3616 static int 
3617 abort_validation (void *cls,
3618                   const GNUNET_HashCode * key,
3619                   void *value)
3620 {
3621   struct ValidationEntry *va = value;
3622
3623   GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3624   GNUNET_free (va->transport_name);
3625   GNUNET_free (va);
3626   return GNUNET_YES;
3627 }
3628
3629
3630 /**
3631  * Function called when the service shuts down.  Unloads our plugins
3632  * and cancels pending validations.
3633  *
3634  * @param cls closure, unused
3635  * @param tc task context (unused)
3636  */
3637 static void
3638 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3639 {
3640   struct TransportPlugin *plug;
3641   struct OwnAddressList *al;
3642   struct CheckHelloValidatedContext *chvc;
3643
3644   while (neighbours != NULL)
3645     disconnect_neighbour (neighbours, GNUNET_NO);
3646 #if DEBUG_TRANSPORT
3647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3648               "Transport service is unloading plugins...\n");
3649 #endif
3650   while (NULL != (plug = plugins))
3651     {
3652       plugins = plug->next;
3653       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3654       GNUNET_free (plug->lib_name);
3655       GNUNET_free (plug->short_name);
3656       while (NULL != (al = plug->addresses))
3657         {
3658           plug->addresses = al->next;
3659           GNUNET_free (al);
3660         }
3661       GNUNET_free (plug);
3662     }
3663   if (my_private_key != NULL)
3664     GNUNET_CRYPTO_rsa_key_free (my_private_key);
3665   GNUNET_free_non_null (our_hello);
3666
3667   /* free 'chvc' data structure */
3668   while (NULL != (chvc = chvc_head))
3669     {
3670       chvc_head = chvc->next;
3671       GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3672       GNUNET_free (chvc);
3673     }
3674   chvc_tail = NULL;
3675
3676   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3677                                          &abort_validation,
3678                                          NULL);
3679   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3680   validation_map = NULL;
3681   if (stats != NULL)
3682     {
3683       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3684       stats = NULL;
3685     }
3686 }
3687
3688
3689 /**
3690  * Initiate transport service.
3691  *
3692  * @param cls closure
3693  * @param s scheduler to use
3694  * @param serv the initialized server
3695  * @param c configuration to use
3696  */
3697 static void
3698 run (void *cls,
3699      struct GNUNET_SCHEDULER_Handle *s,
3700      struct GNUNET_SERVER_Handle *serv,
3701      const struct GNUNET_CONFIGURATION_Handle *c)
3702 {
3703   char *plugs;
3704   char *pos;
3705   int no_transports;
3706   unsigned long long tneigh;
3707   char *keyfile;
3708
3709   sched = s;
3710   cfg = c;
3711   stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3712   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3713   /* parse configuration */
3714   if ((GNUNET_OK !=
3715        GNUNET_CONFIGURATION_get_value_number (c,
3716                                               "TRANSPORT",
3717                                               "NEIGHBOUR_LIMIT",
3718                                               &tneigh)) ||
3719       (GNUNET_OK !=
3720        GNUNET_CONFIGURATION_get_value_filename (c,
3721                                                 "GNUNETD",
3722                                                 "HOSTKEY", &keyfile)))
3723     {
3724       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3725                   _
3726                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
3727       GNUNET_SCHEDULER_shutdown (s);
3728       if (stats != NULL)
3729         {
3730           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3731           stats = NULL;
3732         }
3733       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3734       validation_map = NULL;
3735       return;
3736     }
3737   max_connect_per_transport = (uint32_t) tneigh;
3738   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3739   GNUNET_free (keyfile);
3740   if (my_private_key == NULL)
3741     {
3742       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3743                   _
3744                   ("Transport service could not access hostkey.  Exiting.\n"));
3745       GNUNET_SCHEDULER_shutdown (s);
3746       if (stats != NULL)
3747         {
3748           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3749           stats = NULL;
3750         }
3751       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3752       validation_map = NULL;
3753       return;
3754     }
3755   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3756   GNUNET_CRYPTO_hash (&my_public_key,
3757                       sizeof (my_public_key), &my_identity.hashPubKey);
3758   /* setup notification */
3759   server = serv;
3760   GNUNET_SERVER_disconnect_notify (server,
3761                                    &client_disconnect_notification, NULL);
3762   /* load plugins... */
3763   no_transports = 1;
3764   if (GNUNET_OK ==
3765       GNUNET_CONFIGURATION_get_value_string (c,
3766                                              "TRANSPORT", "PLUGINS", &plugs))
3767     {
3768       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3769                   _("Starting transport plugins `%s'\n"), plugs);
3770       pos = strtok (plugs, " ");
3771       while (pos != NULL)
3772         {
3773           start_transport (server, pos);
3774           no_transports = 0;
3775           pos = strtok (NULL, " ");
3776         }
3777       GNUNET_free (plugs);
3778     }
3779   GNUNET_SCHEDULER_add_delayed (sched,
3780                                 GNUNET_TIME_UNIT_FOREVER_REL,
3781                                 &shutdown_task, NULL);
3782   if (no_transports)
3783     refresh_hello ();
3784
3785 #if DEBUG_TRANSPORT
3786   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3787 #endif
3788   /* process client requests */
3789   GNUNET_SERVER_add_handlers (server, handlers);
3790 }
3791
3792
3793 /**
3794  * The main function for the transport service.
3795  *
3796  * @param argc number of arguments from the command line
3797  * @param argv command line arguments
3798  * @return 0 ok, 1 on error
3799  */
3800 int
3801 main (int argc, char *const *argv)
3802 {
3803   return (GNUNET_OK ==
3804           GNUNET_SERVICE_run (argc,
3805                               argv,
3806                               "transport",
3807                               GNUNET_SERVICE_OPTION_NONE,
3808                               &run, NULL)) ? 0 : 1;
3809 }
3810
3811 /* end of gnunet-service-transport.c */