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