also print inbound addresses
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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 3, 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  */
27 #include "platform.h"
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
41 #include "transport_ats.h"
42
43
44 #define DEBUG_BLACKLIST GNUNET_NO
45
46 #define DEBUG_PING_PONG GNUNET_NO
47
48 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
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.  Note that
64  * this value must be about as large as 'TOTAL_MSGS' in the
65  * 'test_transport_api_reliability.c', otherwise that testcase may
66  * fail.
67  */
68 #define MAX_PENDING (128 * 1024)
69
70 /**
71  * Size of the per-transport blacklist hash maps.
72  */
73 #define TRANSPORT_BLACKLIST_HT_SIZE 16
74
75 /**
76  * How often should we try to reconnect to a peer using a particular
77  * transport plugin before giving up?  Note that the plugin may be
78  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
79  */
80 #define MAX_CONNECT_RETRY 3
81
82 /**
83  * Limit on the number of ready-to-run tasks when validating
84  * HELLOs.  If more tasks are ready to run, we will drop
85  * HELLOs instead of validating them.
86  */
87 #define MAX_HELLO_LOAD 4
88
89 /**
90  * How often must a peer violate bandwidth quotas before we start
91  * to simply drop its messages?
92  */
93 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
94
95 /**
96  * How long until a HELLO verification attempt should time out?
97  * Must be rather small, otherwise a partially successful HELLO
98  * validation (some addresses working) might not be available
99  * before a client's request for a connection fails for good.
100  * Besides, if a single request to an address takes a long time,
101  * then the peer is unlikely worthwhile anyway.
102  */
103 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
104
105 /**
106  * How long is a PONG signature valid?  We'll recycle a signature until
107  * 1/4 of this time is remaining.  PONGs should expire so that if our
108  * external addresses change an adversary cannot replay them indefinitely.
109  * OTOH, we don't want to spend too much time generating PONG signatures,
110  * so they must have some lifetime to reduce our CPU usage.
111  */
112 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
113
114 /**
115  * Priority to use for PONG messages.
116  */
117 #define TRANSPORT_PONG_PRIORITY 4
118
119 /**
120  * How often do we re-add (cheaper) plugins to our list of plugins
121  * to try for a given connected peer?
122  */
123 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
124
125 /**
126  * After how long do we expire an address in a HELLO that we just
127  * validated?  This value is also used for our own addresses when we
128  * create a HELLO.
129  */
130 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
131
132
133 /**
134  * How long before an existing address expires should we again try to
135  * validate it?  Must be (significantly) smaller than
136  * HELLO_ADDRESS_EXPIRATION.
137  */
138 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
139
140 /**
141  * Maximum frequency for re-evaluating latencies for all transport addresses.
142  */
143 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144
145 /**
146  * Maximum frequency for re-evaluating latencies for connected addresses.
147  */
148 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
149
150 /**
151  * List of addresses of other peers
152  */
153 struct ForeignAddressList
154 {
155   /**
156    * This is a linked list.
157    */
158   struct ForeignAddressList *next;
159
160   /**
161    * Which ready list does this entry belong to.
162    */
163   struct ReadyList *ready_list;
164
165   /**
166    * How long until we auto-expire this address (unless it is
167    * re-confirmed by the transport)?
168    */
169   struct GNUNET_TIME_Absolute expires;
170
171   /**
172    * Task used to re-validate addresses, updates latencies and
173    * verifies liveness.
174    */
175   GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176
177   /**
178    * The address.
179    */
180   const void *addr;
181
182   /**
183    * Session (or NULL if no valid session currently exists or if the
184    * plugin does not use sessions).
185    */
186   struct Session *session;
187
188   struct ATS_ressource_entry * ressources;
189
190   struct ATS_quality_entry * quality;
191
192   /**
193    * What was the last latency observed for this address, plugin and peer?
194    */
195   struct GNUNET_TIME_Relative latency;
196
197   /**
198    * If we did not successfully transmit a message to the given peer
199    * via this connection during the specified time, we should consider
200    * the connection to be dead.  This is used in the case that a TCP
201    * transport simply stalls writing to the stream but does not
202    * formerly get a signal that the other peer died.
203    */
204   struct GNUNET_TIME_Absolute timeout;
205
206   /**
207    * How often have we tried to connect using this plugin?  Used to
208    * discriminate against addresses that do not work well.
209    * FIXME: not yet used, but should be!
210    */
211   unsigned int connect_attempts;
212
213   /**
214    * DV distance to this peer (1 if no DV is used).
215    * FIXME: need to set this from transport plugins!
216    */
217   uint32_t distance;
218
219   /**
220    * Length of addr.
221    */
222   uint16_t addrlen;
223
224   /**
225    * Have we ever estimated the latency of this address?  Used to
226    * ensure that the first time we add an address, we immediately
227    * probe its latency.
228    */
229   int8_t estimated;
230
231   /**
232    * Are we currently connected via this address?  The first time we
233    * successfully transmit or receive data to a peer via a particular
234    * address, we set this to GNUNET_YES.  If we later get an error
235    * (disconnect notification, transmission failure, timeout), we set
236    * it back to GNUNET_NO.
237    */
238   int8_t connected;
239
240   /**
241    * Is this plugin currently busy transmitting to the specific target?
242    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
243    * messages do not count as 'in transmit'.
244    */
245   int8_t in_transmit;
246
247   /**
248    * Has this address been validated yet?
249    */
250   int8_t validated;
251
252 };
253
254
255 /**
256  * Entry in linked list of network addresses for ourselves.  Also
257  * includes a cached signature for 'struct TransportPongMessage's.
258  */
259 struct OwnAddressList
260 {
261   /**
262    * This is a linked list.
263    */
264   struct OwnAddressList *next;
265
266   /**
267    * How long until the current signature expires? (ZERO if the
268    * signature was never created).
269    */
270   struct GNUNET_TIME_Absolute pong_sig_expires;
271
272   /**
273    * Signature for a 'struct TransportPongMessage' for this address.
274    */
275   struct GNUNET_CRYPTO_RsaSignature pong_signature;
276
277   /**
278    * Length of addr.
279    */
280   uint32_t addrlen;
281
282 };
283
284
285 /**
286  * Entry in linked list of all of our plugins.
287  */
288 struct TransportPlugin
289 {
290   /**
291    * This is a linked list.
292    */
293   struct TransportPlugin *next;
294
295   /**
296    * API of the transport as returned by the plugin's
297    * initialization function.
298    */
299   struct GNUNET_TRANSPORT_PluginFunctions *api;
300
301   /**
302    * Short name for the plugin (i.e. "tcp").
303    */
304   char *short_name;
305
306   /**
307    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
308    */
309   char *lib_name;
310
311   /**
312    * List of our known addresses for this transport.
313    */
314   struct OwnAddressList *addresses;
315
316   /**
317    * Environment this transport service is using
318    * for this plugin.
319    */
320   struct GNUNET_TRANSPORT_PluginEnvironment env;
321
322   /**
323    * ID of task that is used to clean up expired addresses.
324    */
325   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
326
327   /**
328    * Set to GNUNET_YES if we need to scrap the existing list of
329    * "addresses" and start fresh when we receive the next address
330    * update from a transport.  Set to GNUNET_NO if we should just add
331    * the new address to the list and wait for the commit call.
332    */
333   int rebuild;
334
335   struct ATS_plugin * rc;
336
337   /**
338    * Hashmap of blacklisted peers for this particular transport.
339    */
340   struct GNUNET_CONTAINER_MultiHashMap *blacklist;
341 };
342
343 struct NeighbourList;
344
345 /**
346  * For each neighbour we keep a list of messages
347  * that we still want to transmit to the neighbour.
348  */
349 struct MessageQueue
350 {
351
352   /**
353    * This is a doubly linked list.
354    */
355   struct MessageQueue *next;
356
357   /**
358    * This is a doubly linked list.
359    */
360   struct MessageQueue *prev;
361
362   /**
363    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
364    * stuck together in memory.  Allocated at the end of this struct.
365    */
366   const char *message_buf;
367
368   /**
369    * Size of the message buf
370    */
371   size_t message_buf_size;
372
373   /**
374    * Client responsible for queueing the message;
375    * used to check that a client has no two messages
376    * pending for the same target.  Can be NULL.
377    */
378   struct TransportClient *client;
379
380   /**
381    * Using which specific address should we send this message?
382    */
383   struct ForeignAddressList *specific_address;
384
385   /**
386    * Peer ID of the Neighbour this entry belongs to.
387    */
388   struct GNUNET_PeerIdentity neighbour_id;
389
390   /**
391    * Plugin that we used for the transmission.
392    * NULL until we scheduled a transmission.
393    */
394   struct TransportPlugin *plugin;
395
396   /**
397    * At what time should we fail?
398    */
399   struct GNUNET_TIME_Absolute timeout;
400
401   /**
402    * Internal message of the transport system that should not be
403    * included in the usual SEND-SEND_OK transmission confirmation
404    * traffic management scheme.  Typically, "internal_msg" will
405    * be set whenever "client" is NULL (but it is not strictly
406    * required).
407    */
408   int internal_msg;
409
410   /**
411    * How important is the message?
412    */
413   unsigned int priority;
414
415 };
416
417
418 /**
419  * For a given Neighbour, which plugins are available
420  * to talk to this peer and what are their costs?
421  */
422 struct ReadyList
423 {
424   /**
425    * This is a linked list.
426    */
427   struct ReadyList *next;
428
429   /**
430    * Which of our transport plugins does this entry
431    * represent?
432    */
433   struct TransportPlugin *plugin;
434
435   /**
436    * Transport addresses, latency, and readiness for
437    * this particular plugin.
438    */
439   struct ForeignAddressList *addresses;
440
441   /**
442    * To which neighbour does this ready list belong to?
443    */
444   struct NeighbourList *neighbour;
445 };
446
447
448 /**
449  * Entry in linked list of all of our current neighbours.
450  */
451 struct NeighbourList
452 {
453
454   /**
455    * This is a linked list.
456    */
457   struct NeighbourList *next;
458
459   /**
460    * Which of our transports is connected to this peer
461    * and what is their status?
462    */
463   struct ReadyList *plugins;
464
465   /**
466    * Head of list of messages we would like to send to this peer;
467    * must contain at most one message per client.
468    */
469   struct MessageQueue *messages_head;
470
471   /**
472    * Tail of list of messages we would like to send to this peer; must
473    * contain at most one message per client.
474    */
475   struct MessageQueue *messages_tail;
476
477   /**
478    * Head of list of messages of messages we expected the continuation
479    * to be called to destroy the message
480    */
481   struct MessageQueue *cont_head;
482
483   /**
484    * Tail of list of messages of messages we expected the continuation
485    * to be called to destroy the message
486    */
487   struct MessageQueue *cont_tail;
488
489   /**
490    * Buffer for at most one payload message used when we receive
491    * payload data before our PING-PONG has succeeded.  We then
492    * store such messages in this intermediary buffer until the
493    * connection is fully up.
494    */
495   struct GNUNET_MessageHeader *pre_connect_message_buffer;
496
497   /**
498    * Context for peerinfo iteration.
499    * NULL after we are done processing peerinfo's information.
500    */
501   struct GNUNET_PEERINFO_IteratorContext *piter;
502
503   /**
504    * Public key for this peer.   Valid only if the respective flag is set below.
505    */
506   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
507
508   /**
509    * Identity of this neighbour.
510    */
511   struct GNUNET_PeerIdentity id;
512
513   /**
514    * ID of task scheduled to run when this peer is about to
515    * time out (will free resources associated with the peer).
516    */
517   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
518
519   /**
520    * ID of task scheduled to run when we should retry transmitting
521    * the head of the message queue.  Actually triggered when the
522    * transmission is timing out (we trigger instantly when we have
523    * a chance of success).
524    */
525   GNUNET_SCHEDULER_TaskIdentifier retry_task;
526
527   /**
528    * How long until we should consider this peer dead
529    * (if we don't receive another message in the
530    * meantime)?
531    */
532   struct GNUNET_TIME_Absolute peer_timeout;
533
534   /**
535    * Tracker for inbound bandwidth.
536    */
537   struct GNUNET_BANDWIDTH_Tracker in_tracker;
538
539   /**
540    * The latency we have seen for this particular address for
541    * this particular peer.  This latency may have been calculated
542    * over multiple transports.  This value reflects how long it took
543    * us to receive a response when SENDING via this particular
544    * transport/neighbour/address combination!
545    *
546    * FIXME: we need to periodically send PINGs to update this
547    * latency (at least more often than the current "huge" (11h?)
548    * update interval).
549    */
550   struct GNUNET_TIME_Relative latency;
551
552   /**
553    * How often has the other peer (recently) violated the
554    * inbound traffic limit?  Incremented by 10 per violation,
555    * decremented by 1 per non-violation (for each
556    * time interval).
557    */
558   unsigned int quota_violation_count;
559
560   /**
561    * DV distance to this peer (1 if no DV is used).
562    */
563   uint32_t distance;
564
565   /**
566    * Have we seen an PONG from this neighbour in the past (and
567    * not had a disconnect since)?
568    */
569   int received_pong;
570
571   /**
572    * Do we have a valid public key for this neighbour?
573    */
574   int public_key_valid;
575
576   /**
577    * Performance data for the peer.
578    */
579   struct GNUNET_TRANSPORT_ATS_Information *ats;
580 };
581
582 /**
583  * Message used to ask a peer to validate receipt (to check an address
584  * from a HELLO).  Followed by the address we are trying to validate,
585  * or an empty address if we are just sending a PING to confirm that a
586  * connection which the receiver (of the PING) initiated is still valid.
587  */
588 struct TransportPingMessage
589 {
590
591   /**
592    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
593    */
594   struct GNUNET_MessageHeader header;
595
596   /**
597    * Challenge code (to ensure fresh reply).
598    */
599   uint32_t challenge GNUNET_PACKED;
600
601   /**
602    * Who is the intended recipient?
603    */
604   struct GNUNET_PeerIdentity target;
605
606 };
607
608
609 /**
610  * Message used to validate a HELLO.  The challenge is included in the
611  * confirmation to make matching of replies to requests possible.  The
612  * signature signs our public key, an expiration time and our address.<p>
613  *
614  * This message is followed by our transport address that the PING tried
615  * to confirm (if we liked it).  The address can be empty (zero bytes)
616  * if the PING had not address either (and we received the request via
617  * a connection that we initiated).
618  */
619 struct TransportPongMessage
620 {
621
622   /**
623    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
624    */
625   struct GNUNET_MessageHeader header;
626
627   /**
628    * Challenge code from PING (showing freshness).  Not part of what
629    * is signed so that we can re-use signatures.
630    */
631   uint32_t challenge GNUNET_PACKED;
632
633   /**
634    * Signature.
635    */
636   struct GNUNET_CRYPTO_RsaSignature signature;
637
638   /**
639    * What are we signing and why?  Two possible reason codes can be here:
640    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
641    * plausible address for this peer (pid is set to identity of signer); or
642    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
643    * an address we used to connect to the peer with the given pid.
644    */
645   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
646
647   /**
648    * When does this signature expire?
649    */
650   struct GNUNET_TIME_AbsoluteNBO expiration;
651
652   /**
653    * Either the identity of the peer Who signed this message, or the
654    * identity of the peer that we're connected to using the given
655    * address (depending on purpose.type).
656    */
657   struct GNUNET_PeerIdentity pid;
658
659   /**
660    * Size of address appended to this message (part of what is
661    * being signed, hence not redundant).
662    */
663   uint32_t addrlen;
664
665 };
666
667
668 /**
669  * Linked list of messages to be transmitted to the client.  Each
670  * entry is followed by the actual message.
671  */
672 struct ClientMessageQueueEntry
673 {
674   /**
675    * This is a doubly-linked list.
676    */
677   struct ClientMessageQueueEntry *next;
678
679   /**
680    * This is a doubly-linked list.
681    */
682   struct ClientMessageQueueEntry *prev;
683 };
684
685
686 /**
687  * Client connected to the transport service.
688  */
689 struct TransportClient
690 {
691
692   /**
693    * This is a linked list.
694    */
695   struct TransportClient *next;
696
697   /**
698    * Handle to the client.
699    */
700   struct GNUNET_SERVER_Client *client;
701
702   /**
703    * Linked list of messages yet to be transmitted to
704    * the client.
705    */
706   struct ClientMessageQueueEntry *message_queue_head;
707
708   /**
709    * Tail of linked list of messages yet to be transmitted to the
710    * client.
711    */
712   struct ClientMessageQueueEntry *message_queue_tail;
713
714   /**
715    * Current transmit request handle.
716    */
717   struct GNUNET_CONNECTION_TransmitHandle *th;
718
719   /**
720    * Is a call to "transmit_send_continuation" pending?  If so, we
721    * must not free this struct (even if the corresponding client
722    * disconnects) and instead only remove it from the linked list and
723    * set the "client" field to NULL.
724    */
725   int tcs_pending;
726
727   /**
728    * Length of the list of messages pending for this client.
729    */
730   unsigned int message_count;
731
732 };
733
734
735 /**
736  * Context of currently active requests to peerinfo
737  * for validation of HELLOs.
738  */
739 struct CheckHelloValidatedContext;
740
741
742 /**
743  * Entry in map of all HELLOs awaiting validation.
744  */
745 struct ValidationEntry 
746 {
747
748   /**
749    * NULL if this entry is not part of a larger HELLO validation.
750    */
751   struct CheckHelloValidatedContext *chvc;
752
753   /**
754    * The address, actually a pointer to the end
755    * of this struct.  Do not free!
756    */
757   const void *addr;
758
759   /**
760    * Name of the transport.
761    */
762   char *transport_name;
763
764   /**
765    * The public key of the peer.
766    */
767   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
768
769   /**
770    * ID of task that will clean up this entry if we don't succeed
771    * with the validation first.
772    */
773   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
774
775   /**
776    * At what time did we send this validation?
777    */
778   struct GNUNET_TIME_Absolute send_time;
779
780   /**
781    * Session being validated (or NULL for none).
782    */
783   struct Session *session;
784
785   /**
786    * Challenge number we used.
787    */
788   uint32_t challenge;
789
790   /**
791    * Length of addr.
792    */
793   uint16_t addrlen;
794
795 };
796
797
798 /**
799  * Context of currently active requests to peerinfo
800  * for validation of HELLOs.
801  */
802 struct CheckHelloValidatedContext
803 {
804
805   /**
806    * This is a doubly-linked list.
807    */
808   struct CheckHelloValidatedContext *next;
809
810   /**
811    * This is a doubly-linked list.
812    */
813   struct CheckHelloValidatedContext *prev;
814
815   /**
816    * Hello that we are validating.
817    */
818   const struct GNUNET_HELLO_Message *hello;
819
820   /**
821    * Context for peerinfo iteration.
822    * NULL after we are done processing peerinfo's information.
823    */
824   struct GNUNET_PEERINFO_IteratorContext *piter;
825
826   /**
827    * Was a HELLO known for this peer to peerinfo?
828    */
829   int hello_known;
830
831   /**
832    * Number of validation entries currently referring to this
833    * CHVC.
834    */
835   unsigned int ve_count;
836 };
837
838
839 /**
840  * Our HELLO message.
841  */
842 static struct GNUNET_HELLO_Message *our_hello;
843
844 /**
845  * Our public key.
846  */
847 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
848
849 /**
850  * Our identity.
851  */
852 static struct GNUNET_PeerIdentity my_identity;
853
854 /**
855  * Our private key.
856  */
857 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
858
859 /**
860  * Our configuration.
861  */
862 const struct GNUNET_CONFIGURATION_Handle *cfg;
863
864 /**
865  * Linked list of all clients to this service.
866  */
867 static struct TransportClient *clients;
868
869 /**
870  * All loaded plugins.
871  */
872 static struct TransportPlugin *plugins;
873
874 /**
875  * Handle to peerinfo service.
876  */
877 static struct GNUNET_PEERINFO_Handle *peerinfo;
878
879 /**
880  * All known neighbours and their HELLOs.
881  */
882 static struct NeighbourList *neighbours;
883
884 /**
885  * Number of neighbours we'd like to have.
886  */
887 static uint32_t max_connect_per_transport;
888
889 /**
890  * Head of linked list.
891  */
892 static struct CheckHelloValidatedContext *chvc_head;
893
894 /**
895  * Tail of linked list.
896  */
897 static struct CheckHelloValidatedContext *chvc_tail;
898
899 /**
900  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
901  * of the given peer that we are currently validating).
902  */
903 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
904
905 /**
906  * Handle for reporting statistics.
907  */
908 static struct GNUNET_STATISTICS_Handle *stats;
909
910 /**
911  * Identifier of 'refresh_hello' task.
912  */
913 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
914
915 /**
916  * Identifier of ats scheduler task.
917  */
918 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
919
920 /**
921  * Is transport service shutting down ?
922  */
923 static int shutdown_in_progress;
924
925 /**
926  * Handle for ats information
927  */
928 static struct ATS_Handle *ats;
929
930 /**
931  * Time of last ats execution
932  */
933 struct GNUNET_TIME_Absolute last_ats_execution;
934 /**
935  * Minimum interval between two ATS executions
936  */
937 struct GNUNET_TIME_Relative ats_minimum_interval;
938 /**
939  * Regular interval when ATS execution is triggered
940  */
941 struct GNUNET_TIME_Relative ats_regular_interval;
942
943 /**
944  * The peer specified by the given neighbour has timed-out or a plugin
945  * has disconnected.  We may either need to do nothing (other plugins
946  * still up), or trigger a full disconnect and clean up.  This
947  * function updates our state and do the necessary notifications.
948  * Also notifies our clients that the neighbour is now officially
949  * gone.
950  *
951  * @param n the neighbour list entry for the peer
952  * @param check should we just check if all plugins
953  *        disconnected or must we ask all plugins to
954  *        disconnect?
955  */
956 static void disconnect_neighbour (struct NeighbourList *n, int check);
957
958 /**
959  * Check the ready list for the given neighbour and if a plugin is
960  * ready for transmission (and if we have a message), do so!
961  *
962  * @param nexi target peer for which to transmit
963  */
964 static void try_transmission_to_peer (struct NeighbourList *n);
965
966 struct ForeignAddressList * get_preferred_ats_address (
967                 struct NeighbourList *n);
968
969 /**
970  * Find an entry in the neighbour list for a particular peer.
971  *
972  * @return NULL if not found.
973  */
974 static struct NeighbourList *
975 find_neighbour (const struct GNUNET_PeerIdentity *key)
976 {
977   struct NeighbourList *head = neighbours;
978
979   while ((head != NULL) &&
980         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
981     head = head->next;
982   return head;
983 }
984
985 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
986 {
987   int c;
988   int set = GNUNET_NO;
989   for (c=0; c<available_quality_metrics; c++)
990   {
991     if (ats_index == qm[c].atis_index)
992     {
993       fal->quality[c].values[0] = fal->quality[c].values[1];
994       fal->quality[c].values[1] = fal->quality[c].values[2];
995       fal->quality[c].values[2] = value;
996       set = GNUNET_YES;
997       ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
998     }
999   }
1000   if (set == GNUNET_NO)
1001   {
1002     for (c=0; c<available_ressources; c++)
1003     {
1004       if (ats_index == ressources[c].atis_index)
1005       {
1006         fal->ressources[c].c = value;
1007         set = GNUNET_YES;
1008         ats_modify_problem_state (ats, ATS_COST_UPDATED);
1009       }
1010     }
1011   }
1012   return set;
1013 }
1014
1015 static int
1016 update_addr_ats (struct ForeignAddressList *fal, 
1017                  const struct GNUNET_TRANSPORT_ATS_Information *ats_data, 
1018                  int ats_count)
1019 {
1020   int c1, set;
1021   set = GNUNET_NO;
1022   for (c1=0; c1<ats_count; c1++)
1023     {
1024       set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1025     }
1026   return set;
1027 }
1028
1029 /**
1030  * Find an entry in the transport list for a particular transport.
1031  *
1032  * @return NULL if not found.
1033  */
1034 static struct TransportPlugin *
1035 find_transport (const char *short_name)
1036 {
1037   struct TransportPlugin *head = plugins;
1038   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1039     head = head->next;
1040   return head;
1041 }
1042
1043 /**
1044  * Is a particular peer blacklisted for a particular transport?
1045  *
1046  * @param peer the peer to check for
1047  * @param plugin the plugin used to connect to the peer
1048  *
1049  * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1050  */
1051 static int
1052 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1053 {
1054
1055   if (plugin->blacklist != NULL)
1056     {
1057       if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1058         {
1059 #if DEBUG_BLACKLIST
1060           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061                       "Peer `%s:%s' is blacklisted!\n",
1062                       plugin->short_name, GNUNET_i2s (peer));
1063 #endif
1064           if (stats != NULL)
1065             GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1066           return GNUNET_YES;
1067         }
1068     }
1069
1070   return GNUNET_NO;
1071 }
1072
1073
1074 static void
1075 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, 
1076                        char *transport_name)
1077 {
1078   struct TransportPlugin *plugin;
1079
1080   plugin = find_transport(transport_name);
1081   if (plugin == NULL) /* Nothing to do */
1082     return;
1083 #if DEBUG_TRANSPORT
1084   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085               "Adding peer `%s' with plugin `%s' to blacklist\n",
1086               GNUNET_i2s (peer),
1087               transport_name);
1088 #endif
1089   if (plugin->blacklist == NULL)
1090     plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1091   GNUNET_assert(plugin->blacklist != NULL);
1092   GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1093                                     NULL,
1094                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1095 }
1096
1097
1098 /**
1099  * Read the blacklist file, containing transport:peer entries.
1100  * Provided the transport is loaded, set up hashmap with these
1101  * entries to blacklist peers by transport.
1102  *
1103  */
1104 static void
1105 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1106 {
1107   char *fn;
1108   char *data;
1109   size_t pos;
1110   size_t colon_pos;
1111   int tsize;
1112   struct GNUNET_PeerIdentity pid;
1113   struct stat frstat;
1114   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1115   unsigned int entries_found;
1116   char *transport_name;
1117
1118   if (GNUNET_OK !=
1119       GNUNET_CONFIGURATION_get_value_filename (cfg,
1120                                                "TRANSPORT",
1121                                                "BLACKLIST_FILE",
1122                                                &fn))
1123     {
1124 #if DEBUG_TRANSPORT
1125       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1126                   "Option `%s' in section `%s' not specified!\n",
1127                   "BLACKLIST_FILE",
1128                   "TRANSPORT");
1129 #endif
1130       return;
1131     }
1132   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1133     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1134         | GNUNET_DISK_PERM_USER_WRITE);
1135   if (0 != STAT (fn, &frstat))
1136     {
1137       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1138                   _("Could not read blacklist file `%s'\n"), fn);
1139       GNUNET_free (fn);
1140       return;
1141     }
1142   if (frstat.st_size == 0)
1143     {
1144 #if DEBUG_TRANSPORT
1145       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146                   _("Blacklist file `%s' is empty.\n"),
1147                   fn);
1148 #endif
1149       GNUNET_free (fn);
1150       return;
1151     }
1152   /* FIXME: use mmap */
1153   data = GNUNET_malloc_large (frstat.st_size);
1154   GNUNET_assert(data != NULL);
1155   if (frstat.st_size !=
1156       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1157     {
1158       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1159                   _("Failed to read blacklist from `%s'\n"), fn);
1160       GNUNET_free (fn);
1161       GNUNET_free (data);
1162       return;
1163     }
1164   entries_found = 0;
1165   pos = 0;
1166   while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1167     pos++;
1168   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1169          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1170     {
1171       colon_pos = pos;
1172       while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1173         colon_pos++;
1174
1175       if (colon_pos >= frstat.st_size)
1176         {
1177           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1178                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1179                       (unsigned long long) colon_pos);
1180           GNUNET_free (fn);
1181           GNUNET_free (data);
1182           return;
1183         }
1184
1185       if (isspace( (unsigned char) data[colon_pos]))
1186       {
1187         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1188                     _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1189                     (unsigned long long) colon_pos);
1190         pos = colon_pos;
1191         while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1192           pos++;
1193         continue;
1194       }
1195       tsize = colon_pos - pos;
1196       if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1197         {
1198           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1199                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1200                       (unsigned long long) colon_pos);
1201           GNUNET_free (fn);
1202           GNUNET_free (data);
1203           return;
1204         }
1205
1206       if (tsize < 1)
1207         continue;
1208
1209       transport_name = GNUNET_malloc(tsize + 1);
1210       memcpy(transport_name, &data[pos], tsize);
1211       pos = colon_pos + 1;
1212 #if DEBUG_TRANSPORT
1213       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214                   "Read transport name %s in blacklist file.\n",
1215                   transport_name);
1216 #endif
1217       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1218       if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1219         {
1220           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1221                       _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1222                       (unsigned long long) pos);
1223           pos++;
1224           while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1225             pos++;
1226           GNUNET_free_non_null(transport_name);
1227           continue;
1228         }
1229       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1230       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1231         {
1232           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1233                       _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1234                       (unsigned long long) pos,
1235                       &enc);
1236         }
1237       else
1238         {
1239           if (0 != memcmp (&pid,
1240                            &my_identity,
1241                            sizeof (struct GNUNET_PeerIdentity)))
1242             {
1243               entries_found++;
1244               add_peer_to_blacklist (&pid,
1245                                      transport_name);
1246             }
1247           else
1248             {
1249               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1250                           _("Found myself `%s' in blacklist (useless, ignored)\n"),
1251                           GNUNET_i2s (&pid));
1252             }
1253         }
1254       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1255       GNUNET_free_non_null(transport_name);
1256       while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1257         pos++;
1258     }
1259   GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1260   GNUNET_free (data);
1261   GNUNET_free (fn);
1262 }
1263
1264
1265 /**
1266  * Function called to notify a client about the socket being ready to
1267  * queue more data.  "buf" will be NULL and "size" zero if the socket
1268  * was closed for writing in the meantime.
1269  *
1270  * @param cls closure
1271  * @param size number of bytes available in buf
1272  * @param buf where the callee should write the message
1273  * @return number of bytes written to buf
1274  */
1275 static size_t
1276 transmit_to_client_callback (void *cls, size_t size, void *buf)
1277 {
1278   struct TransportClient *client = cls;
1279   struct ClientMessageQueueEntry *q;
1280   uint16_t msize;
1281   size_t tsize;
1282   const struct GNUNET_MessageHeader *msg;
1283   char *cbuf;
1284
1285   client->th = NULL;
1286   if (buf == NULL)
1287     {
1288 #if DEBUG_TRANSPORT 
1289       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1290                   "Transmission to client failed, closing connection.\n");
1291 #endif
1292       /* fatal error with client, free message queue! */
1293       while (NULL != (q = client->message_queue_head))
1294         {
1295           GNUNET_STATISTICS_update (stats,
1296                                     gettext_noop ("# bytes discarded (could not transmit to client)"),
1297                                     ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1298                                     GNUNET_NO);
1299           GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1300                                        client->message_queue_tail,
1301                                        q);
1302           GNUNET_free (q);
1303         }
1304       client->message_count = 0;
1305       return 0;
1306     }
1307   cbuf = buf;
1308   tsize = 0;
1309   while (NULL != (q = client->message_queue_head))
1310     {
1311       msg = (const struct GNUNET_MessageHeader *) &q[1];
1312       msize = ntohs (msg->size);
1313       if (msize + tsize > size)
1314         break;
1315 #if DEBUG_TRANSPORT
1316       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317                   "Transmitting message of type %u to client.\n",
1318                   ntohs (msg->type));
1319 #endif
1320       GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1321                                    client->message_queue_tail,
1322                                    q);
1323       memcpy (&cbuf[tsize], msg, msize);
1324       tsize += msize;
1325       GNUNET_free (q);
1326       client->message_count--;
1327     }
1328   if (NULL != q)
1329     {
1330       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1331       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1332                                                         msize,
1333                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1334                                                         &transmit_to_client_callback,
1335                                                         client);
1336       GNUNET_assert (client->th != NULL);
1337     }
1338   return tsize;
1339 }
1340
1341
1342 /**
1343  * Convert an address to a string.
1344  *
1345  * @param plugin name of the plugin responsible for the address
1346  * @param addr binary address
1347  * @param addr_len number of bytes in addr
1348  * @return NULL on error, otherwise address string
1349  */
1350 static const char*
1351 a2s (const char *plugin,
1352      const void *addr,
1353      uint16_t addr_len)
1354 {
1355   struct TransportPlugin *p;
1356
1357   if (plugin == NULL)
1358     return NULL;
1359   p = find_transport (plugin);
1360   if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1361     return NULL;
1362
1363   return p->api->address_to_string (NULL,
1364                                     addr,
1365                                     addr_len);
1366   return NULL;
1367 }
1368
1369
1370
1371
1372 /**
1373  * Iterator to free entries in the validation_map.
1374  *
1375  * @param cls closure (unused)
1376  * @param key current key code
1377  * @param value value in the hash map (validation to abort)
1378  * @return GNUNET_YES (always)
1379  */
1380 static int
1381 abort_validation (void *cls,
1382                   const GNUNET_HashCode * key,
1383                   void *value)
1384 {
1385   struct ValidationEntry *va = value;
1386
1387   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1388     GNUNET_SCHEDULER_cancel (va->timeout_task);
1389   GNUNET_free (va->transport_name);
1390   if (va->chvc != NULL)
1391     {
1392       va->chvc->ve_count--;
1393       if (va->chvc->ve_count == 0)
1394         {
1395           GNUNET_CONTAINER_DLL_remove (chvc_head,
1396                                        chvc_tail,
1397                                        va->chvc);
1398           GNUNET_free (va->chvc);
1399         }
1400       va->chvc = NULL;
1401     }
1402   GNUNET_free (va);
1403   return GNUNET_YES;
1404 }
1405
1406
1407 /**
1408  * HELLO validation cleanup task (validation failed).
1409  *
1410  * @param cls the 'struct ValidationEntry' that failed
1411  * @param tc scheduler context (unused)
1412  */
1413 static void
1414 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1415 {
1416   struct ValidationEntry *va = cls;
1417   struct GNUNET_PeerIdentity pid;
1418
1419   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1420   GNUNET_STATISTICS_update (stats,
1421                             gettext_noop ("# address validation timeouts"),
1422                             1,
1423                             GNUNET_NO);
1424   GNUNET_CRYPTO_hash (&va->publicKey,
1425                       sizeof (struct
1426                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1427                       &pid.hashPubKey);
1428   GNUNET_break (GNUNET_OK ==
1429                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1430                                                       &pid.hashPubKey,
1431                                                       va));
1432   abort_validation (NULL, NULL, va);
1433 }
1434
1435
1436
1437 /**
1438  * Send the specified message to the specified client.  Since multiple
1439  * messages may be pending for the same client at a time, this code
1440  * makes sure that no message is lost.
1441  *
1442  * @param client client to transmit the message to
1443  * @param msg the message to send
1444  * @param may_drop can this message be dropped if the
1445  *        message queue for this client is getting far too large?
1446  */
1447 static void
1448 transmit_to_client (struct TransportClient *client,
1449                     const struct GNUNET_MessageHeader *msg, int may_drop)
1450 {
1451   struct ClientMessageQueueEntry *q;
1452   uint16_t msize;
1453
1454   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1455     {
1456       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1457                   _
1458                   ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1459                   ntohs (msg->type),
1460                   ntohs (msg->size),
1461                   client->message_count,
1462                   MAX_PENDING);
1463       GNUNET_STATISTICS_update (stats,
1464                                 gettext_noop ("# messages dropped due to slow client"),
1465                                 1,
1466                                 GNUNET_NO);
1467       return;
1468     }
1469   msize = ntohs (msg->size);
1470   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1471   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1472   memcpy (&q[1], msg, msize);
1473   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1474                                      client->message_queue_tail,
1475                                      client->message_queue_tail,
1476                                      q);
1477   client->message_count++;
1478   if (client->th == NULL)
1479     {
1480       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1481                                                         msize,
1482                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1483                                                         &transmit_to_client_callback,
1484                                                         client);
1485       GNUNET_assert (client->th != NULL);
1486     }
1487 }
1488
1489
1490 /**
1491  * Transmit a 'SEND_OK' notification to the given client for the
1492  * given neighbour.
1493  *
1494  * @param client who to notify
1495  * @param n neighbour to notify about, can be NULL (on failure)
1496  * @param target target of the transmission
1497  * @param result status code for the transmission request
1498  */
1499 static void
1500 transmit_send_ok (struct TransportClient *client,
1501                   struct NeighbourList *n,
1502                   const struct GNUNET_PeerIdentity *target,
1503                   int result)
1504 {
1505   struct SendOkMessage send_ok_msg;
1506
1507   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1508   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1509   send_ok_msg.success = htonl (result);
1510   if (n != NULL)
1511     send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1512   else
1513     send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1514   send_ok_msg.peer = *target;
1515   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1516 }
1517
1518
1519 /**
1520  * Mark the given FAL entry as 'connected' (and hence preferred for
1521  * sending); also mark all others for the same peer as 'not connected'
1522  * (since only one can be preferred).
1523  *
1524  * @param fal address to set to 'connected'
1525  */
1526 static void
1527 mark_address_connected (struct ForeignAddressList *fal);
1528
1529
1530
1531 /**
1532  * We should re-try transmitting to the given peer,
1533  * hopefully we've learned something in the meantime.
1534  */
1535 static void
1536 retry_transmission_task (void *cls,
1537                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1538 {
1539   struct NeighbourList *n = cls;
1540
1541   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1542   try_transmission_to_peer (n);
1543 }
1544
1545
1546 /**
1547  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1548  * upon "completion" of a send request.  This tells the API
1549  * that it is now legal to send another message to the given
1550  * peer.
1551  *
1552  * @param cls closure, identifies the entry on the
1553  *            message queue that was transmitted and the
1554  *            client responsible for queuing the message
1555  * @param target the peer receiving the message
1556  * @param result GNUNET_OK on success, if the transmission
1557  *           failed, we should not tell the client to transmit
1558  *           more messages
1559  */
1560 static void
1561 transmit_send_continuation (void *cls,
1562                             const struct GNUNET_PeerIdentity *target,
1563                             int result)
1564 {
1565   struct MessageQueue *mq = cls;
1566   struct NeighbourList *n;
1567
1568   GNUNET_STATISTICS_update (stats,
1569                             gettext_noop ("# bytes pending with plugins"),
1570                             - (int64_t) mq->message_buf_size,
1571                             GNUNET_NO);
1572   if (result == GNUNET_OK)
1573     {
1574       GNUNET_STATISTICS_update (stats,
1575                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1576                                 mq->message_buf_size,
1577                                 GNUNET_NO);
1578     }
1579   else
1580     {
1581       GNUNET_STATISTICS_update (stats,
1582                                 gettext_noop ("# bytes with transmission failure by plugins"),
1583                                 mq->message_buf_size,
1584                                 GNUNET_NO);
1585     }
1586   if (mq->specific_address != NULL)
1587     {
1588       if (result == GNUNET_OK)
1589         {
1590           mq->specific_address->timeout =
1591             GNUNET_TIME_relative_to_absolute
1592             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1593           if (mq->specific_address->validated == GNUNET_YES)
1594             mark_address_connected (mq->specific_address);
1595         }
1596       else
1597         {
1598           if (mq->specific_address->connected != GNUNET_NO)
1599             {
1600 #if DEBUG_TRANSPORT
1601               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1602                           "Marking address `%s' as no longer connected (due to transmission problem)\n",
1603                           a2s (mq->specific_address->ready_list->plugin->short_name,
1604                                mq->specific_address->addr,
1605                                mq->specific_address->addrlen));
1606 #endif
1607               GNUNET_STATISTICS_update (stats,
1608                                         gettext_noop ("# connected addresses"),
1609                                         -1,
1610                                         GNUNET_NO);
1611               mq->specific_address->connected = GNUNET_NO;
1612             }
1613         }
1614       if (! mq->internal_msg)
1615         mq->specific_address->in_transmit = GNUNET_NO;
1616     }
1617   n = find_neighbour (&mq->neighbour_id);
1618   if (mq->client != NULL)
1619     transmit_send_ok (mq->client, n, target, result);
1620   if (n != NULL)
1621     {
1622       GNUNET_CONTAINER_DLL_remove (n->cont_head,
1623                                    n->cont_tail,
1624                                    mq);
1625     }
1626   GNUNET_free (mq);
1627   if (n != NULL) 
1628     {
1629       if (result == GNUNET_OK) 
1630         try_transmission_to_peer (n);
1631       else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1632         n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1633                                                   n);
1634     }   
1635 }
1636
1637
1638 /**
1639  * Check the ready list for the given neighbour and if a plugin is
1640  * ready for transmission (and if we have a message), do so!
1641  *
1642  * @param neighbour target peer for which to transmit
1643  */
1644 static void
1645 try_transmission_to_peer (struct NeighbourList *n)
1646 {
1647   struct ReadyList *rl;
1648   struct MessageQueue *mq;
1649   struct GNUNET_TIME_Relative timeout;
1650   ssize_t ret;
1651   int force_address;
1652
1653   if (n->messages_head == NULL)
1654     {
1655 #if DEBUG_TRANSPORT
1656       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657                   "Transmission queue for `%4s' is empty\n",
1658                   GNUNET_i2s (&n->id));
1659 #endif
1660       return;                     /* nothing to do */
1661     }
1662   rl = NULL;
1663   mq = n->messages_head;
1664   force_address = GNUNET_YES;
1665   if (mq->specific_address == NULL)
1666     {
1667       /* TODO: ADD ATS */
1668       mq->specific_address = get_preferred_ats_address(n);
1669       GNUNET_STATISTICS_update (stats,
1670                                 gettext_noop ("# transport selected peer address freely"),
1671                                 1,
1672                                 GNUNET_NO);
1673       force_address = GNUNET_NO;
1674     }
1675   if (mq->specific_address == NULL)
1676     {
1677       GNUNET_STATISTICS_update (stats,
1678                                 gettext_noop ("# transport failed to selected peer address"),
1679                                 1,
1680                                 GNUNET_NO);
1681       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1682       if (timeout.rel_value == 0)
1683         {
1684 #if DEBUG_TRANSPORT
1685           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1687                       mq->message_buf_size,
1688                       GNUNET_i2s (&mq->neighbour_id));
1689 #endif
1690           GNUNET_STATISTICS_update (stats,
1691                                     gettext_noop ("# bytes in message queue for other peers"),
1692                                     - (int64_t) mq->message_buf_size,
1693                                     GNUNET_NO);
1694           GNUNET_STATISTICS_update (stats,
1695                                     gettext_noop ("# bytes discarded (no destination address available)"),
1696                                     mq->message_buf_size,
1697                                     GNUNET_NO);
1698           if (mq->client != NULL)
1699             transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1700           GNUNET_CONTAINER_DLL_remove (n->messages_head,
1701                                        n->messages_tail,
1702                                        mq);
1703           GNUNET_free (mq);
1704           return;               /* nobody ready */
1705         }
1706       GNUNET_STATISTICS_update (stats,
1707                                 gettext_noop ("# message delivery deferred (no address)"),
1708                                 1,
1709                                 GNUNET_NO);
1710       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1711         GNUNET_SCHEDULER_cancel (n->retry_task);
1712       n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1713                                                     &retry_transmission_task,
1714                                                     n);
1715 #if DEBUG_TRANSPORT
1716       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1717                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1718                   mq->message_buf_size,
1719                   GNUNET_i2s (&mq->neighbour_id),
1720                   timeout.rel_value);
1721 #endif
1722       /* FIXME: might want to trigger peerinfo lookup here
1723          (unless that's already pending...) */
1724       return;
1725     }
1726   GNUNET_CONTAINER_DLL_remove (n->messages_head,
1727                                n->messages_tail,
1728                                mq);
1729   if (mq->specific_address->connected == GNUNET_NO)
1730     mq->specific_address->connect_attempts++;
1731   rl = mq->specific_address->ready_list;
1732   mq->plugin = rl->plugin;
1733   if (!mq->internal_msg)
1734     mq->specific_address->in_transmit = GNUNET_YES;
1735 #if DEBUG_TRANSPORT
1736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1737               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1738               mq->message_buf_size,
1739               GNUNET_i2s (&n->id),
1740               (mq->specific_address->addr != NULL)
1741               ? a2s (mq->plugin->short_name,
1742                      mq->specific_address->addr,
1743                      mq->specific_address->addrlen)
1744               : "<inbound>",
1745               rl->plugin->short_name);
1746 #endif
1747   GNUNET_STATISTICS_update (stats,
1748                             gettext_noop ("# bytes in message queue for other peers"),
1749                             - (int64_t) mq->message_buf_size,
1750                             GNUNET_NO);
1751   GNUNET_STATISTICS_update (stats,
1752                             gettext_noop ("# bytes pending with plugins"),
1753                             mq->message_buf_size,
1754                             GNUNET_NO);
1755
1756   GNUNET_CONTAINER_DLL_insert (n->cont_head,
1757                                n->cont_tail,
1758                                mq);
1759
1760   ret = rl->plugin->api->send (rl->plugin->api->cls,
1761                                &mq->neighbour_id,
1762                                mq->message_buf,
1763                                mq->message_buf_size,
1764                                mq->priority,
1765                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1766                                mq->specific_address->session,
1767                                mq->specific_address->addr,
1768                                mq->specific_address->addrlen,
1769                                force_address,
1770                                &transmit_send_continuation, mq);
1771   if (ret == -1)
1772     {
1773       /* failure, but 'send' would not call continuation in this case,
1774          so we need to do it here! */
1775       transmit_send_continuation (mq,
1776                                   &mq->neighbour_id,
1777                                   GNUNET_SYSERR);
1778     }
1779 }
1780
1781
1782 /**
1783  * Send the specified message to the specified peer.
1784  *
1785  * @param client source of the transmission request (can be NULL)
1786  * @param peer_address ForeignAddressList where we should send this message
1787  * @param priority how important is the message
1788  * @param timeout how long do we have to transmit?
1789  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1790  * @param message_buf_size total size of all messages in message_buf
1791  * @param is_internal is this an internal message; these are pre-pended and
1792  *                    also do not count for plugins being "ready" to transmit
1793  * @param neighbour handle to the neighbour for transmission
1794  */
1795 static void
1796 transmit_to_peer (struct TransportClient *client,
1797                   struct ForeignAddressList *peer_address,
1798                   unsigned int priority,
1799                   struct GNUNET_TIME_Relative timeout,
1800                   const char *message_buf,
1801                   size_t message_buf_size,
1802                   int is_internal, struct NeighbourList *neighbour)
1803 {
1804   struct MessageQueue *mq;
1805
1806 #if EXTRA_CHECKS
1807   if (client != NULL)
1808     {
1809       /* check for duplicate submission */
1810       mq = neighbour->messages_head;
1811       while (NULL != mq)
1812         {
1813           if (mq->client == client)
1814             {
1815               /* client transmitted to same peer twice
1816                  before getting SEND_OK! */
1817               GNUNET_break (0);
1818               return;
1819             }
1820           mq = mq->next;
1821         }
1822     }
1823 #endif
1824   GNUNET_STATISTICS_update (stats,
1825                             gettext_noop ("# bytes in message queue for other peers"),
1826                             message_buf_size,
1827                             GNUNET_NO);
1828   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1829   mq->specific_address = peer_address;
1830   mq->client = client;
1831   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1832   memcpy (&mq[1], message_buf, message_buf_size);
1833   mq->message_buf = (const char*) &mq[1];
1834   mq->message_buf_size = message_buf_size;
1835   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1836   mq->internal_msg = is_internal;
1837   mq->priority = priority;
1838   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1839   if (is_internal)
1840     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1841                                  neighbour->messages_tail,
1842                                  mq);
1843   else
1844     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1845                                        neighbour->messages_tail,
1846                                        neighbour->messages_tail,
1847                                        mq);
1848   try_transmission_to_peer (neighbour);
1849 }
1850
1851
1852 /**
1853  * Send a plain PING (without address or our HELLO) to the given
1854  * foreign address to try to establish a connection (and validate
1855  * that the other peer is really who he claimed he is).
1856  *
1857  * @param n neighbour to PING
1858  */
1859 static void
1860 transmit_plain_ping (struct NeighbourList *n)
1861 {
1862   struct ValidationEntry *ve;
1863   struct TransportPingMessage ping;
1864   struct ReadyList *rl;
1865   struct TransportPlugin *plugin;
1866   struct ForeignAddressList *fal;
1867
1868   if (! n->public_key_valid)
1869     {
1870       /* This should not happen since the other peer
1871          should send us a HELLO prior to sending his
1872          PING */
1873       GNUNET_break_op (0);
1874       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875                   "Could not transmit plain PING to `%s': public key not known\n",
1876                   GNUNET_i2s (&n->id));
1877       return;
1878     }
1879   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1880               "Looking for addresses to transmit plain PING to `%s'\n",
1881               GNUNET_i2s (&n->id));
1882   for (rl = n->plugins; rl != NULL; rl = rl->next)
1883     {
1884       plugin = rl->plugin;
1885       for (fal = rl->addresses; fal != NULL; fal = fal->next)
1886         {
1887           if (! fal->connected)
1888             continue;      
1889           ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1890           ve->transport_name = GNUNET_strdup (plugin->short_name);
1891           ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1892                                                     UINT_MAX);
1893           ve->send_time = GNUNET_TIME_absolute_get();
1894           ve->session = fal->session;
1895           memcpy(&ve->publicKey,
1896                  &n->publicKey,
1897                  sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1898           ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1899                                                            &timeout_hello_validation,
1900                                                            ve);
1901           GNUNET_CONTAINER_multihashmap_put (validation_map,
1902                                              &n->id.hashPubKey,
1903                                              ve,
1904                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1905           ping.header.size = htons(sizeof(struct TransportPingMessage));
1906           ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1907           ping.challenge = htonl(ve->challenge);
1908           memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1909           GNUNET_STATISTICS_update (stats,
1910                                     gettext_noop ("# PING without HELLO messages sent"),
1911                                     1,
1912                                     GNUNET_NO);
1913           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1914                       "Transmitting plain PING to `%s'\n",
1915                       GNUNET_i2s (&n->id));
1916           transmit_to_peer (NULL, 
1917                             fal,
1918                             GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1919                             HELLO_VERIFICATION_TIMEOUT,
1920                             (const char*) &ping, sizeof (ping),
1921                             GNUNET_YES, n);
1922         }
1923     }
1924 }
1925
1926
1927 /**
1928  * Mark the given FAL entry as 'connected' (and hence preferred for
1929  * sending); also mark all others for the same peer as 'not connected'
1930  * (since only one can be preferred).
1931  *
1932  * @param fal address to set to 'connected'
1933  */
1934 static void
1935 mark_address_connected (struct ForeignAddressList *fal)
1936 {
1937   struct ForeignAddressList *pos;
1938   int cnt;
1939
1940   GNUNET_assert (GNUNET_YES == fal->validated);
1941   if (fal->connected == GNUNET_YES)
1942     return; /* nothing to do */
1943   cnt = GNUNET_YES;
1944   pos = fal->ready_list->addresses;
1945   while (pos != NULL)
1946     {
1947       if (GNUNET_YES == pos->connected)
1948         {
1949 #if DEBUG_TRANSPORT
1950           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1951                       "Marking address `%s' as no longer connected (due to connect on other address)\n",
1952                       a2s (pos->ready_list->plugin->short_name,
1953                            pos->addr,
1954                            pos->addrlen));
1955 #endif
1956           GNUNET_break (cnt == GNUNET_YES);
1957           cnt = GNUNET_NO;
1958           pos->connected = GNUNET_NO;
1959           GNUNET_STATISTICS_update (stats,
1960                                     gettext_noop ("# connected addresses"),
1961                                     -1,
1962                                     GNUNET_NO);
1963         }
1964       pos = pos->next;
1965     }
1966   fal->connected = GNUNET_YES;
1967   if (GNUNET_YES == cnt)
1968     {
1969       GNUNET_STATISTICS_update (stats,
1970                                 gettext_noop ("# connected addresses"),
1971                                 1,
1972                                 GNUNET_NO);
1973     }
1974 }
1975
1976
1977 /**
1978  * Find an address in any of the available transports for
1979  * the given neighbour that would be good for message
1980  * transmission.  This is essentially the transport selection
1981  * routine.
1982  *
1983  * @param neighbour for whom to select an address
1984  * @return selected address, NULL if we have none
1985  */
1986 struct ForeignAddressList *
1987 find_ready_address(struct NeighbourList *neighbour)
1988 {
1989   struct ReadyList *head = neighbour->plugins;
1990   struct ForeignAddressList *addresses;
1991   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1992   struct ForeignAddressList *best_address;
1993
1994   /* Hack to prefer unix domain sockets */
1995   struct ForeignAddressList *unix_address = NULL;
1996
1997   best_address = NULL;
1998   while (head != NULL)
1999     {
2000       addresses = head->addresses;
2001       while (addresses != NULL)
2002         {
2003           if ( (addresses->timeout.abs_value < now.abs_value) &&
2004                (addresses->connected == GNUNET_YES) )
2005             {
2006 #if DEBUG_TRANSPORT
2007               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2008                           "Marking long-time inactive connection to `%4s' as down.\n",
2009                           GNUNET_i2s (&neighbour->id));
2010 #endif
2011               GNUNET_STATISTICS_update (stats,
2012                                         gettext_noop ("# connected addresses"),
2013                                         -1,
2014                                         GNUNET_NO);
2015               addresses->connected = GNUNET_NO;
2016             }
2017           addresses = addresses->next;
2018         }
2019
2020       addresses = head->addresses;
2021       while (addresses != NULL)
2022         {
2023 #if DEBUG_TRANSPORT
2024           if (addresses->addr != NULL)
2025             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2026                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2027                         a2s (head->plugin->short_name,
2028                              addresses->addr,
2029                              addresses->addrlen),
2030                         GNUNET_i2s (&neighbour->id),
2031                         addresses->connected,
2032                         addresses->in_transmit,
2033                         addresses->validated,
2034                         addresses->connect_attempts,
2035                         (unsigned long long) addresses->timeout.abs_value,
2036                         (unsigned int) addresses->distance);
2037 #endif
2038           if (0==strcmp(head->plugin->short_name,"unix"))
2039             {
2040               if ( (unix_address == NULL) || 
2041                    ( (unix_address != NULL) &&
2042                      (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2043                 unix_address = addresses;
2044             }
2045           if ( ( (best_address == NULL) ||
2046                  (addresses->connected == GNUNET_YES) ||
2047                  (best_address->connected == GNUNET_NO) ) &&
2048                (addresses->in_transmit == GNUNET_NO) &&
2049                ( (best_address == NULL) ||
2050                  (addresses->latency.rel_value < best_address->latency.rel_value)) )
2051             best_address = addresses;
2052           /* FIXME: also give lower-latency addresses that are not
2053              connected a chance some times... */
2054           addresses = addresses->next;
2055         }
2056       if (unix_address != NULL)
2057           break;
2058       head = head->next;
2059     }
2060   if (unix_address != NULL)
2061     {
2062       best_address = unix_address;
2063 #if DEBUG_TRANSPORT
2064       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2065                   "Found UNIX address, forced this address\n");
2066 #endif
2067     }
2068   if (best_address != NULL)
2069     {
2070 #if DEBUG_TRANSPORT
2071       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2072                   "Best address found (`%s') has latency of %llu ms.\n",
2073                   (best_address->addrlen > 0)
2074                   ? a2s (best_address->ready_list->plugin->short_name,
2075                          best_address->addr,
2076                        best_address->addrlen)
2077                   : "<inbound>",
2078                   best_address->latency.rel_value);
2079 #endif
2080     }
2081   else
2082     {
2083       GNUNET_STATISTICS_update (stats,
2084                                 gettext_noop ("# transmission attempts failed (no address)"),
2085                                 1,
2086                                 GNUNET_NO);
2087     }
2088
2089   return best_address;
2090
2091 }
2092
2093
2094 /**
2095  * FIXME: document.
2096  */
2097 struct GeneratorContext
2098 {
2099   struct TransportPlugin *plug_pos;
2100   struct OwnAddressList *addr_pos;
2101   struct GNUNET_TIME_Absolute expiration;
2102 };
2103
2104
2105 /**
2106  * FIXME: document.
2107  */
2108 static size_t
2109 address_generator (void *cls, size_t max, void *buf)
2110 {
2111   struct GeneratorContext *gc = cls;
2112   size_t ret;
2113
2114   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2115     {
2116       gc->plug_pos = gc->plug_pos->next;
2117       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2118     }
2119   if (NULL == gc->plug_pos)
2120     {
2121
2122       return 0;
2123     }
2124   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2125                                   gc->expiration,
2126                                   &gc->addr_pos[1],
2127                                   gc->addr_pos->addrlen, buf, max);
2128   gc->addr_pos = gc->addr_pos->next;
2129   return ret;
2130 }
2131
2132
2133 /**
2134  * Construct our HELLO message from all of the addresses of
2135  * all of the transports.
2136  *
2137  * @param cls unused
2138  * @param tc scheduler context
2139  */
2140 static void
2141 refresh_hello_task (void *cls,
2142                     const struct GNUNET_SCHEDULER_TaskContext *tc)
2143 {
2144   struct GNUNET_HELLO_Message *hello;
2145   struct TransportClient *cpos;
2146   struct NeighbourList *npos;
2147   struct GeneratorContext gc;
2148
2149   hello_task = GNUNET_SCHEDULER_NO_TASK;
2150   gc.plug_pos = plugins;
2151   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2152   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2153   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2154 #if DEBUG_TRANSPORT
2155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2156               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2157 #endif
2158   GNUNET_STATISTICS_update (stats,
2159                             gettext_noop ("# refreshed my HELLO"),
2160                             1,
2161                             GNUNET_NO);
2162   cpos = clients;
2163   while (cpos != NULL)
2164     {
2165       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2166                   "Transmitting my HELLO to client!\n");
2167       transmit_to_client (cpos,
2168                           (const struct GNUNET_MessageHeader *) hello,
2169                           GNUNET_NO);
2170       cpos = cpos->next;
2171     }
2172
2173   GNUNET_free_non_null (our_hello);
2174   our_hello = hello;
2175   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2176   for (npos = neighbours; npos != NULL; npos = npos->next)
2177     {
2178       if (! npos->received_pong)
2179         continue;
2180 #if DEBUG_TRANSPORT
2181       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2182                   "Transmitting updated `%s' to neighbour `%4s'\n",
2183                   "HELLO", GNUNET_i2s (&npos->id));
2184 #endif
2185       GNUNET_STATISTICS_update (stats,
2186                                 gettext_noop ("# transmitted my HELLO to other peers"),
2187                                 1,
2188                                 GNUNET_NO);
2189       transmit_to_peer (NULL, NULL, 0,
2190                         HELLO_ADDRESS_EXPIRATION,
2191                         (const char *) our_hello,
2192                         GNUNET_HELLO_size(our_hello),
2193                         GNUNET_NO, npos);
2194     }
2195 }
2196
2197
2198 /**
2199  * Schedule task to refresh hello (unless such a
2200  * task exists already).
2201  */
2202 static void
2203 refresh_hello ()
2204 {
2205 #if DEBUG_TRANSPORT_HELLO
2206   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2207               "refresh_hello() called!\n");
2208 #endif
2209   if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2210     return;
2211   hello_task
2212     = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2213                                 NULL);
2214 }
2215
2216
2217 /**
2218  * Iterator over hash map entries that NULLs the session of validation
2219  * entries that match the given session.
2220  *
2221  * @param cls closure (the 'struct Session*' to match against)
2222  * @param key current key code (peer ID, not used)
2223  * @param value value in the hash map ('struct ValidationEntry*')
2224  * @return GNUNET_YES (we should continue to iterate)
2225  */
2226 static int
2227 remove_session_validations (void *cls,
2228                             const GNUNET_HashCode * key,
2229                             void *value)
2230 {
2231   struct Session *session = cls;
2232   struct ValidationEntry *ve = value;
2233
2234   if (session == ve->session)
2235     ve->session = NULL;
2236   return GNUNET_YES;
2237 }
2238
2239
2240 /**
2241  * We've been disconnected from the other peer (for some
2242  * connection-oriented transport).  Either quickly
2243  * re-establish the connection or signal the disconnect
2244  * to the CORE.
2245  *
2246  * Only signal CORE level disconnect if ALL addresses
2247  * for the peer are exhausted.
2248  *
2249  * @param p overall plugin context
2250  * @param nl neighbour that was disconnected
2251  */
2252 static void
2253 try_fast_reconnect (struct TransportPlugin *p,
2254                     struct NeighbourList *nl)
2255 {
2256   /* FIXME-MW: fast reconnect / transport switching not implemented... */
2257   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2258               "try_fast_reconnect not implemented!\n");
2259   /* Note: the idea here is to hide problems with transports (or
2260      switching between plugins) from the core to eliminate the need to
2261      re-negotiate session keys and the like; OTOH, we should tell core
2262      quickly (much faster than timeout) `if a connection was lost and
2263      could not be re-established (i.e. other peer went down or is
2264      unable / refuses to communicate);
2265
2266      So we should consider:
2267      1) ideally: our own willingness / need to connect
2268      2) prior failures to connect to this peer (by plugin)
2269      3) ideally: reasons why other peer terminated (as far as knowable)
2270
2271      Most importantly, it must be POSSIBLE for another peer to terminate
2272      a connection for a while (without us instantly re-establishing it).
2273      Similarly, if another peer is gone we should quickly notify CORE.
2274      OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2275      on the other end), we should reconnect in such a way that BOTH CORE
2276      services never even notice.
2277      Furthermore, the same mechanism (or small variation) could be used
2278      to switch to a better-performing plugin (ATS).
2279
2280      Finally, this needs to be tested throughly... */
2281
2282   /*
2283    * GNUNET_NO in the call below makes transport disconnect the peer,
2284    * even if only a single address (out of say, six) went away.  This
2285    * function must be careful to ONLY disconnect if the peer is gone,
2286    * not just a specific address.
2287    *
2288    * More specifically, half the places it was used had it WRONG.
2289    */
2290
2291   /* No reconnect, signal disconnect instead! */
2292 #if DEBUG_TRANSPORT
2293 #endif
2294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2295             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2296             "try_fast_reconnect");
2297
2298   GNUNET_STATISTICS_update (stats,
2299                             gettext_noop ("# disconnects due to try_fast_reconnect"),
2300                             1,
2301                             GNUNET_NO);
2302 #if DISCONNECT || 1
2303   disconnect_neighbour (nl, GNUNET_YES);
2304 #endif
2305 }
2306
2307
2308 /**
2309  * Function that will be called whenever the plugin internally
2310  * cleans up a session pointer and hence the service needs to
2311  * discard all of those sessions as well.  Plugins that do not
2312  * use sessions can simply omit calling this function and always
2313  * use NULL wherever a session pointer is needed.
2314  *
2315  * @param cls closure
2316  * @param peer which peer was the session for
2317  * @param session which session is being destoyed
2318  */
2319 static void
2320 plugin_env_session_end  (void *cls,
2321                          const struct GNUNET_PeerIdentity *peer,
2322                          struct Session *session)
2323 {
2324   struct TransportPlugin *p = cls;
2325   struct NeighbourList *nl;
2326   struct ReadyList *rl;
2327   struct ForeignAddressList *pos;
2328   struct ForeignAddressList *prev;
2329
2330 #if DEBUG_TRANSPORT
2331   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2332               "Session ended with peer `%4s', %s\n", 
2333               GNUNET_i2s(peer),
2334               "plugin_env_session_end");
2335 #endif
2336   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2337                                          &remove_session_validations,
2338                                          session);
2339   nl = find_neighbour (peer);
2340   if (nl == NULL)
2341     {
2342 #if DEBUG_TRANSPORT
2343       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2344                   "No neighbour record found for peer `%4s'\n", 
2345                   GNUNET_i2s(peer));
2346 #endif
2347       return; /* was never marked as connected */
2348     }
2349   rl = nl->plugins;
2350   while (rl != NULL)
2351     {
2352       if (rl->plugin == p)
2353         break;
2354       rl = rl->next;
2355     }
2356   if (rl == NULL)
2357     {
2358 #if DEBUG_TRANSPORT
2359       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2360                   "Plugin was associated with peer `%4s'\n", 
2361                   GNUNET_i2s(peer));
2362 #endif
2363       GNUNET_STATISTICS_update (stats,
2364                                 gettext_noop ("# disconnects due to session end"),
2365                                 1,
2366                                 GNUNET_NO);
2367       disconnect_neighbour (nl, GNUNET_YES);
2368       return;
2369     }
2370   prev = NULL;
2371   pos = rl->addresses;
2372   while ( (pos != NULL) &&
2373           (pos->session != session) )
2374     {
2375       prev = pos;
2376       pos = pos->next;
2377     }
2378   if (pos == NULL)
2379     {
2380 #if DEBUG_TRANSPORT
2381       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2382                   "Session was never marked as ready for peer `%4s'\n", 
2383                   GNUNET_i2s(peer));
2384 #endif
2385
2386       int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2387
2388       /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2389       if (validations_pending ==GNUNET_YES)
2390         {
2391 #if DEBUG_TRANSPORT
2392       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393                   "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2394 #endif
2395         return;
2396         }
2397
2398       //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2399       GNUNET_STATISTICS_update (stats,
2400                                 gettext_noop ("# disconnects due to unready session"),
2401                                 1,
2402                                 GNUNET_NO);
2403
2404       disconnect_neighbour (nl, GNUNET_YES);
2405       return; /* was never marked as connected */
2406     }
2407   pos->session = NULL;
2408   pos->connected = GNUNET_NO;
2409   if (pos->addrlen != 0)
2410     {
2411       if (nl->received_pong != GNUNET_NO)
2412         {
2413           GNUNET_STATISTICS_update (stats,
2414                                     gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2415                                     1,
2416                                     GNUNET_NO);
2417           if (GNUNET_YES == pos->connected)                  
2418               try_fast_reconnect (p, nl);           
2419         }
2420       else
2421         {
2422           GNUNET_STATISTICS_update (stats,
2423                                     gettext_noop ("# disconnects due to missing pong"),
2424                                     1,
2425                                     GNUNET_NO);
2426           /* FIXME this is never true?! See: line 2416*/
2427           if (GNUNET_YES == pos->connected)
2428             disconnect_neighbour (nl, GNUNET_YES);
2429         }
2430       return;
2431     }
2432
2433   GNUNET_STATISTICS_update (stats,
2434                               gettext_noop ("# connected addresses"),
2435                               -1,
2436                               GNUNET_NO);
2437
2438   /* was inbound connection, free 'pos' */
2439   if (prev == NULL)
2440     rl->addresses = pos->next;
2441   else
2442     prev->next = pos->next;
2443   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2444     {
2445       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2446       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2447     }
2448   GNUNET_free_non_null(pos->ressources);
2449   GNUNET_free_non_null(pos->quality);
2450   ats_modify_problem_state (ats, ATS_MODIFIED);
2451
2452   if (GNUNET_YES != pos->connected)
2453     {
2454       /* nothing else to do, connection was never up... */
2455       GNUNET_free (pos);
2456       return; 
2457     }
2458   GNUNET_free (pos);
2459
2460   if (nl->received_pong == GNUNET_NO)
2461     {
2462       GNUNET_STATISTICS_update (stats,
2463                                 gettext_noop ("# disconnects due to NO pong"),
2464                                 1,
2465                                 GNUNET_NO);
2466       disconnect_neighbour (nl, GNUNET_YES);
2467       return; /* nothing to do, never connected... */
2468     }
2469   /* check if we have any validated addresses left */
2470   pos = rl->addresses;
2471   while (pos != NULL)
2472     {
2473       if (GNUNET_YES == pos->validated)
2474         {
2475           GNUNET_STATISTICS_update (stats,
2476                                     gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2477                                     1,
2478                                     GNUNET_NO);
2479           try_fast_reconnect (p, nl);
2480           return;
2481         }
2482       pos = pos->next;
2483     }
2484   /* no valid addresses left, signal disconnect! */
2485
2486 #if DEBUG_TRANSPORT
2487   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2488               "Disconnecting peer `%4s', %s\n", 
2489               GNUNET_i2s(peer),
2490               "plugin_env_session_end");
2491 #endif
2492   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2493    * it means there aren't any left for this PLUGIN/PEER combination! So
2494    * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2495    * when it isn't necessary. Using GNUNET_YES at least checks to see
2496    * if there are any addresses that work first, so as not to overdo it.
2497    * --NE
2498    */
2499   GNUNET_STATISTICS_update (stats,
2500                             gettext_noop ("# disconnects due to plugin_env_session_end"),
2501                             1,
2502                             GNUNET_NO);
2503   disconnect_neighbour (nl, GNUNET_YES);
2504 }
2505
2506
2507 /**
2508  * Function that must be called by each plugin to notify the
2509  * transport service about the addresses under which the transport
2510  * provided by the plugin can be reached.
2511  *
2512  * @param cls closure
2513  * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2514  * @param addr one of the addresses of the host, NULL for the last address
2515  *        the specific address format depends on the transport
2516  * @param addrlen length of the address
2517  */
2518 static void
2519 plugin_env_notify_address (void *cls,
2520                            int add_remove,
2521                            const void *addr,
2522                            size_t addrlen)
2523 {
2524   struct TransportPlugin *p = cls;
2525   struct OwnAddressList *al;
2526   struct OwnAddressList *prev;
2527
2528   GNUNET_assert (p->api != NULL);
2529 #if DEBUG_TRANSPORT
2530   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2531               (add_remove == GNUNET_YES)
2532               ? "Adding `%s':%s to the set of our addresses\n"
2533               : "Removing `%s':%s from the set of our addresses\n",
2534               a2s (p->short_name,
2535                    addr, addrlen),
2536               p->short_name);
2537 #endif
2538   GNUNET_assert (addr != NULL);
2539   if (GNUNET_NO == add_remove)
2540     {
2541       prev = NULL;
2542       al = p->addresses;
2543       while (al != NULL)
2544         {
2545           if ( (addrlen == al->addrlen) &&
2546                (0 == memcmp (addr, &al[1], addrlen)) )
2547             {
2548               if (prev == NULL)
2549                 p->addresses = al->next;
2550               else
2551                 prev->next = al->next;
2552               GNUNET_free (al);
2553               refresh_hello ();
2554               return;
2555             }
2556           prev = al;
2557           al = al->next;
2558         }
2559       GNUNET_break (0);
2560       return;
2561     }
2562   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2563   al->next = p->addresses;
2564   p->addresses = al;
2565   al->addrlen = addrlen;
2566   memcpy (&al[1], addr, addrlen);
2567   refresh_hello ();
2568 }
2569
2570
2571 /**
2572  * Notify all of our clients about a peer connecting.
2573  */
2574 static void
2575 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2576                         struct GNUNET_TIME_Relative latency,
2577                         uint32_t distance)
2578 {
2579   struct ConnectInfoMessage * cim;
2580   struct TransportClient *cpos;
2581   uint32_t ats_count;
2582   size_t size;
2583
2584   if (0 == memcmp (peer,
2585                    &my_identity,
2586                    sizeof (struct GNUNET_PeerIdentity)))
2587     {
2588       GNUNET_break (0);
2589       return;
2590     }
2591 #if DEBUG_TRANSPORT
2592   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2593               "Notifying clients about connection with `%s'\n",
2594               GNUNET_i2s (peer));
2595 #endif
2596   GNUNET_STATISTICS_update (stats,
2597                             gettext_noop ("# peers connected"),
2598                             1,
2599                             GNUNET_NO);
2600
2601   ats_count = 2;
2602   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2603   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2604     {
2605       GNUNET_break(0);
2606     }
2607   cim = GNUNET_malloc (size);
2608   cim->header.size = htons (size);
2609   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2610   cim->ats_count = htonl(2);
2611   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2612   (&(cim->ats))[0].value = htonl (distance);
2613   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2614   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2615   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2616   (&(cim->ats))[2].value = htonl (0);
2617   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2618
2619   /* notify ats about connecting peer */
2620   /* notify ats about connecting peer */
2621   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2622   {
2623     ats_modify_problem_state(ats, ATS_MODIFIED);
2624     ats_calculate_bandwidth_distribution (ats, stats);
2625   }
2626
2627
2628   cpos = clients;
2629   while (cpos != NULL)
2630     {
2631       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2632       cpos = cpos->next;
2633     }
2634
2635   GNUNET_free (cim);
2636 }
2637
2638
2639 /**
2640  * Notify all of our clients about a peer disconnecting.
2641  */
2642 static void
2643 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2644 {
2645   struct DisconnectInfoMessage dim;
2646   struct TransportClient *cpos;
2647
2648   if (0 == memcmp (peer,
2649                    &my_identity,
2650                    sizeof (struct GNUNET_PeerIdentity)))
2651     {
2652       GNUNET_break (0);
2653       return;
2654     }
2655 #if DEBUG_TRANSPORT
2656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2657               "Notifying clients about lost connection to `%s'\n",
2658               GNUNET_i2s (peer));
2659 #endif
2660   GNUNET_STATISTICS_update (stats,
2661                             gettext_noop ("# peers connected"),
2662                             -1,
2663                             GNUNET_NO);
2664   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2665   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2666   dim.reserved = htonl (0);
2667   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2668
2669   /* notify ats about connecting peer */
2670   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2671   {
2672     ats_modify_problem_state(ats, ATS_MODIFIED);
2673     ats_calculate_bandwidth_distribution (ats, stats);
2674   }
2675
2676   cpos = clients;
2677   while (cpos != NULL)
2678     {
2679       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2680       cpos = cpos->next;
2681     }
2682 }
2683
2684
2685 /**
2686  * Find a ForeignAddressList entry for the given neighbour
2687  * that matches the given address and transport.
2688  *
2689  * @param neighbour which peer we care about
2690  * @param tname name of the transport plugin
2691  * @param session session to look for, NULL for 'any'; otherwise
2692  *        can be used for the service to "learn" this session ID
2693  *        if 'addr' matches
2694  * @param addr binary address
2695  * @param addrlen length of addr
2696  * @return NULL if no such entry exists
2697  */
2698 static struct ForeignAddressList *
2699 find_peer_address(struct NeighbourList *neighbour,
2700                   const char *tname,
2701                   struct Session *session,
2702                   const char *addr,
2703                   uint16_t addrlen)
2704 {
2705   struct ReadyList *head;
2706   struct ForeignAddressList *pos;
2707
2708   head = neighbour->plugins;
2709   while (head != NULL)
2710     {
2711       if (0 == strcmp (tname, head->plugin->short_name))
2712         break;
2713       head = head->next;
2714     }
2715   if (head == NULL)
2716     return NULL;
2717   pos = head->addresses;
2718   while ( (pos != NULL) &&
2719           ( (pos->addrlen != addrlen) ||
2720             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2721     {
2722       if ( (session != NULL) &&
2723            (pos->session == session) )
2724         return pos;
2725       pos = pos->next;
2726     }
2727   if ( (session != NULL) && (pos != NULL) )
2728     pos->session = session; /* learn it! */
2729   return pos;
2730 }
2731
2732
2733 /**
2734  * Get the peer address struct for the given neighbour and
2735  * address.  If it doesn't yet exist, create it.
2736  *
2737  * @param neighbour which peer we care about
2738  * @param tname name of the transport plugin
2739  * @param session session of the plugin, or NULL for none
2740  * @param addr binary address
2741  * @param addrlen length of addr
2742  * @return NULL if we do not have a transport plugin for 'tname'
2743  */
2744 static struct ForeignAddressList *
2745 add_peer_address (struct NeighbourList *neighbour,
2746                   const char *tname,
2747                   struct Session *session,
2748                   const char *addr,
2749                   uint16_t addrlen)
2750 {
2751   struct ReadyList *head;
2752   struct ForeignAddressList *ret;
2753   int c;
2754
2755   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2756   if (ret != NULL)
2757     return ret;
2758   head = neighbour->plugins;
2759
2760   while (head != NULL)
2761     {
2762       if (0 == strcmp (tname, head->plugin->short_name))
2763         break;
2764       head = head->next;
2765     }
2766   if (head == NULL)
2767     return NULL;
2768   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2769   ret->session = session;
2770   if ((addrlen > 0) && (addr != NULL))
2771     {
2772       ret->addr = (const char*) &ret[1];
2773       memcpy (&ret[1], addr, addrlen);
2774     }
2775   else
2776     {
2777       ret->addr = NULL;
2778     }
2779
2780   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2781   for (c=0; c<available_ressources; c++)
2782     {
2783       struct ATS_ressource_entry *r = ret->ressources;
2784       r[c].index = c;
2785       r[c].atis_index = ressources[c].atis_index;
2786       if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2787         {
2788           r[c].c = ressources[c].c_unix;
2789         }
2790       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2791         {
2792           r[c].c = ressources[c].c_udp;
2793         }
2794       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2795         {
2796           r[c].c = ressources[c].c_tcp;
2797         }
2798       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2799         {
2800           r[c].c = ressources[c].c_http;
2801         }
2802       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2803         {
2804           r[c].c = ressources[c].c_https;
2805         }
2806       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2807         {
2808           r[c].c = ressources[c].c_wlan;
2809         }
2810       else
2811         {
2812           r[c].c = ressources[c].c_default;
2813           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2814                       "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2815                       GNUNET_i2s(&neighbour->id),
2816                       neighbour->plugins->plugin->short_name);
2817         }
2818     }
2819
2820   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2821   ret->addrlen = addrlen;
2822   ret->expires = GNUNET_TIME_relative_to_absolute
2823     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2824   ret->latency = GNUNET_TIME_relative_get_forever();
2825   ret->distance = -1;
2826   ret->timeout = GNUNET_TIME_relative_to_absolute
2827     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2828   ret->ready_list = head;
2829   ret->next = head->addresses;
2830   head->addresses = ret;
2831   return ret;
2832 }
2833
2834
2835 /**
2836  * Closure for 'add_validated_address'.
2837  */
2838 struct AddValidatedAddressContext
2839 {
2840   /**
2841    * Entry that has been validated.
2842    */
2843   const struct ValidationEntry *ve;
2844
2845   /**
2846    * Flag set after we have added the address so
2847    * that we terminate the iteration next time.
2848    */
2849   int done;
2850 };
2851
2852
2853 /**
2854  * Callback function used to fill a buffer of max bytes with a list of
2855  * addresses in the format used by HELLOs.  Should use
2856  * "GNUNET_HELLO_add_address" as a helper function.
2857  *
2858  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2859  * @param max maximum number of bytes that can be written to buf
2860  * @param buf where to write the address information
2861  * @return number of bytes written, 0 to signal the
2862  *         end of the iteration.
2863  */
2864 static size_t
2865 add_validated_address (void *cls,
2866                        size_t max, void *buf)
2867 {
2868   struct AddValidatedAddressContext *avac = cls;
2869   const struct ValidationEntry *ve = avac->ve;
2870
2871   if (GNUNET_YES == avac->done)
2872     return 0;
2873   avac->done = GNUNET_YES;
2874   return GNUNET_HELLO_add_address (ve->transport_name,
2875                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2876                                    ve->addr,
2877                                    ve->addrlen,
2878                                    buf,
2879                                    max);
2880 }
2881
2882
2883
2884 /**
2885  * Closure for 'check_address_exists'.
2886  */
2887 struct CheckAddressExistsClosure
2888 {
2889   /**
2890    * Address to check for.
2891    */
2892   const void *addr;
2893
2894   /**
2895    * Name of the transport.
2896    */
2897   const char *tname;
2898
2899   /**
2900    * Session, or NULL.
2901    */
2902   struct Session *session;
2903
2904   /**
2905    * Set to GNUNET_YES if the address exists.
2906    */
2907   int exists;
2908
2909   /**
2910    * Length of addr.
2911    */
2912   uint16_t addrlen;
2913
2914 };
2915
2916
2917 /**
2918  * Iterator over hash map entries.  Checks if the given
2919  * validation entry is for the same address as what is given
2920  * in the closure.
2921  *
2922  * @param cls the 'struct CheckAddressExistsClosure*'
2923  * @param key current key code (ignored)
2924  * @param value value in the hash map ('struct ValidationEntry')
2925  * @return GNUNET_YES if we should continue to
2926  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2927  */
2928 static int
2929 check_address_exists (void *cls,
2930                       const GNUNET_HashCode * key,
2931                       void *value)
2932 {
2933   struct CheckAddressExistsClosure *caec = cls;
2934   struct ValidationEntry *ve = value;
2935
2936   if ( (0 == strcmp (caec->tname,
2937                      ve->transport_name)) &&
2938        (caec->addrlen == ve->addrlen) &&
2939        (0 == memcmp (caec->addr,
2940                      ve->addr,
2941                      caec->addrlen)) )
2942     {
2943       caec->exists = GNUNET_YES;
2944       return GNUNET_NO;
2945     }
2946   if ( (ve->session != NULL) &&
2947        (caec->session == ve->session) )
2948     {
2949       caec->exists = GNUNET_YES;
2950       return GNUNET_NO;
2951     }
2952   return GNUNET_YES;
2953 }
2954
2955
2956 static void
2957 neighbour_timeout_task (void *cls,
2958                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2959 {
2960   struct NeighbourList *n = cls;
2961
2962 #if DEBUG_TRANSPORT
2963   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2964               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2965 #endif
2966   GNUNET_STATISTICS_update (stats,
2967                             gettext_noop ("# disconnects due to timeout"),
2968                             1,
2969                             GNUNET_NO);
2970   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2971   disconnect_neighbour (n, GNUNET_NO);
2972 }
2973
2974
2975 /**
2976  * Schedule the job that will cause us to send a PING to the
2977  * foreign address to evaluate its validity and latency.
2978  *
2979  * @param fal address to PING
2980  */
2981 static void
2982 schedule_next_ping (struct ForeignAddressList *fal);
2983
2984
2985 /**
2986  * Add the given address to the list of foreign addresses
2987  * available for the given peer (check for duplicates).
2988  *
2989  * @param cls the respective 'struct NeighbourList' to update
2990  * @param tname name of the transport
2991  * @param expiration expiration time
2992  * @param addr the address
2993  * @param addrlen length of the address
2994  * @return GNUNET_OK (always)
2995  */
2996 static int
2997 add_to_foreign_address_list (void *cls,
2998                              const char *tname,
2999                              struct GNUNET_TIME_Absolute expiration,
3000                              const void *addr,
3001                              uint16_t addrlen)
3002 {
3003   struct NeighbourList *n = cls;
3004   struct ForeignAddressList *fal;
3005   int try;
3006
3007   GNUNET_STATISTICS_update (stats,
3008                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
3009                             1,
3010                             GNUNET_NO);
3011   try = GNUNET_NO;
3012   fal = find_peer_address (n, tname, NULL, addr, addrlen);
3013   if (fal == NULL)
3014     {
3015 #if DEBUG_TRANSPORT_HELLO
3016       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3017                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3018                   a2s (tname, addr, addrlen),
3019                   tname,
3020                   GNUNET_i2s (&n->id),
3021                   expiration.abs_value);
3022 #endif
3023       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3024       if (fal == NULL)
3025         {
3026           GNUNET_STATISTICS_update (stats,
3027                                     gettext_noop ("# previously validated addresses lacking transport"),
3028                                     1,
3029                                     GNUNET_NO);
3030         }
3031       else
3032         {
3033           fal->expires = GNUNET_TIME_absolute_max (expiration,
3034                                                    fal->expires);
3035           schedule_next_ping (fal);
3036         }
3037       try = GNUNET_YES;
3038     }
3039   else
3040     {
3041       fal->expires = GNUNET_TIME_absolute_max (expiration,
3042                                                fal->expires);
3043     }
3044   if (fal == NULL)
3045     {
3046 #if DEBUG_TRANSPORT
3047       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3048                   "Failed to add new address for `%4s'\n",
3049                   GNUNET_i2s (&n->id));
3050 #endif
3051       return GNUNET_OK;
3052     }
3053   if (fal->validated == GNUNET_NO)
3054     {
3055       fal->validated = GNUNET_YES;
3056       GNUNET_STATISTICS_update (stats,
3057                                 gettext_noop ("# peer addresses considered valid"),
3058                                 1,
3059                                 GNUNET_NO);
3060     }
3061   if (try == GNUNET_YES)
3062     {
3063 #if DEBUG_TRANSPORT
3064       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3065                   "Have new addresses, will try to trigger transmissions.\n");
3066 #endif
3067       try_transmission_to_peer (n);
3068     }
3069   return GNUNET_OK;
3070 }
3071
3072
3073 /**
3074  * Add addresses in validated HELLO "h" to the set of addresses
3075  * we have for this peer.
3076  *
3077  * @param cls closure ('struct NeighbourList*')
3078  * @param peer id of the peer, NULL for last call
3079  * @param h hello message for the peer (can be NULL)
3080  * @param err_msg NULL if successful, otherwise contains error message
3081  */
3082 static void
3083 add_hello_for_peer (void *cls,
3084                     const struct GNUNET_PeerIdentity *peer,
3085                     const struct GNUNET_HELLO_Message *h,
3086                     const char *err_msg)
3087 {
3088   struct NeighbourList *n = cls;
3089
3090   if (err_msg != NULL)
3091     {
3092 #if DEBUG_TRANSPORT
3093       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094                   _("Error in communication with PEERINFO service: %s\n"),
3095                   err_msg);
3096 #endif
3097       /* return; */
3098     }
3099   if (peer == NULL)
3100     {
3101       GNUNET_STATISTICS_update (stats,
3102                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3103                                 -1,
3104                                 GNUNET_NO);
3105       n->piter = NULL;
3106       return;
3107     }
3108   if (h == NULL)
3109     return; /* no HELLO available */
3110 #if DEBUG_TRANSPORT
3111   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3112               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3113               "HELLO",
3114               GNUNET_i2s (peer));
3115 #endif
3116   if (GNUNET_YES != n->public_key_valid)
3117     {
3118       GNUNET_HELLO_get_key (h, &n->publicKey);
3119       n->public_key_valid = GNUNET_YES;
3120     }
3121   GNUNET_HELLO_iterate_addresses (h,
3122                                   GNUNET_NO,
3123                                   &add_to_foreign_address_list,
3124                                   n);
3125 }
3126
3127
3128 /**
3129  * Create a fresh entry in our neighbour list for the given peer.
3130  * Will try to transmit our current HELLO to the new neighbour.
3131  * Do not call this function directly, use 'setup_peer_check_blacklist.
3132  *
3133  * @param peer the peer for which we create the entry
3134  * @param do_hello should we schedule transmitting a HELLO
3135  * @return the new neighbour list entry
3136  */
3137 static struct NeighbourList *
3138 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3139                      int do_hello)
3140 {
3141   struct NeighbourList *n;
3142   struct TransportPlugin *tp;
3143   struct ReadyList *rl;
3144
3145   GNUNET_assert (0 != memcmp (peer,
3146                               &my_identity,
3147                               sizeof (struct GNUNET_PeerIdentity)));
3148 #if DEBUG_TRANSPORT
3149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3150               "Setting up state for neighbour `%4s'\n",
3151               GNUNET_i2s (peer));
3152 #endif
3153   GNUNET_STATISTICS_update (stats,
3154                             gettext_noop ("# active neighbours"),
3155                             1,
3156                             GNUNET_NO);
3157   n = GNUNET_malloc (sizeof (struct NeighbourList));
3158   n->next = neighbours;
3159   neighbours = n;
3160   n->id = *peer;
3161   n->peer_timeout =
3162     GNUNET_TIME_relative_to_absolute
3163     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3164   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3165                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3166                                  MAX_BANDWIDTH_CARRY_S);
3167   tp = plugins;
3168   while (tp != NULL)
3169     {
3170       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3171         {
3172           rl = GNUNET_malloc (sizeof (struct ReadyList));
3173           rl->neighbour = n;
3174           rl->next = n->plugins;
3175           n->plugins = rl;
3176           rl->plugin = tp;
3177           rl->addresses = NULL;
3178         }
3179       tp = tp->next;
3180     }
3181   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3182   n->distance = -1;
3183   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3184                                                   &neighbour_timeout_task, n);
3185   if (do_hello)
3186     {
3187       GNUNET_STATISTICS_update (stats,
3188                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3189                                 1,
3190                                 GNUNET_NO);
3191       GNUNET_STATISTICS_update (stats,
3192                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3193                                 1,
3194                                 GNUNET_NO);
3195       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3196                                           GNUNET_TIME_UNIT_FOREVER_REL,
3197                                           &add_hello_for_peer, n);
3198
3199       GNUNET_STATISTICS_update (stats,
3200                                 gettext_noop ("# HELLO's sent to new neighbors"),
3201                                 1,
3202                                 GNUNET_NO);
3203       if (NULL != our_hello)
3204         transmit_to_peer (NULL, NULL, 0,
3205                           HELLO_ADDRESS_EXPIRATION,
3206                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3207                           GNUNET_NO, n);
3208     }
3209   return n;
3210 }
3211
3212
3213 /**
3214  * Function called after we have checked if communicating
3215  * with a given peer is acceptable.
3216  *
3217  * @param cls closure
3218  * @param n NULL if communication is not acceptable
3219  */
3220 typedef void (*SetupContinuation)(void *cls,
3221                                   struct NeighbourList *n);
3222
3223
3224 /**
3225  * Information kept for each client registered to perform
3226  * blacklisting.
3227  */
3228 struct Blacklisters
3229 {
3230   /**
3231    * This is a linked list.
3232    */
3233   struct Blacklisters *next;
3234
3235   /**
3236    * This is a linked list.
3237    */
3238   struct Blacklisters *prev;
3239
3240   /**
3241    * Client responsible for this entry.
3242    */
3243   struct GNUNET_SERVER_Client *client;
3244
3245   /**
3246    * Blacklist check that we're currently performing.
3247    */
3248   struct BlacklistCheck *bc;
3249
3250 };
3251
3252
3253 /**
3254  * Head of DLL of blacklisting clients.
3255  */
3256 static struct Blacklisters *bl_head;
3257
3258 /**
3259  * Tail of DLL of blacklisting clients.
3260  */
3261 static struct Blacklisters *bl_tail;
3262
3263
3264 /**
3265  * Context we use when performing a blacklist check.
3266  */
3267 struct BlacklistCheck
3268 {
3269
3270   /**
3271    * This is a linked list.
3272    */
3273   struct BlacklistCheck *next;
3274
3275   /**
3276    * This is a linked list.
3277    */
3278   struct BlacklistCheck *prev;
3279
3280   /**
3281    * Peer being checked.
3282    */
3283   struct GNUNET_PeerIdentity peer;
3284
3285   /**
3286    * Option for setup neighbour afterwards.
3287    */
3288   int do_hello;
3289
3290   /**
3291    * Continuation to call with the result.
3292    */
3293   SetupContinuation cont;
3294
3295   /**
3296    * Closure for cont.
3297    */
3298   void *cont_cls;
3299
3300   /**
3301    * Current transmission request handle for this client, or NULL if no
3302    * request is pending.
3303    */
3304   struct GNUNET_CONNECTION_TransmitHandle *th;
3305
3306   /**
3307    * Our current position in the blacklisters list.
3308    */
3309   struct Blacklisters *bl_pos;
3310
3311   /**
3312    * Current task performing the check.
3313    */
3314   GNUNET_SCHEDULER_TaskIdentifier task;
3315
3316 };
3317
3318 /**
3319  * Head of DLL of active blacklisting queries.
3320  */
3321 static struct BlacklistCheck *bc_head;
3322
3323 /**
3324  * Tail of DLL of active blacklisting queries.
3325  */
3326 static struct BlacklistCheck *bc_tail;
3327
3328
3329 /**
3330  * Perform next action in the blacklist check.
3331  *
3332  * @param cls the 'struct BlacklistCheck*'
3333  * @param tc unused
3334  */
3335 static void
3336 do_blacklist_check (void *cls,
3337                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3338
3339 /**
3340  * Transmit blacklist query to the client.
3341  *
3342  * @param cls the 'struct BlacklistCheck'
3343  * @param size number of bytes allowed
3344  * @param buf where to copy the message
3345  * @return number of bytes copied to buf
3346  */
3347 static size_t
3348 transmit_blacklist_message (void *cls,
3349                             size_t size,
3350                             void *buf)
3351 {
3352   struct BlacklistCheck *bc = cls;
3353   struct Blacklisters *bl;
3354   struct BlacklistMessage bm;
3355
3356   bc->th = NULL;
3357   if (size == 0)
3358     {
3359       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3360       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3361                                            bc);
3362       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3363                   "Failed to send blacklist test for peer `%s' to client\n",
3364                   GNUNET_i2s (&bc->peer));
3365       return 0;
3366     }
3367 #if DEBUG_TRANSPORT
3368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3369               "Sending blacklist test for peer `%s' to client\n",
3370               GNUNET_i2s (&bc->peer));
3371 #endif
3372   bl = bc->bl_pos;
3373   bm.header.size = htons (sizeof (struct BlacklistMessage));
3374   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3375   bm.is_allowed = htonl (0);
3376   bm.peer = bc->peer;
3377   memcpy (buf, &bm, sizeof (bm));
3378   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3379   return sizeof (bm);
3380 }
3381
3382
3383 /**
3384  * Perform next action in the blacklist check.
3385  *
3386  * @param cls the 'struct BlacklistCheck*'
3387  * @param tc unused
3388  */
3389 static void
3390 do_blacklist_check (void *cls,
3391                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3392 {
3393   struct BlacklistCheck *bc = cls;
3394   struct Blacklisters *bl;
3395
3396   bc->task = GNUNET_SCHEDULER_NO_TASK;
3397   bl = bc->bl_pos;
3398   if (bl == NULL)
3399     {
3400 #if DEBUG_TRANSPORT
3401       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3402                   "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3403                   GNUNET_i2s (&bc->peer));
3404 #endif
3405       bc->cont (bc->cont_cls,
3406                 setup_new_neighbour (&bc->peer, bc->do_hello));
3407       GNUNET_free (bc);
3408       return;
3409     }
3410   if (bl->bc == NULL)
3411     {
3412       bl->bc = bc;
3413       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3414                                                     sizeof (struct BlacklistMessage),
3415                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3416                                                     &transmit_blacklist_message,
3417                                                     bc);
3418     }
3419 }
3420
3421
3422 /**
3423  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3424  * does not yet exist, check the blacklist.  If the blacklist says creating
3425  * one is acceptable, create one and call the continuation; otherwise
3426  * call the continuation with NULL.
3427  *
3428  * @param peer peer to setup or look up a struct NeighbourList for
3429  * @param do_hello should we also schedule sending our HELLO to the peer
3430  *        if this is a new record
3431  * @param cont function to call with the 'struct NeigbhbourList*'
3432  * @param cont_cls closure for cont
3433  */
3434 static void
3435 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3436                             int do_hello,
3437                             SetupContinuation cont,
3438                             void *cont_cls)
3439 {
3440   struct NeighbourList *n;
3441   struct BlacklistCheck *bc;
3442
3443   n = find_neighbour(peer);
3444   if (n != NULL)
3445     {
3446 #if DEBUG_TRANSPORT
3447       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
3448                  "Neighbour record exists for peer `%s'\n", 
3449                  GNUNET_i2s(peer));
3450 #endif
3451       if (cont != NULL)
3452         cont (cont_cls, n);
3453       return;
3454     }
3455   if (bl_head == NULL)
3456     {
3457       if (cont != NULL)
3458         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3459       else
3460         setup_new_neighbour(peer, do_hello);
3461       return;
3462     }
3463   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3464   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3465   bc->peer = *peer;
3466   bc->do_hello = do_hello;
3467   bc->cont = cont;
3468   bc->cont_cls = cont_cls;
3469   bc->bl_pos = bl_head;
3470   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3471                                        bc);
3472 }
3473
3474
3475 /**
3476  * Function called with the result of querying a new blacklister about
3477  * it being allowed (or not) to continue to talk to an existing neighbour.
3478  *
3479  * @param cls the original 'struct NeighbourList'
3480  * @param n NULL if we need to disconnect
3481  */
3482 static void
3483 confirm_or_drop_neighbour (void *cls,
3484                            struct NeighbourList *n)
3485 {
3486   struct NeighbourList * orig = cls;
3487
3488   if (n == NULL)
3489     {
3490 #if DEBUG_TRANSPORT
3491       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3492               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3493               "confirm_or_drop_neighboUr");
3494 #endif
3495       GNUNET_STATISTICS_update (stats,
3496                                 gettext_noop ("# disconnects due to blacklist"),
3497                                 1,
3498                                 GNUNET_NO);
3499       disconnect_neighbour (orig, GNUNET_NO);
3500     }
3501 }
3502
3503
3504 /**
3505  * Handle a request to start a blacklist.
3506  *
3507  * @param cls closure (always NULL)
3508  * @param client identification of the client
3509  * @param message the actual message
3510  */
3511 static void
3512 handle_blacklist_init (void *cls,
3513                        struct GNUNET_SERVER_Client *client,
3514                        const struct GNUNET_MessageHeader *message)
3515 {
3516   struct Blacklisters *bl;
3517   struct BlacklistCheck *bc;
3518   struct NeighbourList *n;
3519
3520   bl = bl_head;
3521   while (bl != NULL)
3522     {
3523       if (bl->client == client)
3524         {
3525           GNUNET_break (0);
3526           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3527           return;
3528         }
3529       bl = bl->next;
3530     }
3531   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3532   bl->client = client;
3533   GNUNET_SERVER_client_keep (client);
3534   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3535   /* confirm that all existing connections are OK! */
3536   n = neighbours;
3537   while (NULL != n)
3538     {
3539       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3540       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3541       bc->peer = n->id;
3542       bc->do_hello = GNUNET_NO;
3543       bc->cont = &confirm_or_drop_neighbour;
3544       bc->cont_cls = n;
3545       bc->bl_pos = bl;
3546       if (n == neighbours) /* all would wait for the same client, no need to
3547                               create more than just the first task right now */
3548         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3549                                              bc);
3550       n = n->next;
3551     }
3552 }
3553
3554
3555 /**
3556  * Handle a request to blacklist a peer.
3557  *
3558  * @param cls closure (always NULL)
3559  * @param client identification of the client
3560  * @param message the actual message
3561  */
3562 static void
3563 handle_blacklist_reply (void *cls,
3564                         struct GNUNET_SERVER_Client *client,
3565                         const struct GNUNET_MessageHeader *message)
3566 {
3567   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3568   struct Blacklisters *bl;
3569   struct BlacklistCheck *bc;
3570
3571   bl = bl_head;
3572   while ( (bl != NULL) &&
3573           (bl->client != client) )
3574     bl = bl->next;
3575   if (bl == NULL)
3576     {
3577 #if DEBUG_TRANSPORT
3578       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3579                   "Blacklist client disconnected\n");
3580 #endif
3581       /* FIXME: other error handling here!? */
3582       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3583       return;
3584     }
3585   bc = bl->bc;
3586   bl->bc = NULL;
3587   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3588     {
3589 #if DEBUG_TRANSPORT
3590       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3591                   "Blacklist check failed, peer not allowed\n");
3592 #endif
3593       bc->cont (bc->cont_cls, NULL);
3594       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3595       GNUNET_free (bc);
3596     }
3597   else
3598     {
3599 #if DEBUG_TRANSPORT
3600       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3601                   "Blacklist check succeeded, continuing with checks\n");
3602 #endif
3603       bc->bl_pos = bc->bl_pos->next;
3604       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3605                                            bc);
3606     }
3607   /* check if any other bc's are waiting for this blacklister */
3608   bc = bc_head;
3609   while (bc != NULL)
3610     {
3611       if ( (bc->bl_pos == bl) &&
3612            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3613         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3614                                              bc);
3615       bc = bc->next;
3616     }
3617 }
3618
3619
3620 /**
3621  * Send periodic PING messages to a given foreign address.
3622  *
3623  * @param cls our 'struct PeriodicValidationContext*'
3624  * @param tc task context
3625  */
3626 static void
3627 send_periodic_ping (void *cls,
3628                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3629 {
3630   struct ForeignAddressList *peer_address = cls;
3631   struct TransportPlugin *tp;
3632   struct ValidationEntry *va;
3633   struct NeighbourList *neighbour;
3634   struct TransportPingMessage ping;
3635   struct CheckAddressExistsClosure caec;
3636   char * message_buf;
3637   uint16_t hello_size;
3638   size_t slen;
3639   size_t tsize;
3640
3641   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3642   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3643     return;
3644   tp = peer_address->ready_list->plugin;
3645   neighbour = peer_address->ready_list->neighbour;
3646   if (GNUNET_YES != neighbour->public_key_valid)
3647     {
3648       /* no public key yet, try again later */
3649       schedule_next_ping (peer_address);
3650       return;
3651     }
3652   caec.addr = peer_address->addr;
3653   caec.addrlen = peer_address->addrlen;
3654   caec.tname = tp->short_name;
3655   caec.session = peer_address->session;
3656   caec.exists = GNUNET_NO;
3657   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3658                                          &check_address_exists,
3659                                          &caec);
3660   if (caec.exists == GNUNET_YES)
3661     {
3662       /* During validation attempts we will likely trigger the other
3663          peer trying to validate our address which in turn will cause
3664          it to send us its HELLO, so we expect to hit this case rather
3665          frequently.  Only print something if we are very verbose. */
3666 #if DEBUG_TRANSPORT > 1
3667       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3668                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3669                   (peer_address->addr != NULL)
3670                   ? a2s (tp->short_name,
3671                          peer_address->addr,
3672                          peer_address->addrlen)
3673                   : "<inbound>",
3674                   tp->short_name,
3675                   GNUNET_i2s (&neighbour->id));
3676 #endif
3677       schedule_next_ping (peer_address);
3678       return;
3679     }
3680   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3681   va->transport_name = GNUNET_strdup (tp->short_name);
3682   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3683                                             UINT_MAX);
3684   va->send_time = GNUNET_TIME_absolute_get();
3685   va->session = peer_address->session;
3686   if (peer_address->addr != NULL)
3687     {
3688       va->addr = (const void*) &va[1];
3689       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3690       va->addrlen = peer_address->addrlen;
3691     }
3692   memcpy(&va->publicKey,
3693          &neighbour->publicKey,
3694          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3695
3696   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3697                                                    &timeout_hello_validation,
3698                                                    va);
3699   GNUNET_CONTAINER_multihashmap_put (validation_map,
3700                                      &neighbour->id.hashPubKey,
3701                                      va,
3702                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3703
3704   if (peer_address->validated != GNUNET_YES)
3705     hello_size = GNUNET_HELLO_size(our_hello);
3706   else
3707     hello_size = 0;
3708
3709   tsize = sizeof(struct TransportPingMessage) + hello_size;
3710
3711   if (peer_address->addr != NULL)
3712     {
3713       slen = strlen (tp->short_name) + 1;
3714       tsize += slen + peer_address->addrlen;
3715     }
3716   else
3717     {
3718       slen = 0; /* make gcc happy */
3719     }
3720   message_buf = GNUNET_malloc(tsize);
3721   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3722   ping.challenge = htonl(va->challenge);
3723   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3724   if (peer_address->validated != GNUNET_YES)
3725     {
3726       memcpy(message_buf, our_hello, hello_size);
3727     }
3728
3729   if (peer_address->addr != NULL)
3730     {
3731       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3732                                peer_address->addrlen +
3733                                slen);
3734       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3735              tp->short_name,
3736              slen);
3737       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3738              peer_address->addr,
3739              peer_address->addrlen);
3740     }
3741   else
3742     {
3743       ping.header.size = htons(sizeof(struct TransportPingMessage));
3744     }
3745
3746   memcpy(&message_buf[hello_size],
3747          &ping,
3748          sizeof(struct TransportPingMessage));
3749
3750 #if DEBUG_TRANSPORT_REVALIDATION
3751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3752               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3753               (peer_address->addr != NULL)
3754               ? a2s (peer_address->plugin->short_name,
3755                      peer_address->addr,
3756                      peer_address->addrlen)
3757               : "<inbound>",
3758               tp->short_name,
3759               GNUNET_i2s (&neighbour->id),
3760               "HELLO", hello_size,
3761               "PING");
3762 #endif
3763   if (peer_address->validated != GNUNET_YES)
3764     GNUNET_STATISTICS_update (stats,
3765                               gettext_noop ("# PING with HELLO messages sent"),
3766                               1,
3767                               GNUNET_NO);
3768   else
3769     GNUNET_STATISTICS_update (stats,
3770                               gettext_noop ("# PING without HELLO messages sent"),
3771                               1,
3772                               GNUNET_NO);
3773   GNUNET_STATISTICS_update (stats,
3774                             gettext_noop ("# PING messages sent for re-validation"),
3775                             1,
3776                             GNUNET_NO);
3777   transmit_to_peer (NULL, peer_address,
3778                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3779                     HELLO_VERIFICATION_TIMEOUT,
3780                     message_buf, tsize,
3781                     GNUNET_YES, neighbour);
3782   GNUNET_free(message_buf);
3783   schedule_next_ping (peer_address);
3784 }
3785
3786
3787 /**
3788  * Schedule the job that will cause us to send a PING to the
3789  * foreign address to evaluate its validity and latency.
3790  *
3791  * @param fal address to PING
3792  */
3793 static void
3794 schedule_next_ping (struct ForeignAddressList *fal)
3795 {
3796   struct GNUNET_TIME_Relative delay;
3797
3798   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3799     return;
3800   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3801   delay.rel_value /= 2; /* do before expiration */
3802   delay = GNUNET_TIME_relative_min (delay,
3803                                     LATENCY_EVALUATION_MAX_DELAY);
3804   if (GNUNET_YES != fal->estimated)
3805     {
3806       delay = GNUNET_TIME_UNIT_ZERO;
3807       fal->estimated = GNUNET_YES;
3808     }
3809   if (GNUNET_YES == fal->connected)
3810     {
3811       delay = GNUNET_TIME_relative_min (delay,
3812                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3813     }
3814   /* FIXME: also adjust delay based on how close the last
3815      observed latency is to the latency of the best alternative */
3816   /* bound how fast we can go */
3817   delay = GNUNET_TIME_relative_max (delay,
3818                                     GNUNET_TIME_UNIT_SECONDS);
3819   /* randomize a bit (to avoid doing all at the same time) */
3820   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3821   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3822                                                       &send_periodic_ping,
3823                                                       fal);
3824 }
3825
3826
3827
3828
3829 /**
3830  * Function that will be called if we receive some payload
3831  * from another peer.
3832  *
3833  * @param message the payload
3834  * @param n peer who claimed to be the sender
3835  */
3836 static void
3837 handle_payload_message (const struct GNUNET_MessageHeader *message,
3838                         struct NeighbourList *n)
3839 {
3840   struct InboundMessage *im;
3841   struct TransportClient *cpos;
3842   uint16_t msize;
3843
3844   msize = ntohs (message->size);
3845   if (n->received_pong == GNUNET_NO)
3846     {
3847 #if DEBUG_TRANSPORT
3848       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3849                   "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3850                   ntohs (message->type),
3851                   ntohs (message->size),
3852                   GNUNET_i2s (&n->id));
3853 #endif
3854       GNUNET_free_non_null (n->pre_connect_message_buffer);
3855       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3856       memcpy (n->pre_connect_message_buffer, message, msize);
3857       return;
3858     }
3859
3860 #if DEBUG_TRANSPORT
3861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3862               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3863               ntohs (message->type),
3864               ntohs (message->size),
3865               GNUNET_i2s (&n->id));
3866 #endif
3867   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3868                                                       (ssize_t) msize))
3869     {
3870       n->quota_violation_count++;
3871 #if DEBUG_TRANSPORT
3872       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3873                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3874                   n->in_tracker.available_bytes_per_s__,
3875                   n->quota_violation_count);
3876 #endif
3877       /* Discount 32k per violation */
3878       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3879                                         - 32 * 1024);
3880     }
3881   else
3882     {
3883       if (n->quota_violation_count > 0)
3884         {
3885           /* try to add 32k back */
3886           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3887                                             32 * 1024);
3888           n->quota_violation_count--;
3889         }
3890     }
3891   GNUNET_STATISTICS_update (stats,
3892                             gettext_noop ("# payload received from other peers"),
3893                             msize,
3894                             GNUNET_NO);
3895   /* transmit message to all clients */
3896   uint32_t ats_count = 2;
3897   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3898   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3899           GNUNET_break(0);
3900
3901   im = GNUNET_malloc (size);
3902   im->header.size = htons (size);
3903   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3904   im->peer = n->id;
3905   im->ats_count = htonl(ats_count);
3906   /* Setting ATS data */
3907   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3908   (&(im->ats))[0].value = htonl (n->distance);
3909   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3910   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3911   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3912   (&(im->ats))[ats_count].value = htonl (0);
3913
3914   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3915   cpos = clients;
3916   while (cpos != NULL)
3917     {
3918       transmit_to_client (cpos, &im->header, GNUNET_YES);
3919       cpos = cpos->next;
3920     }
3921   GNUNET_free (im);
3922 }
3923
3924
3925 /**
3926  * Iterator over hash map entries.  Checks if the given validation
3927  * entry is for the same challenge as what is given in the PONG.
3928  *
3929  * @param cls the 'struct TransportPongMessage*'
3930  * @param key peer identity
3931  * @param value value in the hash map ('struct ValidationEntry')
3932  * @return GNUNET_YES if we should continue to
3933  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3934  */
3935 static int
3936 check_pending_validation (void *cls,
3937                           const GNUNET_HashCode * key,
3938                           void *value)
3939 {
3940   const struct TransportPongMessage *pong = cls;
3941   struct ValidationEntry *ve = value;
3942   struct AddValidatedAddressContext avac;
3943   unsigned int challenge = ntohl(pong->challenge);
3944   struct GNUNET_HELLO_Message *hello;
3945   struct GNUNET_PeerIdentity target;
3946   struct NeighbourList *n;
3947   struct ForeignAddressList *fal;
3948   struct OwnAddressList *oal;
3949   struct TransportPlugin *tp;
3950   struct GNUNET_MessageHeader *prem;
3951   uint16_t ps;
3952   const char *addr;
3953   size_t slen;
3954   size_t alen;
3955
3956   ps = ntohs (pong->header.size);
3957   if (ps < sizeof (struct TransportPongMessage))
3958     {
3959       GNUNET_break_op (0);
3960       return GNUNET_NO;
3961     }
3962   addr = (const char*) &pong[1];
3963   slen = strlen (ve->transport_name) + 1;
3964   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3965        (ve->challenge != challenge) ||
3966        (addr[slen-1] != '\0') ||
3967        (0 != strcmp (addr, ve->transport_name)) ||
3968        (ntohl (pong->purpose.size)
3969         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3970         sizeof (uint32_t) +
3971         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3972         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3973     {
3974       return GNUNET_YES;
3975     }
3976
3977   alen = ps - sizeof (struct TransportPongMessage) - slen;
3978   switch (ntohl (pong->purpose.purpose))
3979     {
3980     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3981       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3982            (0 != memcmp (&addr[slen],
3983                          ve->addr,
3984                          ve->addrlen)) )
3985         {
3986           return GNUNET_YES; /* different entry, keep trying! */
3987         }
3988       if (0 != memcmp (&pong->pid,
3989                        key,
3990                        sizeof (struct GNUNET_PeerIdentity)))
3991         {
3992           GNUNET_break_op (0);
3993           return GNUNET_NO;
3994         }
3995       if (GNUNET_OK !=
3996           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3997                                     &pong->purpose,
3998                                     &pong->signature,
3999                                     &ve->publicKey))
4000         {
4001           GNUNET_break_op (0);
4002           return GNUNET_NO;
4003         }
4004
4005 #if DEBUG_TRANSPORT
4006       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4007                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4008                   GNUNET_h2s (key),
4009                   a2s (ve->transport_name,
4010                        (const struct sockaddr *) ve->addr,
4011                        ve->addrlen),
4012                   ve->transport_name);
4013 #endif
4014       break;
4015     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4016       if (0 != memcmp (&pong->pid,
4017                          &my_identity,
4018                          sizeof (struct GNUNET_PeerIdentity)))
4019         {
4020           char * peer;
4021
4022           GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4023 #if DEBUG_TRANSPORT
4024           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4025                       "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4026                       GNUNET_i2s (&my_identity), 
4027                       peer );
4028 #endif
4029           GNUNET_free (peer);
4030           return GNUNET_NO;
4031         }
4032       if (ve->addrlen != 0)
4033         {
4034           /* must have been for a different validation entry */
4035           return GNUNET_YES;
4036         }
4037       tp = find_transport (ve->transport_name);
4038       if (tp == NULL)
4039         {
4040           GNUNET_break (0);
4041           return GNUNET_YES;
4042         }
4043       oal = tp->addresses;
4044       while (NULL != oal)
4045         {
4046           if ( (oal->addrlen == alen) &&
4047                (0 == memcmp (&oal[1],
4048                              &addr[slen],
4049                              alen)) )
4050             break;
4051           oal = oal->next;
4052         }
4053       if (oal == NULL)
4054         {
4055           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4056                       _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4057                       GNUNET_i2s (&pong->pid),
4058                       a2s (ve->transport_name,
4059                            &addr[slen],
4060                            alen));
4061           /* FIXME: since the sender of the PONG currently uses the
4062              wrong address (see FIMXE there!), we cannot run a 
4063              proper check here... */
4064 #if FIXME_URGENT
4065           return GNUNET_NO;
4066 #endif
4067         }
4068       if (GNUNET_OK !=
4069           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4070                                     &pong->purpose,
4071                                     &pong->signature,
4072                                     &ve->publicKey))
4073         {
4074           GNUNET_break_op (0);
4075           return GNUNET_NO;
4076         }
4077
4078 #if DEBUG_TRANSPORT
4079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4080                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4081                   GNUNET_h2s (key),
4082                   a2s (ve->transport_name,
4083                        &addr[slen],
4084                        alen),
4085                   ve->transport_name);
4086 #endif
4087       break;
4088     default:
4089       GNUNET_break_op (0);
4090       return GNUNET_NO;
4091     }
4092   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4093     {
4094       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4095                   _("Received expired signature.  Check system time.\n"));
4096       return GNUNET_NO;
4097     }
4098   GNUNET_STATISTICS_update (stats,
4099                             gettext_noop ("# address validation successes"),
4100                             1,
4101                             GNUNET_NO);
4102   /* create the updated HELLO */
4103   GNUNET_CRYPTO_hash (&ve->publicKey,
4104                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4105                       &target.hashPubKey);
4106   if (ve->addr != NULL)
4107     {
4108       avac.done = GNUNET_NO;
4109       avac.ve = ve;
4110       hello = GNUNET_HELLO_create (&ve->publicKey,
4111                                    &add_validated_address,
4112                                    &avac);
4113       GNUNET_PEERINFO_add_peer (peerinfo,
4114                                 hello);
4115       GNUNET_free (hello);
4116     }
4117   n = find_neighbour (&target);
4118   if (n != NULL)
4119     {
4120       n->publicKey = ve->publicKey;
4121       n->public_key_valid = GNUNET_YES;
4122       fal = add_peer_address (n,
4123                               ve->transport_name,
4124                               ve->session,
4125                               ve->addr,
4126                               ve->addrlen);
4127       GNUNET_assert (fal != NULL);
4128       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4129       fal->validated = GNUNET_YES;
4130       mark_address_connected (fal);
4131       GNUNET_STATISTICS_update (stats,
4132                                 gettext_noop ("# peer addresses considered valid"),
4133                                 1,
4134                                 GNUNET_NO);
4135       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4136       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4137
4138       schedule_next_ping (fal);
4139       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4140         n->latency = fal->latency;
4141       else
4142         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4143
4144       n->distance = fal->distance;
4145       if (GNUNET_NO == n->received_pong)
4146         {
4147           n->received_pong = GNUNET_YES;
4148           notify_clients_connect (&target, n->latency, n->distance);
4149           if (NULL != (prem = n->pre_connect_message_buffer))
4150             {
4151               n->pre_connect_message_buffer = NULL;
4152               handle_payload_message (prem, n);
4153               GNUNET_free (prem);
4154             }
4155         }
4156       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4157         {
4158           GNUNET_SCHEDULER_cancel (n->retry_task);
4159           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4160           try_transmission_to_peer (n);
4161         }
4162     }
4163
4164   /* clean up validation entry */
4165   GNUNET_assert (GNUNET_YES ==
4166                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4167                                                        key,
4168                                                        ve));
4169   abort_validation (NULL, NULL, ve);
4170   return GNUNET_NO;
4171 }
4172
4173
4174 /**
4175  * Function that will be called if we receive a validation
4176  * of an address challenge that we transmitted to another
4177  * peer.  Note that the validation should only be considered
4178  * acceptable if the challenge matches AND if the sender
4179  * address is at least a plausible address for this peer
4180  * (otherwise we may be seeing a MiM attack).
4181  *
4182  * @param cls closure
4183  * @param message the pong message
4184  * @param peer who responded to our challenge
4185  * @param sender_address string describing our sender address (as observed
4186  *         by the other peer in binary format)
4187  * @param sender_address_len number of bytes in 'sender_address'
4188  */
4189 static void
4190 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4191              const struct GNUNET_PeerIdentity *peer,
4192              const char *sender_address,
4193              size_t sender_address_len)
4194 {
4195   if (0 == memcmp (peer,
4196                    &my_identity,
4197                    sizeof (struct GNUNET_PeerIdentity)))
4198     {
4199       /* PONG send to self, ignore */
4200       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4201                   "Receiving `%s' message from myself\n", 
4202                   "PONG");
4203       return;
4204     }
4205 #if DEBUG_TRANSPORT > 1
4206   /* we get tons of these that just get discarded, only log
4207      if we are quite verbose */
4208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4209               "Receiving `%s' message from `%4s'.\n", "PONG",
4210               GNUNET_i2s (peer));
4211 #endif
4212   GNUNET_STATISTICS_update (stats,
4213                             gettext_noop ("# PONG messages received"),
4214                             1,
4215                             GNUNET_NO);
4216   if (GNUNET_SYSERR !=
4217       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4218                                                   &peer->hashPubKey,
4219                                                   &check_pending_validation,
4220                                                   (void*) message))
4221     {
4222       /* This is *expected* to happen a lot since we send
4223          PONGs to *all* known addresses of the sender of
4224          the PING, so most likely we get multiple PONGs
4225          per PING, and all but the first PONG will end up
4226          here. So really we should not print anything here
4227          unless we want to be very, very verbose... */
4228 #if DEBUG_TRANSPORT > 2
4229       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4230                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4231                   "PONG",
4232                   GNUNET_i2s (peer),
4233                   "PING");
4234 #endif
4235       return;
4236     }
4237
4238 }
4239
4240
4241 /**
4242  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4243  *
4244  * @param cls the 'struct ValidationEntry*'
4245  * @param neighbour neighbour to validate, NULL if validation failed
4246  */
4247 static void
4248 transmit_hello_and_ping (void *cls,
4249                          struct NeighbourList *neighbour)
4250 {
4251   struct ValidationEntry *va = cls;
4252   struct ForeignAddressList *peer_address;
4253   struct TransportPingMessage ping;
4254   uint16_t hello_size;
4255   size_t tsize;
4256   char * message_buf;
4257   struct GNUNET_PeerIdentity id;
4258   size_t slen;
4259
4260   GNUNET_CRYPTO_hash (&va->publicKey,
4261                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4262                       &id.hashPubKey);
4263   if (neighbour == NULL)
4264     {
4265       /* FIXME: stats... */
4266       GNUNET_break (GNUNET_OK ==
4267                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4268                                                           &id.hashPubKey,
4269                                                           va));
4270       abort_validation (NULL, NULL, va);
4271       return;
4272     }
4273   neighbour->publicKey = va->publicKey;
4274   neighbour->public_key_valid = GNUNET_YES;
4275   peer_address = add_peer_address (neighbour,
4276                                    va->transport_name, NULL,
4277                                    (const void*) &va[1],
4278                                    va->addrlen);
4279   if (peer_address == NULL)
4280     {
4281       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4282                   "Failed to add peer `%4s' for plugin `%s'\n",
4283                   GNUNET_i2s (&neighbour->id),
4284                   va->transport_name);
4285       GNUNET_break (GNUNET_OK ==
4286                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4287                                                           &id.hashPubKey,
4288                                                           va));
4289       abort_validation (NULL, NULL, va);
4290       return;
4291     }
4292   if (NULL == our_hello)
4293     refresh_hello_task (NULL, NULL);
4294   hello_size = GNUNET_HELLO_size(our_hello);
4295   slen = strlen(va->transport_name) + 1;
4296   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4297   message_buf = GNUNET_malloc(tsize);
4298   ping.challenge = htonl(va->challenge);
4299   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4300   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4301   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4302   memcpy(message_buf, our_hello, hello_size);
4303   memcpy(&message_buf[hello_size],
4304          &ping,
4305          sizeof(struct TransportPingMessage));
4306   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4307          va->transport_name,
4308          slen);
4309   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4310          &va[1],
4311          va->addrlen);
4312 #if DEBUG_TRANSPORT
4313   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4314               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4315               (va->addrlen == 0)
4316               ? "<inbound>"
4317               : a2s (va->transport_name,
4318                      (const void*) &va[1], va->addrlen),
4319               va->transport_name,
4320               GNUNET_i2s (&neighbour->id),
4321               "HELLO", hello_size,
4322               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4323 #endif
4324
4325   GNUNET_STATISTICS_update (stats,
4326                             gettext_noop ("# PING messages sent for initial validation"),
4327                             1,
4328                             GNUNET_NO);
4329   transmit_to_peer (NULL, peer_address,
4330                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4331                     HELLO_VERIFICATION_TIMEOUT,
4332                     message_buf, tsize,
4333                     GNUNET_YES, neighbour);
4334   GNUNET_free(message_buf);
4335 }
4336
4337
4338 /**
4339  * Check if the given address is already being validated; if not,
4340  * append the given address to the list of entries that are being be
4341  * validated and initiate validation.
4342  *
4343  * @param cls closure ('struct CheckHelloValidatedContext *')
4344  * @param tname name of the transport
4345  * @param expiration expiration time
4346  * @param addr the address
4347  * @param addrlen length of the address
4348  * @return GNUNET_OK (always)
4349  */
4350 static int
4351 run_validation (void *cls,
4352                 const char *tname,
4353                 struct GNUNET_TIME_Absolute expiration,
4354                 const void *addr,
4355                 uint16_t addrlen)
4356 {
4357   struct CheckHelloValidatedContext *chvc = cls;
4358   struct GNUNET_PeerIdentity id;
4359   struct TransportPlugin *tp;
4360   struct ValidationEntry *va;
4361   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4362   struct CheckAddressExistsClosure caec;
4363   struct OwnAddressList *oal;
4364
4365   GNUNET_assert (addr != NULL);
4366
4367   GNUNET_STATISTICS_update (stats,
4368                             gettext_noop ("# peer addresses scheduled for validation"),
4369                             1,
4370                             GNUNET_NO);
4371   tp = find_transport (tname);
4372   if (tp == NULL)
4373     {
4374       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4375                   GNUNET_ERROR_TYPE_BULK,
4376                   _
4377                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4378                   tname);
4379       GNUNET_STATISTICS_update (stats,
4380                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4381                                 1,
4382                                 GNUNET_NO);
4383       return GNUNET_OK;
4384     }
4385   /* check if this is one of our own addresses */
4386   oal = tp->addresses;
4387   while (NULL != oal)
4388     {
4389       if ( (oal->addrlen == addrlen) &&
4390            (0 == memcmp (&oal[1],
4391                          addr,
4392                          addrlen)) )
4393         {
4394           /* not plausible, this address is equivalent to our own address! */
4395           GNUNET_STATISTICS_update (stats,
4396                                     gettext_noop ("# peer addresses not validated (loopback)"),
4397                                     1,
4398                                     GNUNET_NO);
4399           return GNUNET_OK;
4400         }
4401       oal = oal->next;
4402     }
4403   GNUNET_HELLO_get_key (chvc->hello, &pk);
4404   GNUNET_CRYPTO_hash (&pk,
4405                       sizeof (struct
4406                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4407                       &id.hashPubKey);
4408
4409   if (is_blacklisted(&id, tp))
4410     {
4411 #if DEBUG_TRANSPORT
4412       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4413                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4414                   GNUNET_i2s(&id),
4415                   tname);
4416 #endif
4417       return GNUNET_OK;
4418     }
4419
4420   caec.addr = addr;
4421   caec.addrlen = addrlen;
4422   caec.session = NULL;
4423   caec.tname = tname;
4424   caec.exists = GNUNET_NO;
4425   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4426                                          &check_address_exists,
4427                                          &caec);
4428   if (caec.exists == GNUNET_YES)
4429     {
4430       /* During validation attempts we will likely trigger the other
4431          peer trying to validate our address which in turn will cause
4432          it to send us its HELLO, so we expect to hit this case rather
4433          frequently.  Only print something if we are very verbose. */
4434 #if DEBUG_TRANSPORT > 1
4435       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4436                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4437                   a2s (tname, addr, addrlen),
4438                   tname,
4439                   GNUNET_i2s (&id));
4440 #endif
4441       GNUNET_STATISTICS_update (stats,
4442                                 gettext_noop ("# peer addresses not validated (in progress)"),
4443                                 1,
4444                                 GNUNET_NO);
4445       return GNUNET_OK;
4446     }
4447   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4448   va->chvc = chvc;
4449   chvc->ve_count++;
4450   va->transport_name = GNUNET_strdup (tname);
4451   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4452                                             UINT_MAX);
4453   va->send_time = GNUNET_TIME_absolute_get();
4454   va->addr = (const void*) &va[1];
4455   memcpy (&va[1], addr, addrlen);
4456   va->addrlen = addrlen;
4457   GNUNET_HELLO_get_key (chvc->hello,
4458                         &va->publicKey);
4459   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4460                                                    &timeout_hello_validation,
4461                                                    va);
4462   GNUNET_CONTAINER_multihashmap_put (validation_map,
4463                                      &id.hashPubKey,
4464                                      va,
4465                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4466   setup_peer_check_blacklist (&id, GNUNET_NO,
4467                               &transmit_hello_and_ping,
4468                               va);
4469   return GNUNET_OK;
4470 }
4471
4472
4473 /**
4474  * Check if addresses in validated hello "h" overlap with
4475  * those in "chvc->hello" and validate the rest.
4476  *
4477  * @param cls closure
4478  * @param peer id of the peer, NULL for last call
4479  * @param h hello message for the peer (can be NULL)
4480  * @param err_msg NULL if successful, otherwise contains error message
4481  */
4482 static void
4483 check_hello_validated (void *cls,
4484                        const struct GNUNET_PeerIdentity *peer,
4485                        const struct GNUNET_HELLO_Message *h,
4486                        const char *err_msg)
4487 {
4488   struct CheckHelloValidatedContext *chvc = cls;
4489   struct GNUNET_HELLO_Message *plain_hello;
4490   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4491   struct GNUNET_PeerIdentity target;
4492   struct NeighbourList *n;
4493
4494   if (err_msg != NULL)
4495     {
4496 #if DEBUG_TRANSPORT
4497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4498                   _("Error in communication with PEERINFO service: %s\n"),
4499                   err_msg);
4500 #endif
4501       /* return; */
4502   }
4503
4504   if (peer == NULL)
4505     {
4506       GNUNET_STATISTICS_update (stats,
4507                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4508                                 -1,
4509                                 GNUNET_NO);
4510       chvc->piter = NULL;
4511       if (GNUNET_NO == chvc->hello_known)
4512         {
4513           /* notify PEERINFO about the peer now, so that we at least
4514              have the public key if some other component needs it */
4515           GNUNET_HELLO_get_key (chvc->hello, &pk);
4516           GNUNET_CRYPTO_hash (&pk,
4517                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4518                               &target.hashPubKey);
4519           plain_hello = GNUNET_HELLO_create (&pk,
4520                                              NULL,
4521                                              NULL);
4522           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4523           GNUNET_free (plain_hello);
4524 #if DEBUG_TRANSPORT_HELLO
4525           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4526                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4527                       "HELLO",
4528                       GNUNET_i2s (&target));
4529 #endif
4530           GNUNET_STATISTICS_update (stats,
4531                                     gettext_noop ("# new HELLOs requiring full validation"),
4532                                     1,
4533                                     GNUNET_NO);
4534           GNUNET_HELLO_iterate_addresses (chvc->hello,
4535                                           GNUNET_NO,
4536                                           &run_validation,
4537                                           chvc);
4538         }
4539       else
4540         {
4541           GNUNET_STATISTICS_update (stats,
4542                                     gettext_noop ("# duplicate HELLO (peer known)"),
4543                                     1,
4544                                     GNUNET_NO);
4545         }
4546       chvc->ve_count--;
4547       if (chvc->ve_count == 0)
4548         {
4549           GNUNET_CONTAINER_DLL_remove (chvc_head,
4550                                        chvc_tail,
4551                                        chvc);
4552           GNUNET_free (chvc);
4553         }
4554       return;
4555     }
4556   if (h == NULL)
4557     return;
4558 #if DEBUG_TRANSPORT_HELLO
4559   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4560               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4561               "HELLO",
4562               GNUNET_i2s (peer));
4563 #endif
4564   chvc->hello_known = GNUNET_YES;
4565   n = find_neighbour (peer);
4566   if (n != NULL)
4567     {
4568 #if DEBUG_TRANSPORT_HELLO
4569       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4570                   "Calling hello_iterate_addresses for %s!\n",
4571                   GNUNET_i2s (peer));
4572 #endif
4573       GNUNET_HELLO_iterate_addresses (h,
4574                                       GNUNET_NO,
4575                                       &add_to_foreign_address_list,
4576                                       n);
4577       try_transmission_to_peer (n);
4578     }
4579   else
4580     {
4581 #if DEBUG_TRANSPORT_HELLO
4582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4583                   "No existing neighbor record for %s!\n",
4584                   GNUNET_i2s (peer));
4585 #endif
4586       GNUNET_STATISTICS_update (stats,
4587                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4588                                 1,
4589                                 GNUNET_NO);
4590     }
4591   GNUNET_STATISTICS_update (stats,
4592                             gettext_noop ("# HELLO validations (update case)"),
4593                             1,
4594                             GNUNET_NO);
4595   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4596                                       h,
4597                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4598                                       &run_validation,
4599                                       chvc);
4600 }
4601
4602
4603 /**
4604  * Process HELLO-message.
4605  *
4606  * @param plugin transport involved, may be NULL
4607  * @param message the actual message
4608  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4609  */
4610 static int
4611 process_hello (struct TransportPlugin *plugin,
4612                const struct GNUNET_MessageHeader *message)
4613 {
4614   uint16_t hsize;
4615   struct GNUNET_PeerIdentity target;
4616   const struct GNUNET_HELLO_Message *hello;
4617   struct CheckHelloValidatedContext *chvc;
4618   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4619   struct NeighbourList *n;
4620 #if DEBUG_TRANSPORT_HELLO > 2
4621   char *my_id;
4622 #endif
4623
4624   hsize = ntohs (message->size);
4625   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4626       (hsize < sizeof (struct GNUNET_MessageHeader)))
4627     {
4628       GNUNET_break (0);
4629       return GNUNET_SYSERR;
4630     }
4631   GNUNET_STATISTICS_update (stats,
4632                             gettext_noop ("# HELLOs received for validation"),
4633                             1,
4634                             GNUNET_NO);
4635
4636   hello = (const struct GNUNET_HELLO_Message *) message;
4637   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4638     {
4639 #if DEBUG_TRANSPORT_HELLO
4640       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4641                   "Unable to get public key from `%s' for `%4s'!\n",
4642                   "HELLO",
4643                   GNUNET_i2s (&target));
4644 #endif
4645       GNUNET_break_op (0);
4646       return GNUNET_SYSERR;
4647     }
4648   GNUNET_CRYPTO_hash (&publicKey,
4649                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4650                       &target.hashPubKey);
4651
4652 #if DEBUG_TRANSPORT_HELLO
4653   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4654               "Received `%s' message for `%4s'\n",
4655               "HELLO",
4656               GNUNET_i2s (&target));
4657 #endif
4658   if (0 == memcmp (&my_identity,
4659                    &target,
4660                    sizeof (struct GNUNET_PeerIdentity)))
4661     {
4662       GNUNET_STATISTICS_update (stats,
4663                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4664                                 1,
4665                                 GNUNET_NO);
4666       return GNUNET_OK;
4667     }
4668   n = find_neighbour (&target);
4669   if ( (NULL != n) &&
4670        (! n->public_key_valid) )
4671     {
4672       GNUNET_HELLO_get_key (hello, &n->publicKey);
4673       n->public_key_valid = GNUNET_YES;
4674     }
4675
4676   /* check if load is too high before doing expensive stuff */
4677   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4678     {
4679       GNUNET_STATISTICS_update (stats,
4680                                 gettext_noop ("# HELLOs ignored due to high load"),
4681                                 1,
4682                                 GNUNET_NO);
4683 #if DEBUG_TRANSPORT_HELLO
4684       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4685                   "Ignoring `%s' for `%4s', load too high.\n",
4686                   "HELLO",
4687                   GNUNET_i2s (&target));
4688 #endif
4689       return GNUNET_OK;
4690     }
4691
4692
4693   chvc = chvc_head;
4694   while (NULL != chvc)
4695     {
4696       if (GNUNET_HELLO_equals (hello,
4697                                chvc->hello,
4698                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4699         {
4700 #if DEBUG_TRANSPORT_HELLO > 2
4701           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4702                       "Received duplicate `%s' message for `%4s'; ignored\n",
4703                       "HELLO",
4704                       GNUNET_i2s (&target));
4705 #endif
4706           return GNUNET_OK; /* validation already pending */
4707         }
4708       if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4709         GNUNET_break (0 != memcmp (hello, chvc->hello,
4710                                    GNUNET_HELLO_size(hello)));
4711       chvc = chvc->next;
4712     }
4713
4714 #if BREAK_TESTS
4715   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4716   if ((NULL != temp_neighbor))
4717     {
4718       fprintf(stderr, "Already know peer, ignoring hello\n");
4719       return GNUNET_OK;
4720     }
4721 #endif
4722
4723 #if DEBUG_TRANSPORT_HELLO > 2
4724   if (plugin != NULL)
4725     {
4726       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4727 #if DEBUG_TRANSPORT
4728       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4729                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4730                   my_id,
4731                   "HELLO",
4732                   GNUNET_i2s (&target),
4733                   plugin->short_name,
4734                   GNUNET_HELLO_size(hello));
4735 #endif
4736       GNUNET_free(my_id);
4737     }
4738 #endif
4739   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4740   chvc->ve_count = 1;
4741   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4742   memcpy (&chvc[1], hello, hsize);
4743   GNUNET_CONTAINER_DLL_insert (chvc_head,
4744                                chvc_tail,
4745                                chvc);
4746   /* finally, check if HELLO was previously validated
4747      (continuation will then schedule actual validation) */
4748   GNUNET_STATISTICS_update (stats,
4749                             gettext_noop ("# peerinfo process hello iterate requests"),
4750                             1,
4751                             GNUNET_NO);
4752   GNUNET_STATISTICS_update (stats,
4753                             gettext_noop ("# outstanding peerinfo iterate requests"),
4754                             1,
4755                             GNUNET_NO);
4756   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4757                                          &target,
4758                                          HELLO_VERIFICATION_TIMEOUT,
4759                                          &check_hello_validated, chvc);
4760   return GNUNET_OK;
4761 }
4762
4763
4764 /**
4765  * The peer specified by the given neighbour has timed-out or a plugin
4766  * has disconnected.  We may either need to do nothing (other plugins
4767  * still up), or trigger a full disconnect and clean up.  This
4768  * function updates our state and does the necessary notifications.
4769  * Also notifies our clients that the neighbour is now officially
4770  * gone.
4771  *
4772  * @param n the neighbour list entry for the peer
4773  * @param check GNUNET_YES to check if ALL addresses for this peer
4774  *              are gone, GNUNET_NO to force a disconnect of the peer
4775  *              regardless of whether other addresses exist.
4776  */
4777 static void
4778 disconnect_neighbour (struct NeighbourList *n, int check)
4779 {
4780   struct ReadyList *rpos;
4781   struct NeighbourList *npos;
4782   struct NeighbourList *nprev;
4783   struct MessageQueue *mq;
4784   struct ForeignAddressList *peer_addresses;
4785   struct ForeignAddressList *peer_pos;
4786
4787   if (GNUNET_YES == check)
4788     {
4789       rpos = n->plugins;
4790       while (NULL != rpos)
4791         {
4792           peer_addresses = rpos->addresses;
4793           while (peer_addresses != NULL)
4794             {
4795               // Do not disconnect if: an address is connected or an inbound address exists
4796               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4797                 {
4798 #if DEBUG_TRANSPORT
4799                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4800                               "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4801                               GNUNET_i2s (&n->id),
4802                               a2s (peer_addresses->ready_list->plugin->short_name,
4803                                    peer_addresses->addr,
4804                                    peer_addresses->addrlen));
4805 #endif
4806                   return;             /* still connected */
4807                 }
4808               peer_addresses = peer_addresses->next;
4809             }
4810           rpos = rpos->next;
4811         }
4812     }
4813 #if DEBUG_TRANSPORT
4814   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4815               "Disconnecting from `%4s'\n",
4816               GNUNET_i2s (&n->id));
4817 #endif
4818
4819   /* remove n from neighbours list */
4820   nprev = NULL;
4821   npos = neighbours;
4822   while ((npos != NULL) && (npos != n))
4823     {
4824       nprev = npos;
4825       npos = npos->next;
4826     }
4827   GNUNET_assert (npos != NULL);
4828   if (nprev == NULL)
4829     neighbours = n->next;
4830   else
4831     nprev->next = n->next;
4832
4833   /* notify all clients about disconnect */
4834   if (GNUNET_YES == n->received_pong)
4835     notify_clients_disconnect (&n->id);
4836
4837   ats_modify_problem_state(ats, ATS_MODIFIED);
4838
4839   /* clean up all plugins, cancel connections and pending transmissions */
4840   while (NULL != (rpos = n->plugins))
4841     {
4842       n->plugins = rpos->next;
4843       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4844       while (rpos->addresses != NULL)
4845         {
4846           peer_pos = rpos->addresses;
4847           rpos->addresses = peer_pos->next;
4848           if (peer_pos->connected == GNUNET_YES)
4849             GNUNET_STATISTICS_update (stats,
4850                                       gettext_noop ("# connected addresses"),
4851                                       -1,
4852                                       GNUNET_NO);
4853           if (GNUNET_YES == peer_pos->validated)
4854             GNUNET_STATISTICS_update (stats,
4855                                       gettext_noop ("# peer addresses considered valid"),
4856                                       -1,
4857                                       GNUNET_NO);
4858           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4859             {
4860               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4861               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4862             }
4863           GNUNET_free(peer_pos->ressources);
4864           peer_pos->ressources = NULL;
4865           GNUNET_free(peer_pos->quality);
4866           peer_pos->ressources = NULL;
4867           GNUNET_free(peer_pos);
4868         }
4869       GNUNET_free (rpos);
4870     }
4871
4872   /* free all messages on the queue */
4873   while (NULL != (mq = n->messages_head))
4874     {
4875       GNUNET_STATISTICS_update (stats,
4876                                 gettext_noop ("# bytes in message queue for other peers"),
4877                                 - (int64_t) mq->message_buf_size,
4878                                 GNUNET_NO);
4879       GNUNET_STATISTICS_update (stats,
4880                                 gettext_noop ("# bytes discarded due to disconnect"),
4881                                 mq->message_buf_size,
4882                                 GNUNET_NO);
4883       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4884                                    n->messages_tail,
4885                                    mq);
4886       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4887                                  &n->id,
4888                                  sizeof(struct GNUNET_PeerIdentity)));
4889       GNUNET_free (mq);
4890     }
4891
4892   while (NULL != (mq = n->cont_head))
4893     {
4894
4895       GNUNET_CONTAINER_DLL_remove (n->cont_head,
4896                                    n->cont_tail,
4897                                    mq);
4898       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4899                                  &n->id,
4900                                  sizeof(struct GNUNET_PeerIdentity)));
4901       GNUNET_free (mq);
4902     }
4903
4904   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4905     {
4906       GNUNET_SCHEDULER_cancel (n->timeout_task);
4907       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4908     }
4909   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4910     {
4911       GNUNET_SCHEDULER_cancel (n->retry_task);
4912       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4913     }
4914   if (n->piter != NULL)
4915     {
4916       GNUNET_PEERINFO_iterate_cancel (n->piter);
4917       GNUNET_STATISTICS_update (stats,
4918                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4919                                 -1,
4920                                 GNUNET_NO);
4921       n->piter = NULL;
4922     }
4923   /* finally, free n itself */
4924   GNUNET_STATISTICS_update (stats,
4925                             gettext_noop ("# active neighbours"),
4926                             -1,
4927                             GNUNET_NO);
4928   GNUNET_free_non_null (n->pre_connect_message_buffer);
4929   GNUNET_free (n);
4930 }
4931
4932
4933 /**
4934  * We have received a PING message from someone.  Need to send a PONG message
4935  * in response to the peer by any means necessary.
4936  */
4937 static int
4938 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4939              const struct GNUNET_PeerIdentity *peer,
4940              struct Session *session,
4941              const char *sender_address,
4942              uint16_t sender_address_len)
4943 {
4944   struct TransportPlugin *plugin = cls;
4945   struct SessionHeader *session_header = (struct SessionHeader*) session;
4946   struct TransportPingMessage *ping;
4947   struct TransportPongMessage *pong;
4948   struct NeighbourList *n;
4949   struct ReadyList *rl;
4950   struct ForeignAddressList *fal;
4951   struct OwnAddressList *oal;
4952   const char *addr;
4953   size_t alen;
4954   size_t slen;
4955   int did_pong;
4956
4957   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4958     {
4959       GNUNET_break_op (0);
4960       return GNUNET_SYSERR;
4961     }
4962
4963   ping = (struct TransportPingMessage *) message;
4964   if (0 != memcmp (&ping->target,
4965                    plugin->env.my_identity,
4966                    sizeof (struct GNUNET_PeerIdentity)))
4967     {
4968 #if DEBUG_TRANSPORT
4969       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4970                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4971                   "PING",
4972                   (sender_address != NULL)
4973                   ? a2s (plugin->short_name,
4974                          (const struct sockaddr *)sender_address,
4975                          sender_address_len)
4976                   : "<inbound>",
4977                   GNUNET_i2s (&ping->target));
4978 #endif
4979       return GNUNET_SYSERR;
4980     }
4981 #if DEBUG_PING_PONG
4982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4983               "Processing `%s' from `%s'\n",
4984               "PING",
4985               (sender_address != NULL)
4986               ? a2s (plugin->short_name,
4987                      (const struct sockaddr *)sender_address,
4988                      sender_address_len)
4989               : "<inbound>");
4990 #endif
4991   GNUNET_STATISTICS_update (stats,
4992                             gettext_noop ("# PING messages received"),
4993                             1,
4994                             GNUNET_NO);
4995   addr = (const char*) &ping[1];
4996   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4997   slen = strlen (plugin->short_name) + 1;
4998   if (alen == 0)
4999     {
5000       /* peer wants to confirm that we have an outbound connection to him */
5001       if (session == NULL)
5002         {
5003           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5004                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5005                       GNUNET_i2s (peer));
5006           return GNUNET_SYSERR;
5007         }
5008       /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5009         1) it is NULL when we need to have a real value
5010         2) it is documented to be the address of the sender (source-IP), where
5011         what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5012         have...
5013       */
5014       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5015                   "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5016                   a2s (plugin->short_name,
5017                        sender_address,
5018                        sender_address_len),                    
5019                   GNUNET_i2s (peer));
5020
5021       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5022       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5023       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5024       pong->purpose.size =
5025         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5026                sizeof (uint32_t) +
5027                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5028                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5029       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5030       pong->challenge = ping->challenge;
5031       pong->addrlen = htonl(sender_address_len + slen);
5032       memcpy(&pong->pid,
5033              peer,
5034              sizeof(struct GNUNET_PeerIdentity));
5035       memcpy (&pong[1],
5036               plugin->short_name,
5037               slen);
5038       if ((sender_address!=NULL) && (sender_address_len > 0))
5039                   memcpy (&((char*)&pong[1])[slen],
5040                           sender_address,
5041                           sender_address_len);
5042       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5043         {
5044           /* create / update cached sig */
5045 #if DEBUG_TRANSPORT
5046           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5047                       "Creating PONG signature to indicate active connection.\n");
5048 #endif
5049           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5050           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5051           GNUNET_assert (GNUNET_OK ==
5052                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5053                                                  &pong->purpose,
5054                                                  &session_header->pong_signature));
5055         }
5056       else
5057         {
5058           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5059         }
5060       memcpy (&pong->signature,
5061               &session_header->pong_signature,
5062               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5063
5064
5065     }
5066   else
5067     {
5068       /* peer wants to confirm that this is one of our addresses */
5069       addr += slen;
5070       alen -= slen;
5071       if (GNUNET_OK !=
5072           plugin->api->check_address (plugin->api->cls,
5073                                       addr,
5074                                       alen))
5075         {
5076           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5077                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5078                       a2s (plugin->short_name,
5079                            addr,
5080                            alen));
5081           return GNUNET_NO;
5082         }
5083       oal = plugin->addresses;
5084       while (NULL != oal)
5085         {
5086           if ( (oal->addrlen == alen) &&
5087                (0 == memcmp (addr,
5088                              &oal[1],
5089                              alen)) )
5090             break;
5091           oal = oal->next;
5092         }
5093       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5094       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5095       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5096       pong->purpose.size =
5097         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5098                sizeof (uint32_t) +
5099                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5100                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5101       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5102       pong->challenge = ping->challenge;
5103       pong->addrlen = htonl(alen + slen);
5104       memcpy(&pong->pid,
5105              &my_identity,
5106              sizeof(struct GNUNET_PeerIdentity));
5107       memcpy (&pong[1], plugin->short_name, slen);
5108       memcpy (&((char*)&pong[1])[slen], addr, alen);
5109       if ( (oal != NULL) &&
5110            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5111         {
5112           /* create / update cached sig */
5113 #if DEBUG_TRANSPORT
5114           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5115                       "Creating PONG signature to indicate ownership.\n");
5116 #endif
5117           oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5118           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5119           GNUNET_assert (GNUNET_OK ==
5120                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5121                                                  &pong->purpose,
5122                                                  &oal->pong_signature));
5123           memcpy (&pong->signature,
5124                   &oal->pong_signature,
5125                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5126         }
5127       else if (oal == NULL)
5128         {
5129           /* not using cache (typically DV-only) */
5130           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5131           GNUNET_assert (GNUNET_OK ==
5132                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5133                                                  &pong->purpose,
5134                                                  &pong->signature));
5135         }
5136       else
5137         {
5138           /* can used cached version */
5139           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5140           memcpy (&pong->signature,
5141                   &oal->pong_signature,
5142                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5143         }
5144     }
5145   n = find_neighbour(peer);
5146   GNUNET_assert (n != NULL);
5147   did_pong = GNUNET_NO;
5148   /* first try reliable response transmission */
5149   rl = n->plugins;
5150   while (rl != NULL)
5151     {
5152       fal = rl->addresses;
5153       while (fal != NULL)
5154         {
5155           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5156                                            peer,
5157                                            (const char*) pong,
5158                                            ntohs (pong->header.size),
5159                                            TRANSPORT_PONG_PRIORITY,
5160                                            HELLO_VERIFICATION_TIMEOUT,
5161                                            fal->session,
5162                                            fal->addr,
5163                                            fal->addrlen,
5164                                            GNUNET_SYSERR,
5165                                            NULL, NULL))
5166             {
5167               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5168                           "Transmitted PONG to `%s' via reliable mechanism\n",
5169                           GNUNET_i2s (peer));
5170               /* done! */
5171               GNUNET_STATISTICS_update (stats,
5172                                         gettext_noop ("# PONGs unicast via reliable transport"),
5173                                         1,
5174                                         GNUNET_NO);
5175               GNUNET_free (pong);
5176               return GNUNET_OK;
5177             }
5178           did_pong = GNUNET_YES;
5179           fal = fal->next;
5180         }
5181       rl = rl->next;
5182     }
5183   /* no reliable method found, do multicast */
5184   GNUNET_STATISTICS_update (stats,
5185                             gettext_noop ("# PONGs multicast to all available addresses"),
5186                             1,
5187                             GNUNET_NO);
5188   rl = n->plugins;
5189   while (rl != NULL)
5190     {
5191       fal = rl->addresses;
5192       while (fal != NULL)
5193         {
5194           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5195                       "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5196                       GNUNET_i2s (peer),
5197                       a2s (rl->plugin->short_name,
5198                            fal->addr,
5199                            fal->addrlen),
5200                       rl->plugin->short_name);
5201           transmit_to_peer(NULL, fal,
5202                            TRANSPORT_PONG_PRIORITY,
5203                            HELLO_VERIFICATION_TIMEOUT,
5204                            (const char *)pong,
5205                            ntohs(pong->header.size),
5206                            GNUNET_YES,
5207                            n);
5208           did_pong = GNUNET_YES;
5209           fal = fal->next;
5210         }
5211       rl = rl->next;
5212     }
5213   GNUNET_free(pong);
5214   if (GNUNET_YES != did_pong)
5215     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5216                 _("Could not send PONG to `%s': no address available\n"),
5217                 GNUNET_i2s (peer));
5218   return GNUNET_OK;
5219 }
5220
5221
5222 /**
5223  * Function called by the plugin for each received message.  Update
5224  * data volumes, possibly notify plugins about reducing the rate at
5225  * which they read from the socket and generally forward to our
5226  * receive callback.
5227  *
5228  * @param cls the "struct TransportPlugin *" we gave to the plugin
5229  * @param peer (claimed) identity of the other peer
5230  * @param message the message, NULL if we only care about
5231  *                learning about the delay until we should receive again
5232  * @param ats_data information for automatic transport selection
5233  * @param ats_count number of elements in ats not including 0-terminator
5234  * @param session identifier used for this session (can be NULL)
5235  * @param sender_address binary address of the sender (if observed)
5236  * @param sender_address_len number of bytes in sender_address
5237  * @return how long in ms the plugin should wait until receiving more data
5238  *         (plugins that do not support this, can ignore the return value)
5239  */
5240 static struct GNUNET_TIME_Relative
5241 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5242                     const struct GNUNET_MessageHeader *message,
5243                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5244                     uint32_t ats_count,
5245                     struct Session *session,
5246                     const char *sender_address,
5247                     uint16_t sender_address_len)
5248 {
5249   struct TransportPlugin *plugin = cls;
5250   struct ReadyList *service_context;
5251   struct ForeignAddressList *peer_address;
5252   uint16_t msize;
5253   struct NeighbourList *n;
5254   struct GNUNET_TIME_Relative ret;
5255   uint32_t distance;
5256   int c;
5257
5258   if (0 == memcmp (peer,
5259                    &my_identity,
5260                    sizeof (struct GNUNET_PeerIdentity)))
5261     {
5262       /* refuse to receive from myself */
5263       GNUNET_break (0); 
5264       return GNUNET_TIME_UNIT_FOREVER_REL;
5265     }
5266   if (is_blacklisted (peer, plugin))
5267     return GNUNET_TIME_UNIT_FOREVER_REL;
5268   n = find_neighbour (peer);
5269   if (n == NULL)
5270     n = setup_new_neighbour (peer, GNUNET_YES);
5271   service_context = n->plugins;
5272   while ((service_context != NULL) && (plugin != service_context->plugin))
5273     service_context = service_context->next;
5274   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5275   peer_address = NULL;
5276   distance = 1;
5277
5278   for (c=0; c<ats_count; c++)
5279     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5280       distance = ntohl(ats_data[c].value);
5281
5282
5283   if (message != NULL)
5284     {
5285       if ( (session != NULL) ||
5286            (sender_address != NULL) )
5287         peer_address = add_peer_address (n,
5288                                          plugin->short_name,
5289                                          session,
5290                                          sender_address,
5291                                          sender_address_len);
5292       if (peer_address != NULL)
5293         {
5294           update_addr_ats(peer_address, ats_data, ats_count);
5295           update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5296           
5297           peer_address->distance = distance;
5298           if (GNUNET_YES == peer_address->validated)
5299             mark_address_connected (peer_address);
5300           peer_address->timeout
5301             = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5302           schedule_next_ping (peer_address);
5303         }
5304       /* update traffic received amount ... */
5305       msize = ntohs (message->size);
5306
5307       GNUNET_STATISTICS_update (stats,
5308                                 gettext_noop ("# bytes received from other peers"),
5309                                 msize,
5310                                 GNUNET_NO);
5311       n->distance = distance;
5312       n->peer_timeout =
5313         GNUNET_TIME_relative_to_absolute
5314         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5315       GNUNET_SCHEDULER_cancel (n->timeout_task);
5316       n->timeout_task =
5317         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5318                                       &neighbour_timeout_task, n);
5319       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5320         {
5321           /* dropping message due to frequent inbound volume violations! */
5322           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5323                       GNUNET_ERROR_TYPE_BULK,
5324                       _
5325                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5326                       n->in_tracker.available_bytes_per_s__,
5327                       n->quota_violation_count);
5328           GNUNET_STATISTICS_update (stats,
5329                                     gettext_noop ("# bandwidth quota violations by other peers"),
5330                                     1,
5331                                     GNUNET_NO);
5332           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5333         }
5334     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5335         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5336       {
5337         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5338         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5339         /* Force ressource and quality update */
5340         if ((value == 4) && (ats != NULL))
5341             ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5342         /* Force cost update */
5343         if ((value == 3) && (ats != NULL))
5344           ats_modify_problem_state(ats, ATS_COST_UPDATED);
5345         /* Force quality update */
5346         if ((value == 2) && (ats != NULL))
5347           ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5348         /* Force full rebuild */
5349         if ((value == 1) && (ats != NULL))
5350           ats_modify_problem_state(ats, ATS_MODIFIED);
5351       }
5352     
5353 #if DEBUG_PING_PONG
5354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5355                 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5356                 ntohs (message->type),
5357                 ntohs (message->size),
5358                 GNUNET_i2s (peer));
5359 #endif
5360       switch (ntohs (message->type))
5361         {
5362         case GNUNET_MESSAGE_TYPE_HELLO:
5363           GNUNET_STATISTICS_update (stats,
5364                                     gettext_noop ("# HELLO messages received from other peers"),
5365                                     1,
5366                                     GNUNET_NO);
5367           process_hello (plugin, message);
5368           break;
5369         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5370           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5371           if (! n->received_pong)
5372             transmit_plain_ping (n);
5373           break;
5374         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5375           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5376           break;
5377         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5378           break;
5379         default:
5380           handle_payload_message (message, n);
5381           break;
5382         }
5383     }
5384   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5385   if (ret.rel_value > 0)
5386     {
5387 #if DEBUG_TRANSPORT 
5388       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5389                   "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5390                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5391                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5392                   (unsigned long long) ret.rel_value);
5393 #endif
5394       GNUNET_STATISTICS_update (stats,
5395                                 gettext_noop ("# ms throttling suggested"),
5396                                 (int64_t) ret.rel_value,
5397                                 GNUNET_NO);
5398     }
5399   return ret;
5400 }
5401
5402 /**
5403  * Handle START-message.  This is the first message sent to us
5404  * by any client which causes us to add it to our list.
5405  *
5406  * @param cls closure (always NULL)
5407  * @param client identification of the client
5408  * @param message the actual message
5409  */
5410 static void
5411 handle_start (void *cls,
5412               struct GNUNET_SERVER_Client *client,
5413               const struct GNUNET_MessageHeader *message)
5414 {
5415   const struct StartMessage *start;
5416   struct TransportClient *c;
5417   struct ConnectInfoMessage * cim;
5418   struct NeighbourList *n;
5419   uint32_t ats_count;
5420   size_t size;
5421
5422   start = (const struct StartMessage*) message;
5423 #if DEBUG_TRANSPORT
5424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5425               "Received `%s' request from client\n", "START");
5426 #endif
5427   c = clients;
5428   while (c != NULL)
5429     {
5430       if (c->client == client)
5431         {
5432           /* client already on our list! */
5433           GNUNET_break (0);
5434           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5435           return;
5436         }
5437       c = c->next;
5438     }
5439   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5440        (0 != memcmp (&start->self,
5441                      &my_identity,
5442                      sizeof (struct GNUNET_PeerIdentity))) )
5443     {
5444       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5445                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5446                   GNUNET_i2s (&start->self));
5447       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5448       return;
5449     }
5450   c = GNUNET_malloc (sizeof (struct TransportClient));
5451   c->next = clients;
5452   clients = c;
5453   c->client = client;
5454   if (our_hello != NULL)
5455     {
5456 #if DEBUG_TRANSPORT
5457       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5458                   "Sending our own `%s' to new client\n", "HELLO");
5459 #endif
5460       transmit_to_client (c,
5461                           (const struct GNUNET_MessageHeader *) our_hello,
5462                           GNUNET_NO);
5463       /* tell new client about all existing connections */
5464       ats_count = 2;
5465       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5466       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5467         {
5468           GNUNET_break(0);
5469         }
5470       cim = GNUNET_malloc (size);
5471       cim->header.size = htons (size);
5472       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5473       cim->ats_count = htonl(ats_count);
5474       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5475       (&(cim->ats))[2].value = htonl (0);
5476       n = neighbours;
5477       while (n != NULL)
5478         {
5479           if (GNUNET_YES == n->received_pong)
5480             {
5481               (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5482               (&(cim->ats))[0].value = htonl (n->distance);
5483               (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5484               (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5485               cim->id = n->id;
5486               transmit_to_client (c, &cim->header, GNUNET_NO);
5487             }
5488           n = n->next;
5489         }
5490       GNUNET_free (cim);
5491     }
5492   else
5493     {
5494 #if DEBUG_TRANSPORT_HELLO
5495       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5496                   "No HELLO created yet, will transmit HELLO to client later!\n");
5497 #endif
5498       refresh_hello ();
5499     }
5500   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5501 }
5502
5503
5504 /**
5505  * Handle HELLO-message.
5506  *
5507  * @param cls closure (always NULL)
5508  * @param client identification of the client
5509  * @param message the actual message
5510  */
5511 static void
5512 handle_hello (void *cls,
5513               struct GNUNET_SERVER_Client *client,
5514               const struct GNUNET_MessageHeader *message)
5515 {
5516   int ret;
5517
5518   GNUNET_STATISTICS_update (stats,
5519                             gettext_noop ("# HELLOs received from clients"),
5520                             1,
5521                             GNUNET_NO);
5522   ret = process_hello (NULL, message);
5523   GNUNET_SERVER_receive_done (client, ret);
5524 }
5525
5526
5527 /**
5528  * Closure for 'transmit_client_message'; followed by
5529  * 'msize' bytes of the actual message.
5530  */
5531 struct TransmitClientMessageContext
5532 {
5533   /**
5534    * Client on whom's behalf we are sending.
5535    */
5536   struct GNUNET_SERVER_Client *client;
5537
5538   /**
5539    * Timeout for the transmission.
5540    */
5541   struct GNUNET_TIME_Absolute timeout;
5542
5543   /**
5544    * Message priority.
5545    */
5546   uint32_t priority;
5547
5548   /**
5549    * Size of the message in bytes.
5550    */
5551   uint16_t msize;
5552 };
5553
5554
5555 /**
5556  * Schedule transmission of a message we got from a client to a peer.
5557  *
5558  * @param cls the 'struct TransmitClientMessageContext*'
5559  * @param n destination, or NULL on error (in that case, drop the message)
5560  */
5561 static void
5562 transmit_client_message (void *cls,
5563                          struct NeighbourList *n)
5564 {
5565   struct TransmitClientMessageContext *tcmc = cls;
5566   struct TransportClient *tc;
5567
5568   tc = clients;
5569   while ((tc != NULL) && (tc->client != tcmc->client))
5570     tc = tc->next;
5571
5572   if (n != NULL)
5573     {
5574       transmit_to_peer (tc, NULL, tcmc->priority,
5575                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5576                         (char *)&tcmc[1],
5577                         tcmc->msize, GNUNET_NO, n);
5578     }
5579   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5580   GNUNET_SERVER_client_drop (tcmc->client);
5581   GNUNET_free (tcmc);
5582 }
5583
5584
5585 /**
5586  * Handle SEND-message.
5587  *
5588  * @param cls closure (always NULL)
5589  * @param client identification of the client
5590  * @param message the actual message
5591  */
5592 static void
5593 handle_send (void *cls,
5594              struct GNUNET_SERVER_Client *client,
5595              const struct GNUNET_MessageHeader *message)
5596 {
5597   const struct OutboundMessage *obm;
5598   const struct GNUNET_MessageHeader *obmm;
5599   struct TransmitClientMessageContext *tcmc;
5600   uint16_t size;
5601   uint16_t msize;
5602
5603   size = ntohs (message->size);
5604   if (size <
5605       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5606     {
5607       GNUNET_break (0);
5608       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5609       return;
5610     }
5611   GNUNET_STATISTICS_update (stats,
5612                             gettext_noop ("# payload received for other peers"),
5613                             size,
5614                             GNUNET_NO);
5615   obm = (const struct OutboundMessage *) message;
5616   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5617   msize = size - sizeof (struct OutboundMessage);
5618 #if DEBUG_TRANSPORT
5619   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5620               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5621               "SEND", GNUNET_i2s (&obm->peer),
5622               ntohs (obmm->type),
5623               msize);
5624 #endif
5625   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5626   tcmc->client = client;
5627   tcmc->priority = ntohl (obm->priority);
5628   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5629   tcmc->msize = msize;
5630   /* FIXME: this memcpy can be up to 7% of our total runtime */
5631   memcpy (&tcmc[1], obmm, msize);
5632   GNUNET_SERVER_client_keep (client);
5633   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5634                               &transmit_client_message,
5635                               tcmc);
5636 }
5637
5638
5639 /**
5640  * Handle request connect message
5641  *
5642  * @param cls closure (always NULL)
5643  * @param client identification of the client
5644  * @param message the actual message
5645  */
5646 static void
5647 handle_request_connect (void *cls,
5648                         struct GNUNET_SERVER_Client *client,
5649                         const struct GNUNET_MessageHeader *message)
5650 {
5651   const struct TransportRequestConnectMessage *trcm =
5652     (const struct TransportRequestConnectMessage *) message;
5653
5654   GNUNET_STATISTICS_update (stats,
5655                             gettext_noop ("# REQUEST CONNECT messages received"),
5656                             1,
5657                             GNUNET_NO);
5658 #if DEBUG_TRANSPORT
5659   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
5660              "Received a request connect message for peer `%s'\n", 
5661              GNUNET_i2s(&trcm->peer));
5662 #endif
5663   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5664                               NULL, NULL);
5665   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5666 }
5667
5668
5669 /**
5670  * Handle SET_QUOTA-message.
5671  *
5672  * @param cls closure (always NULL)
5673  * @param client identification of the client
5674  * @param message the actual message
5675  */
5676 static void
5677 handle_set_quota (void *cls,
5678                   struct GNUNET_SERVER_Client *client,
5679                   const struct GNUNET_MessageHeader *message)
5680 {
5681   const struct QuotaSetMessage *qsm =
5682     (const struct QuotaSetMessage *) message;
5683   struct NeighbourList *n;
5684
5685   GNUNET_STATISTICS_update (stats,
5686                             gettext_noop ("# SET QUOTA messages received"),
5687                             1,
5688                             GNUNET_NO);
5689   n = find_neighbour (&qsm->peer);
5690   if (n == NULL)
5691     {
5692       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5693       GNUNET_STATISTICS_update (stats,
5694                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5695                                 1,
5696                                 GNUNET_NO);
5697       return;
5698     }
5699 #if DEBUG_TRANSPORT 
5700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5701               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5702               "SET_QUOTA",
5703               (unsigned int) ntohl (qsm->quota.value__),
5704               (unsigned int) n->in_tracker.available_bytes_per_s__,
5705               GNUNET_i2s (&qsm->peer));
5706 #endif
5707   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5708                                          qsm->quota);
5709   if (0 == ntohl (qsm->quota.value__))
5710     {
5711 #if DEBUG_TRANSPORT
5712       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5713                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5714                 "SET_QUOTA");
5715 #endif
5716       GNUNET_STATISTICS_update (stats,
5717                                 gettext_noop ("# disconnects due to quota of 0"),
5718                                 1,
5719                                 GNUNET_NO);
5720       disconnect_neighbour (n, GNUNET_NO);
5721     }
5722   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5723 }
5724
5725
5726 /**
5727  * Take the given address and append it to the set of results sent back to
5728  * the client.
5729  *
5730  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5731  * @param address the resolved name, NULL to indicate the last response
5732  */
5733 static void
5734 transmit_address_to_client (void *cls, const char *address)
5735 {
5736   struct GNUNET_SERVER_TransmitContext *tc = cls;
5737   size_t slen;
5738
5739   if (NULL != address)
5740     {
5741       slen = strlen (address) + 1;
5742       GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5743                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5744     }
5745   else
5746     {
5747       GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5748     }
5749 }
5750
5751
5752 /**
5753  * Handle AddressLookup-message.
5754  *
5755  * @param cls closure (always NULL)
5756  * @param client identification of the client
5757  * @param message the actual message
5758  */
5759 static void
5760 handle_address_lookup (void *cls,
5761                        struct GNUNET_SERVER_Client *client,
5762                        const struct GNUNET_MessageHeader *message)
5763 {
5764   const struct AddressLookupMessage *alum;
5765   struct TransportPlugin *lsPlugin;
5766   const char *nameTransport;
5767   const char *address;
5768   uint16_t size;
5769   struct GNUNET_SERVER_TransmitContext *tc;
5770   struct GNUNET_TIME_Absolute timeout;
5771   struct GNUNET_TIME_Relative rtimeout;
5772   int32_t numeric;
5773
5774   size = ntohs (message->size);
5775   if (size < sizeof (struct AddressLookupMessage))
5776     {
5777       GNUNET_break_op (0);
5778       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5779       return;
5780     }
5781   alum = (const struct AddressLookupMessage *) message;
5782   uint32_t addressLen = ntohl (alum->addrlen);
5783   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5784     {
5785       GNUNET_break_op (0);
5786       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5787       return;
5788     }
5789   address = (const char *) &alum[1];
5790   nameTransport = (const char *) &address[addressLen];
5791   if (nameTransport
5792       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5793     {
5794       GNUNET_break_op (0);
5795       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5796       return;
5797     }
5798   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5799   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5800   numeric = ntohl (alum->numeric_only);
5801   lsPlugin = find_transport (nameTransport);
5802   if (NULL == lsPlugin)
5803     {
5804       tc = GNUNET_SERVER_transmit_context_create (client);
5805       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5806                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5807       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5808       return;
5809     }
5810   GNUNET_SERVER_disable_receive_done_warning (client);
5811   tc = GNUNET_SERVER_transmit_context_create (client);
5812   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5813                                          nameTransport,
5814                                          address, addressLen,
5815                                          numeric,
5816                                          rtimeout,
5817                                          &transmit_address_to_client, tc);
5818 }
5819
5820 /**
5821  * Handle PeerAddressLookupMessage.
5822  *
5823  * @param cls closure (always NULL)
5824  * @param client identification of the client
5825  * @param message the actual message
5826  */
5827 static void
5828 handle_peer_address_lookup (void *cls,
5829                        struct GNUNET_SERVER_Client *client,
5830                        const struct GNUNET_MessageHeader *message)
5831 {
5832   const struct PeerAddressLookupMessage *peer_address_lookup;
5833   struct NeighbourList *neighbor_iterator;
5834   struct ReadyList *ready_iterator;
5835   struct ForeignAddressList *foreign_address_iterator;
5836   struct TransportPlugin *transport_plugin;
5837
5838   uint16_t size;
5839   struct GNUNET_SERVER_TransmitContext *tc;
5840   struct GNUNET_TIME_Absolute timeout;
5841   struct GNUNET_TIME_Relative rtimeout;
5842   char *addr_buf;
5843
5844   size = ntohs (message->size);
5845   if (size < sizeof (struct PeerAddressLookupMessage))
5846     {
5847       GNUNET_break_op (0);
5848       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5849       return;
5850     }
5851   peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5852
5853   timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5854   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5855
5856   neighbor_iterator = neighbours;
5857   while (neighbor_iterator != NULL)
5858     {
5859       if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5860         break;
5861       neighbor_iterator = neighbor_iterator->next;
5862     }
5863
5864   /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5865   if (neighbor_iterator == NULL)
5866     {
5867       GNUNET_break(0);
5868       tc = GNUNET_SERVER_transmit_context_create (client);
5869       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5870                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5871       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5872       return;
5873     }
5874
5875   ready_iterator = neighbor_iterator->plugins;
5876   GNUNET_SERVER_disable_receive_done_warning (client);
5877   tc = GNUNET_SERVER_transmit_context_create (client);
5878   while(ready_iterator != NULL)
5879     {
5880       foreign_address_iterator = ready_iterator->addresses;
5881       while (foreign_address_iterator != NULL)
5882         {
5883           transport_plugin = foreign_address_iterator->ready_list->plugin;
5884           if (foreign_address_iterator->addr != NULL)
5885             {
5886               GNUNET_asprintf (&addr_buf, "%s --- %s",
5887                                a2s (transport_plugin->short_name,
5888                                     foreign_address_iterator->addr,
5889                                     foreign_address_iterator->addrlen),
5890                                (foreign_address_iterator->connected
5891                                    == GNUNET_YES) ? "CONNECTED"
5892                                    : "DISCONNECTED");
5893               transmit_address_to_client(tc, addr_buf);
5894               GNUNET_free(addr_buf);
5895             }
5896           else if (foreign_address_iterator->addrlen == 0)
5897             {
5898               GNUNET_asprintf (&addr_buf, "%s --- %s", "<inbound>",
5899                                (foreign_address_iterator->connected
5900                                    == GNUNET_YES) ? "CONNECTED"
5901                                    : "DISCONNECTED");
5902               transmit_address_to_client (tc, addr_buf);
5903               GNUNET_free(addr_buf);
5904             }
5905
5906           foreign_address_iterator = foreign_address_iterator->next;
5907         }
5908       ready_iterator = ready_iterator->next;
5909     }
5910   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5911                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5912   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5913 }
5914
5915 /**
5916  * Handle AddressIterateMessage
5917  *
5918  * @param cls closure (always NULL)
5919  * @param client identification of the client
5920  * @param message the actual message
5921  */
5922 static void
5923 handle_address_iterate (void *cls,
5924                         struct GNUNET_SERVER_Client *client,
5925                         const struct GNUNET_MessageHeader *message)
5926 {
5927   const struct AddressIterateMessage *address_iterate;
5928   struct NeighbourList *neighbor_iterator;
5929   struct ReadyList *ready_iterator;
5930   struct ForeignAddressList *foreign_address_iterator;
5931   struct TransportPlugin *transport_plugin;
5932
5933   uint16_t size;
5934   struct GNUNET_SERVER_TransmitContext *tc;
5935   struct GNUNET_TIME_Absolute timeout;
5936   struct GNUNET_TIME_Relative rtimeout;
5937   char *addr_buf;
5938
5939   size = ntohs (message->size);
5940   if (size < sizeof (struct AddressIterateMessage))
5941     {
5942       GNUNET_break_op (0);
5943       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5944       return;
5945     }
5946   address_iterate = (const struct AddressIterateMessage *) message;
5947
5948   timeout = GNUNET_TIME_absolute_ntoh (address_iterate->timeout);
5949   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5950
5951   GNUNET_SERVER_disable_receive_done_warning (client);
5952   tc = GNUNET_SERVER_transmit_context_create (client);
5953
5954   neighbor_iterator = neighbours;
5955   while (neighbor_iterator != NULL)
5956     {
5957       ready_iterator = neighbor_iterator->plugins;
5958       while (ready_iterator != NULL)
5959         {
5960           foreign_address_iterator = ready_iterator->addresses;
5961           while (foreign_address_iterator != NULL)
5962             {
5963               transport_plugin = foreign_address_iterator->ready_list->plugin;
5964               if (foreign_address_iterator->addr != NULL)
5965                 {
5966                   GNUNET_asprintf (&addr_buf, "%s:%s --- %s",
5967                                    GNUNET_i2s(&neighbor_iterator->id),
5968                                    a2s (transport_plugin->short_name,
5969                                         foreign_address_iterator->addr,
5970                                         foreign_address_iterator->addrlen),
5971                                    (foreign_address_iterator->connected
5972                                        == GNUNET_YES) ? "CONNECTED"
5973                                        : "DISCONNECTED");
5974                   transmit_address_to_client (tc, addr_buf);
5975                   GNUNET_free(addr_buf);
5976                 }
5977               else if (foreign_address_iterator->addrlen == 0)
5978                 {
5979                   GNUNET_asprintf (&addr_buf, "%s:%s --- %s",
5980                                      GNUNET_i2s (&neighbor_iterator->id),
5981                                      "<inbound>",
5982                                      (foreign_address_iterator->connected
5983                                          == GNUNET_YES) ? "CONNECTED"
5984                                          : "DISCONNECTED");
5985                   transmit_address_to_client (tc, addr_buf);
5986                   GNUNET_free(addr_buf);
5987                 }
5988
5989               foreign_address_iterator = foreign_address_iterator->next;
5990             }
5991           ready_iterator = ready_iterator->next;
5992         }
5993       neighbor_iterator = neighbor_iterator->next;
5994     }
5995
5996   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5997                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5998   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5999 }
6000
6001
6002 /**
6003  * Setup the environment for this plugin.
6004  */
6005 static void
6006 create_environment (struct TransportPlugin *plug)
6007 {
6008   plug->env.cfg = cfg;
6009   plug->env.my_identity = &my_identity;
6010   plug->env.our_hello = &our_hello;
6011   plug->env.cls = plug;
6012   plug->env.receive = &plugin_env_receive;
6013   plug->env.notify_address = &plugin_env_notify_address;
6014   plug->env.session_end = &plugin_env_session_end;
6015   plug->env.max_connections = max_connect_per_transport;
6016   plug->env.stats = stats;
6017 }
6018
6019
6020 /**
6021  * Start the specified transport (load the plugin).
6022  */
6023 static void
6024 start_transport (struct GNUNET_SERVER_Handle *server,
6025                  const char *name)
6026 {
6027   struct TransportPlugin *plug;
6028   char *libname;
6029
6030   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6031               _("Loading `%s' transport plugin\n"), name);
6032   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6033   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6034   create_environment (plug);
6035   plug->short_name = GNUNET_strdup (name);
6036   plug->lib_name = libname;
6037   plug->next = plugins;
6038   plugins = plug;
6039   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6040   if (plug->api == NULL)
6041     {
6042       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6043                   _("Failed to load transport plugin for `%s'\n"), name);
6044       GNUNET_free (plug->short_name);
6045       plugins = plug->next;
6046       GNUNET_free (libname);
6047       GNUNET_free (plug);
6048     }
6049 }
6050
6051
6052 /**
6053  * Called whenever a client is disconnected.  Frees our
6054  * resources associated with that client.
6055  *
6056  * @param cls closure
6057  * @param client identification of the client
6058  */
6059 static void
6060 client_disconnect_notification (void *cls,
6061                                 struct GNUNET_SERVER_Client *client)
6062 {
6063   struct TransportClient *pos;
6064   struct TransportClient *prev;
6065   struct ClientMessageQueueEntry *mqe;
6066   struct Blacklisters *bl;
6067   struct BlacklistCheck *bc;
6068
6069   if (client == NULL)
6070     return;
6071 #if DEBUG_TRANSPORT
6072   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6073               "Client disconnected, cleaning up.\n");
6074 #endif
6075   /* clean up blacklister */
6076   bl = bl_head;
6077   while (bl != NULL)
6078     {
6079       if (bl->client == client)
6080         {
6081           bc = bc_head;
6082           while (bc != NULL)
6083             {
6084               if (bc->bl_pos == bl)
6085                 {
6086                   bc->bl_pos = bl->next;
6087                   if (bc->th != NULL)
6088                     {
6089                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6090                       bc->th = NULL;
6091                     }
6092                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6093                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6094                                                          bc);
6095                   break;
6096                 }
6097               bc = bc->next;
6098             }
6099           GNUNET_CONTAINER_DLL_remove (bl_head,
6100                                        bl_tail,
6101                                        bl);
6102           GNUNET_SERVER_client_drop (bl->client);
6103           GNUNET_free (bl);
6104           break;
6105         }
6106       bl = bl->next;
6107     }
6108   /* clean up 'normal' clients */
6109   prev = NULL;
6110   pos = clients;
6111   while ((pos != NULL) && (pos->client != client))
6112     {
6113       prev = pos;
6114       pos = pos->next;
6115     }
6116   if (pos == NULL)
6117     return;
6118   while (NULL != (mqe = pos->message_queue_head))
6119     {
6120       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6121                                    pos->message_queue_tail,
6122                                    mqe);
6123       pos->message_count--;
6124       GNUNET_free (mqe);
6125     }
6126   if (prev == NULL)
6127     clients = pos->next;
6128   else
6129     prev->next = pos->next;
6130   if (GNUNET_YES == pos->tcs_pending)
6131     {
6132       pos->client = NULL;
6133       return;
6134     }
6135   if (pos->th != NULL)
6136     {
6137       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6138       pos->th = NULL;
6139     }
6140   GNUNET_break (0 == pos->message_count);
6141   GNUNET_free (pos);
6142 }
6143
6144
6145 /**
6146  * Function called when the service shuts down.  Unloads our plugins
6147  * and cancels pending validations.
6148  *
6149  * @param cls closure, unused
6150  * @param tc task context (unused)
6151  */
6152 static void
6153 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6154 {
6155   struct TransportPlugin *plug;
6156   struct TransportPlugin *tmp;
6157   struct OwnAddressList *al;
6158   struct CheckHelloValidatedContext *chvc;
6159
6160   shutdown_in_progress = GNUNET_YES;
6161   while (neighbours != NULL)
6162     {
6163 #if DEBUG_TRANSPORT
6164       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6165                   "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6166                   "SHUTDOWN_TASK");
6167 #endif
6168       disconnect_neighbour (neighbours, GNUNET_NO);
6169     }
6170 #if DEBUG_TRANSPORT
6171   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6172               "Transport service is unloading plugins...\n");
6173 #endif
6174   plug = plugins;
6175   while (plug != NULL)
6176     {
6177       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6178         {
6179           GNUNET_SCHEDULER_cancel (plug->address_update_task);
6180           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6181         }
6182       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6183       GNUNET_free (plug->lib_name);
6184       GNUNET_free (plug->short_name);
6185       while (NULL != (al = plug->addresses))
6186         {
6187           plug->addresses = al->next;
6188           GNUNET_free (al);
6189         }
6190       tmp = plug->next;
6191       GNUNET_free (plug);
6192       plug = tmp;
6193     }
6194   if (my_private_key != NULL)
6195     GNUNET_CRYPTO_rsa_key_free (my_private_key);
6196   GNUNET_free_non_null (our_hello);
6197
6198   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6199                                          &abort_validation,
6200                                          NULL);
6201   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6202   validation_map = NULL;
6203
6204
6205   if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6206   {
6207     GNUNET_SCHEDULER_cancel(ats_task);
6208     ats_task = GNUNET_SCHEDULER_NO_TASK;
6209   }
6210   if (ats != NULL)
6211     ats_shutdown (ats);
6212
6213   /* free 'chvc' data structure */
6214   while (NULL != (chvc = chvc_head))
6215     {
6216       chvc_head = chvc->next;
6217       if (chvc->piter != NULL)
6218         {
6219           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6220           GNUNET_STATISTICS_update (stats,
6221                                     gettext_noop ("# outstanding peerinfo iterate requests"),
6222                                     -1,
6223                                     GNUNET_NO);
6224           chvc->ve_count --;
6225         }
6226       else
6227           GNUNET_break (0);
6228       GNUNET_assert (chvc->ve_count == 0);
6229       GNUNET_free (chvc);
6230     }
6231   chvc_tail = NULL;
6232
6233   if (stats != NULL)
6234     {
6235       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6236       stats = NULL;
6237     }
6238   if (peerinfo != NULL)
6239     {
6240       GNUNET_PEERINFO_disconnect (peerinfo);
6241       peerinfo = NULL;
6242     }
6243   if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6244     {
6245       GNUNET_SCHEDULER_cancel (hello_task);
6246       hello_task = GNUNET_SCHEDULER_NO_TASK;
6247     }
6248   /* Can we assume those are gone by now, or do we need to clean up
6249      explicitly!? */
6250   GNUNET_break (bl_head == NULL);
6251   GNUNET_break (bc_head == NULL);
6252 }
6253
6254
6255 void ats_result_cb ()
6256 {
6257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6258       "ATS Result callback\n");
6259 }
6260
6261
6262 void create_ats_information ( struct ATS_peer **p,
6263                               int * c_p,
6264                               struct ATS_mechanism ** m,
6265                               int * c_m )
6266 {
6267 #if VERBOSE_ATS
6268   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6269       "ATS requires clean address information\n");
6270 #endif
6271   struct ATS_mechanism * mechanisms;
6272   struct ATS_peer *peers;
6273
6274   int connected_addresses = 0;
6275   int c_peers = 0;
6276   int c_mechs = 0;
6277   struct NeighbourList *next = neighbours;
6278
6279   while (next!=NULL)
6280   {
6281     int found_addresses = GNUNET_NO;
6282     struct ReadyList *r_next = next->plugins;
6283     while (r_next != NULL)
6284     {
6285         struct ForeignAddressList * a_next = r_next->addresses;
6286         while (a_next != NULL)
6287         {
6288             c_mechs++;
6289             found_addresses = GNUNET_YES;
6290             a_next = a_next->next;
6291         }
6292         r_next = r_next->next;
6293     }
6294     if (found_addresses) c_peers++;
6295     next = next->next;
6296   }
6297
6298 #if VERBOSE_ATS
6299   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6300       "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6301 #endif
6302
6303   if ((c_peers == 0) && (c_mechs == 0))
6304   {
6305     peers = NULL;
6306     (*c_p) = 0;
6307     mechanisms = NULL;
6308     (*c_m) = 0;
6309     return;
6310   }
6311
6312   mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6313   peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6314
6315   c_mechs = 1;
6316   c_peers = 1;
6317
6318   next = neighbours;
6319   while (next!=NULL)
6320   {
6321     int found_addresses = GNUNET_NO;
6322     struct ReadyList *r_next = next->plugins;
6323     while (r_next != NULL)
6324     {
6325         struct ForeignAddressList * a_next = r_next->addresses;
6326         while (a_next != NULL)
6327         {
6328             if (a_next->connected == GNUNET_YES)
6329               connected_addresses ++;
6330             if (found_addresses == GNUNET_NO)
6331             {
6332               peers[c_peers].peer = next->id;
6333               peers[c_peers].m_head = NULL;
6334               peers[c_peers].m_tail = NULL;
6335               peers[c_peers].f = 1.0 / c_mechs;
6336             }
6337
6338             mechanisms[c_mechs].addr = a_next;
6339             mechanisms[c_mechs].col_index = c_mechs;
6340             mechanisms[c_mechs].peer = &peers[c_peers];
6341             mechanisms[c_mechs].next = NULL;
6342             mechanisms[c_mechs].plugin = r_next->plugin;
6343             mechanisms[c_mechs].ressources = a_next->ressources;
6344             mechanisms[c_mechs].quality = a_next->quality;
6345
6346             GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6347                                              peers[c_peers].m_tail,
6348                                              &mechanisms[c_mechs]);
6349             found_addresses = GNUNET_YES;
6350             c_mechs++;
6351
6352             a_next = a_next->next;
6353         }
6354         r_next = r_next->next;
6355     }
6356     if (found_addresses == GNUNET_YES)
6357         c_peers++;
6358     next = next->next;
6359   }
6360   c_mechs--;
6361   c_peers--;
6362   (*c_m) = c_mechs;
6363   (*c_p) = c_peers;
6364   (*p) = peers;
6365   (*m) = mechanisms;
6366
6367   GNUNET_STATISTICS_set(stats,
6368                         gettext_noop ("# connected addresses"),
6369                         connected_addresses,
6370                         GNUNET_NO);
6371 }
6372
6373 static void
6374 schedule_ats (void *cls,
6375               const struct GNUNET_SCHEDULER_TaskContext *tc)
6376 {
6377   struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6378   if (ats==NULL)
6379     return;
6380
6381   ats_task = GNUNET_SCHEDULER_NO_TASK;
6382   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6383       return;
6384
6385   if (shutdown_in_progress == GNUNET_YES)
6386           return;
6387
6388   struct GNUNET_TIME_Relative delta =
6389       GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6390   if (delta.rel_value < ats_minimum_interval.rel_value)
6391   {
6392 #if DEBUG_ATS
6393     GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6394         "Minimum time between cycles not reached\n");
6395 #endif
6396     return;
6397   }
6398
6399 #if DEBUG_ATS
6400   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6401 #endif
6402   ats_calculate_bandwidth_distribution (ats, stats);
6403   last_ats_execution = GNUNET_TIME_absolute_get();
6404
6405   ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6406                                   &schedule_ats, ats);
6407 }
6408
6409 struct ForeignAddressList * get_preferred_ats_address (
6410                 struct NeighbourList *n)
6411 {
6412   // TODO get ATS prefered address
6413   return find_ready_address(n);
6414 }
6415
6416 /**
6417  * Initiate transport service.
6418  *
6419  * @param cls closure
6420  * @param server the initialized server
6421  * @param c configuration to use
6422  */
6423 static void
6424 run (void *cls,
6425      struct GNUNET_SERVER_Handle *server,
6426      const struct GNUNET_CONFIGURATION_Handle *c)
6427 {
6428   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6429     {&handle_start, NULL,
6430      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6431     {&handle_hello, NULL,
6432      GNUNET_MESSAGE_TYPE_HELLO, 0},
6433     {&handle_send, NULL,
6434      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6435     {&handle_request_connect, NULL,
6436      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6437     {&handle_set_quota, NULL,
6438      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6439     {&handle_address_lookup, NULL,
6440      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6441      0},
6442     {&handle_peer_address_lookup, NULL,
6443      GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6444      0},
6445     {&handle_address_iterate, NULL,
6446      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6447      0},
6448     {&handle_blacklist_init, NULL,
6449      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6450     {&handle_blacklist_reply, NULL,
6451      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6452     {NULL, NULL, 0, 0}
6453   };
6454   char *plugs;
6455   char *pos;
6456   int no_transports;
6457   unsigned long long tneigh;
6458   char *keyfile;
6459
6460   shutdown_in_progress = GNUNET_NO;
6461   cfg = c;
6462   stats = GNUNET_STATISTICS_create ("transport", cfg);
6463   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6464   /* parse configuration */
6465   if ((GNUNET_OK !=
6466        GNUNET_CONFIGURATION_get_value_number (c,
6467                                               "TRANSPORT",
6468                                               "NEIGHBOUR_LIMIT",
6469                                               &tneigh)) ||
6470       (GNUNET_OK !=
6471        GNUNET_CONFIGURATION_get_value_filename (c,
6472                                                 "GNUNETD",
6473                                                 "HOSTKEY", &keyfile)))
6474     {
6475       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6476                   _
6477                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
6478       GNUNET_SCHEDULER_shutdown ();
6479       if (stats != NULL)
6480         {
6481           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6482           stats = NULL;
6483         }
6484       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6485       validation_map = NULL;
6486       return;
6487     }
6488
6489   max_connect_per_transport = (uint32_t) tneigh;
6490   peerinfo = GNUNET_PEERINFO_connect (cfg);
6491   if (peerinfo == NULL)
6492     {
6493       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6494                   _("Could not access PEERINFO service.  Exiting.\n"));
6495       GNUNET_SCHEDULER_shutdown ();
6496       if (stats != NULL)
6497         {
6498           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6499           stats = NULL;
6500         }
6501       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6502       validation_map = NULL;
6503       GNUNET_free (keyfile);
6504       return;
6505     }
6506   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6507   GNUNET_free (keyfile);
6508   if (my_private_key == NULL)
6509     {
6510       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6511                   _
6512                   ("Transport service could not access hostkey.  Exiting.\n"));
6513       GNUNET_SCHEDULER_shutdown ();
6514       if (stats != NULL)
6515         {
6516           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6517           stats = NULL;
6518         }
6519       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6520       validation_map = NULL;
6521       return;
6522     }
6523   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6524   GNUNET_CRYPTO_hash (&my_public_key,
6525                       sizeof (my_public_key), &my_identity.hashPubKey);
6526   /* setup notification */
6527   GNUNET_SERVER_disconnect_notify (server,
6528                                    &client_disconnect_notification, NULL);
6529   /* load plugins... */
6530   no_transports = 1;
6531   if (GNUNET_OK ==
6532       GNUNET_CONFIGURATION_get_value_string (c,
6533                                              "TRANSPORT", "PLUGINS", &plugs))
6534     {
6535       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6536                   _("Starting transport plugins `%s'\n"), plugs);
6537       pos = strtok (plugs, " ");
6538       while (pos != NULL)
6539         {
6540           start_transport (server, pos);
6541           no_transports = 0;
6542           pos = strtok (NULL, " ");
6543         }
6544       GNUNET_free (plugs);
6545     }
6546   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6547                                 &shutdown_task, NULL);
6548   if (no_transports)
6549     refresh_hello ();
6550
6551   /* Initializing ATS */
6552   int co;
6553   char * section;
6554   unsigned long long  value;
6555
6556   double D = 1.0;
6557   double U = 1.0;
6558   double R = 1.0;
6559   int v_b_min = 64000;
6560   int v_n_min = 5;
6561
6562   ats_minimum_interval = ATS_MIN_INTERVAL;
6563   ats_regular_interval = ATS_EXEC_INTERVAL;
6564
6565   /* loading cost ressources */
6566   for (co=0; co<available_ressources; co++)
6567   {
6568     GNUNET_asprintf(&section,"%s_UP",ressources[co].cfg_param);
6569     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6570     {
6571       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6572           "transport",
6573           section,
6574           &value))
6575       {
6576 #if DEBUG_ATS
6577               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6578                   "Found ressource cost: [%s] = %llu\n",
6579                   section, value);
6580 #endif
6581               ressources[co].c_max = value;
6582       }
6583     }
6584     GNUNET_free (section);
6585     GNUNET_asprintf(&section,"%s_DOWN",ressources[co].cfg_param);
6586     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6587     {
6588       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6589           "transport",
6590           section,
6591           &value))
6592       {
6593 #if DEBUG_ATS
6594               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6595                   "Found ressource cost: [%s] = %llu\n",
6596                   section, value);
6597 #endif
6598               ressources[co].c_min = value;
6599       }
6600     }
6601     GNUNET_free (section);
6602   }
6603
6604   ats = ats_init (D, U, R, v_b_min, v_n_min,
6605                   ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6606                   create_ats_information,
6607                   ats_result_cb);
6608
6609   int log_problem = GNUNET_NO;
6610   int log_solution = GNUNET_NO;
6611   int overwrite_dump = GNUNET_NO;
6612   int minimum_peers = 0;
6613   int minimum_addresses = 0;
6614
6615   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6616     log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6617                              "transport","DUMP_MLP");
6618
6619   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6620     log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6621                                   "transport","DUMP_SOLUTION");
6622   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
6623     overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6624                                   "transport","DUMP_OVERWRITE");
6625   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
6626   {
6627           GNUNET_CONFIGURATION_get_value_number(cfg,
6628               "transport","DUMP_MIN_PEERS", &value);
6629           minimum_peers = value;
6630   }
6631   if (GNUNET_CONFIGURATION_have_value(cfg,
6632       "transport", "DUMP_MIN_ADDRS"))
6633   {
6634       GNUNET_CONFIGURATION_get_value_number(cfg,
6635         "transport","DUMP_MIN_ADDRS", &value);
6636       minimum_addresses= value;
6637   }
6638   if (GNUNET_CONFIGURATION_have_value(cfg,
6639       "transport", "DUMP_OVERWRITE"))
6640   {
6641       GNUNET_CONFIGURATION_get_value_number(cfg,
6642           "transport","DUMP_OVERWRITE", &value);
6643       overwrite_dump = value;
6644   }
6645
6646   if (GNUNET_CONFIGURATION_have_value(cfg,
6647       "transport", "ATS_MIN_INTERVAL"))
6648   {
6649       GNUNET_CONFIGURATION_get_value_number(cfg,
6650           "transport","ATS_MIN_INTERVAL", &value);
6651       ats_minimum_interval.rel_value = value;
6652   }
6653
6654   if (GNUNET_CONFIGURATION_have_value(cfg,
6655       "transport", "ATS_EXEC_INTERVAL"))
6656   {
6657       GNUNET_CONFIGURATION_get_value_number(cfg,
6658           "transport","ATS_EXEC_INTERVAL", &value);
6659       ats_regular_interval.rel_value = value;
6660   }
6661   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
6662   {
6663       GNUNET_CONFIGURATION_get_value_number(cfg,
6664           "transport","ATS_MIN_INTERVAL", &value);
6665       ats_minimum_interval.rel_value = value;
6666   }
6667
6668   ats_set_logging_options (ats,
6669                           minimum_addresses,
6670                           minimum_peers,
6671                           overwrite_dump,
6672                           log_solution,
6673                           log_problem);
6674
6675   if (ats != NULL)
6676     ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6677
6678
6679
6680
6681 #if DEBUG_TRANSPORT
6682   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
6683               _("Transport service ready.\n"));
6684 #endif
6685   /* If we have a blacklist file, read from it */
6686   read_blacklist_file(cfg);
6687   /* process client requests */
6688   GNUNET_SERVER_add_handlers (server, handlers);
6689 }
6690
6691
6692 /**
6693  * The main function for the transport service.
6694  *
6695  * @param argc number of arguments from the command line
6696  * @param argv command line arguments
6697  * @return 0 ok, 1 on error
6698  */
6699 int
6700 main (int argc, char *const *argv)
6701 {
6702   a2s (NULL, NULL, 0); /* make compiler happy */
6703   return (GNUNET_OK ==
6704           GNUNET_SERVICE_run (argc,
6705                               argv,
6706                               "transport",
6707                               GNUNET_SERVICE_OPTION_NONE,
6708                               &run, NULL)) ? 0 : 1;
6709 }
6710
6711 /* end of gnunet-service-transport.c */