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