transport minor changes
[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
1936   while (pos != NULL)
1937     {
1938       if (GNUNET_YES == pos->connected)
1939         {
1940 #if DEBUG_TRANSPORT
1941           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1942                       "Marking address `%s' as no longer connected (due to connect on other address)\n",
1943                       a2s (pos->ready_list->plugin->short_name,
1944                            pos->addr,
1945                            pos->addrlen));
1946 #endif
1947           GNUNET_break (cnt == GNUNET_YES);
1948           cnt = GNUNET_NO;
1949           pos->connected = GNUNET_NO;
1950           GNUNET_STATISTICS_update (stats,
1951                                     gettext_noop ("# connected addresses"),
1952                                     -1,
1953                                     GNUNET_NO);
1954         }
1955       pos = pos->next;
1956     }
1957
1958   fal->connected = GNUNET_YES;
1959   if (GNUNET_YES == cnt)
1960     {
1961       GNUNET_STATISTICS_update (stats,
1962                                 gettext_noop ("# connected addresses"),
1963                                 1,
1964                                 GNUNET_NO);
1965     }
1966 }
1967
1968
1969 /**
1970  * Find an address in any of the available transports for
1971  * the given neighbour that would be good for message
1972  * transmission.  This is essentially the transport selection
1973  * routine.
1974  *
1975  * @param neighbour for whom to select an address
1976  * @return selected address, NULL if we have none
1977  */
1978 struct ForeignAddressList *
1979 find_ready_address(struct NeighbourList *neighbour)
1980 {
1981   struct ReadyList *head = neighbour->plugins;
1982   struct ForeignAddressList *addresses;
1983   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1984   struct ForeignAddressList *best_address;
1985
1986   /* Hack to prefer unix domain sockets */
1987   struct ForeignAddressList *unix_address = NULL;
1988
1989   best_address = NULL;
1990   while (head != NULL)
1991     {
1992       addresses = head->addresses;
1993       while (addresses != NULL)
1994         {
1995           if ( (addresses->timeout.abs_value < now.abs_value) &&
1996                (addresses->connected == GNUNET_YES) )
1997             {
1998 #if DEBUG_TRANSPORT
1999               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2000                           "Marking long-time inactive connection to `%4s' as down.\n",
2001                           GNUNET_i2s (&neighbour->id));
2002 #endif
2003               GNUNET_STATISTICS_update (stats,
2004                                         gettext_noop ("# connected addresses"),
2005                                         -1,
2006                                         GNUNET_NO);
2007               addresses->connected = GNUNET_NO;
2008             }
2009           addresses = addresses->next;
2010         }
2011
2012       addresses = head->addresses;
2013       while (addresses != NULL)
2014         {
2015 #if DEBUG_TRANSPORT
2016           if (addresses->addr != NULL)
2017             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2018                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2019                         a2s (head->plugin->short_name,
2020                              addresses->addr,
2021                              addresses->addrlen),
2022                         GNUNET_i2s (&neighbour->id),
2023                         addresses->connected,
2024                         addresses->in_transmit,
2025                         addresses->validated,
2026                         addresses->connect_attempts,
2027                         (unsigned long long) addresses->timeout.abs_value,
2028                         (unsigned int) addresses->distance);
2029 #endif
2030           if (0==strcmp(head->plugin->short_name,"unix"))
2031             {
2032               if ( (unix_address == NULL) || 
2033                    ( (unix_address != NULL) &&
2034                      (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2035                 unix_address = addresses;
2036             }
2037           if ( ( (best_address == NULL) ||
2038                  (addresses->connected == GNUNET_YES) ||
2039                  (best_address->connected == GNUNET_NO) ) &&
2040                (addresses->in_transmit == GNUNET_NO) &&
2041                ( (best_address == NULL) ||
2042                  (addresses->latency.rel_value < best_address->latency.rel_value)) )
2043             best_address = addresses;
2044           /* FIXME: also give lower-latency addresses that are not
2045              connected a chance some times... */
2046           addresses = addresses->next;
2047         }
2048       if (unix_address != NULL)
2049           break;
2050       head = head->next;
2051     }
2052   if (unix_address != NULL)
2053     {
2054       best_address = unix_address;
2055 #if DEBUG_TRANSPORT
2056       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2057                   "Found UNIX address, forced this address\n");
2058 #endif
2059     }
2060   if (best_address != NULL)
2061     {
2062 #if DEBUG_TRANSPORT
2063       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2064                   "Best address found (`%s') has latency of %llu ms.\n",
2065                   (best_address->addrlen > 0)
2066                   ? a2s (best_address->ready_list->plugin->short_name,
2067                          best_address->addr,
2068                        best_address->addrlen)
2069                   : "<inbound>",
2070                   best_address->latency.rel_value);
2071 #endif
2072     }
2073   else
2074     {
2075       GNUNET_STATISTICS_update (stats,
2076                                 gettext_noop ("# transmission attempts failed (no address)"),
2077                                 1,
2078                                 GNUNET_NO);
2079     }
2080
2081   return best_address;
2082 }
2083
2084
2085 /**
2086  * FIXME: document.
2087  */
2088 struct GeneratorContext
2089 {
2090   struct TransportPlugin *plug_pos;
2091   struct OwnAddressList *addr_pos;
2092   struct GNUNET_TIME_Absolute expiration;
2093 };
2094
2095
2096 /**
2097  * FIXME: document.
2098  */
2099 static size_t
2100 address_generator (void *cls, size_t max, void *buf)
2101 {
2102   struct GeneratorContext *gc = cls;
2103   size_t ret;
2104
2105   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2106     {
2107       gc->plug_pos = gc->plug_pos->next;
2108       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2109     }
2110   if (NULL == gc->plug_pos)
2111     {
2112
2113       return 0;
2114     }
2115   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2116                                   gc->expiration,
2117                                   &gc->addr_pos[1],
2118                                   gc->addr_pos->addrlen, buf, max);
2119   gc->addr_pos = gc->addr_pos->next;
2120   return ret;
2121 }
2122
2123
2124 /**
2125  * Construct our HELLO message from all of the addresses of
2126  * all of the transports.
2127  *
2128  * @param cls unused
2129  * @param tc scheduler context
2130  */
2131 static void
2132 refresh_hello_task (void *cls,
2133                     const struct GNUNET_SCHEDULER_TaskContext *tc)
2134 {
2135   struct GNUNET_HELLO_Message *hello;
2136   struct TransportClient *cpos;
2137   struct NeighbourList *npos;
2138   struct GeneratorContext gc;
2139
2140   hello_task = GNUNET_SCHEDULER_NO_TASK;
2141   gc.plug_pos = plugins;
2142   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2143   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2144   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2145 #if DEBUG_TRANSPORT
2146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2147               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2148 #endif
2149   GNUNET_STATISTICS_update (stats,
2150                             gettext_noop ("# refreshed my HELLO"),
2151                             1,
2152                             GNUNET_NO);
2153   cpos = clients;
2154   while (cpos != NULL)
2155     {
2156       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2157                   "Transmitting my HELLO to client!\n");
2158       transmit_to_client (cpos,
2159                           (const struct GNUNET_MessageHeader *) hello,
2160                           GNUNET_NO);
2161       cpos = cpos->next;
2162     }
2163
2164   GNUNET_free_non_null (our_hello);
2165   our_hello = hello;
2166   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2167   for (npos = neighbours; npos != NULL; npos = npos->next)
2168     {
2169       if (! npos->received_pong)
2170         continue;
2171 #if DEBUG_TRANSPORT
2172       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2173                   "Transmitting updated `%s' to neighbour `%4s'\n",
2174                   "HELLO", GNUNET_i2s (&npos->id));
2175 #endif
2176       GNUNET_STATISTICS_update (stats,
2177                                 gettext_noop ("# transmitted my HELLO to other peers"),
2178                                 1,
2179                                 GNUNET_NO);
2180       transmit_to_peer (NULL, NULL, 0,
2181                         HELLO_ADDRESS_EXPIRATION,
2182                         (const char *) our_hello,
2183                         GNUNET_HELLO_size(our_hello),
2184                         GNUNET_NO, npos);
2185     }
2186 }
2187
2188
2189 /**
2190  * Schedule task to refresh hello (unless such a
2191  * task exists already).
2192  */
2193 static void
2194 refresh_hello ()
2195 {
2196 #if DEBUG_TRANSPORT_HELLO
2197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2198               "refresh_hello() called!\n");
2199 #endif
2200   if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2201     return;
2202   hello_task
2203     = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2204                                 NULL);
2205 }
2206
2207
2208 /**
2209  * Iterator over hash map entries that NULLs the session of validation
2210  * entries that match the given session.
2211  *
2212  * @param cls closure (the 'struct Session*' to match against)
2213  * @param key current key code (peer ID, not used)
2214  * @param value value in the hash map ('struct ValidationEntry*')
2215  * @return GNUNET_YES (we should continue to iterate)
2216  */
2217 static int
2218 remove_session_validations (void *cls,
2219                             const GNUNET_HashCode * key,
2220                             void *value)
2221 {
2222   struct Session *session = cls;
2223   struct ValidationEntry *ve = value;
2224
2225   if (session == ve->session)
2226     ve->session = NULL;
2227   return GNUNET_YES;
2228 }
2229
2230
2231 /**
2232  * We've been disconnected from the other peer (for some
2233  * connection-oriented transport).  Either quickly
2234  * re-establish the connection or signal the disconnect
2235  * to the CORE.
2236  *
2237  * Only signal CORE level disconnect if ALL addresses
2238  * for the peer are exhausted.
2239  *
2240  * @param p overall plugin context
2241  * @param nl neighbour that was disconnected
2242  */
2243 static void
2244 try_fast_reconnect (struct TransportPlugin *p,
2245                     struct NeighbourList *nl)
2246 {
2247   /* FIXME-MW: fast reconnect / transport switching not implemented... */
2248   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2249               "try_fast_reconnect not implemented!\n");
2250   /* Note: the idea here is to hide problems with transports (or
2251      switching between plugins) from the core to eliminate the need to
2252      re-negotiate session keys and the like; OTOH, we should tell core
2253      quickly (much faster than timeout) `if a connection was lost and
2254      could not be re-established (i.e. other peer went down or is
2255      unable / refuses to communicate);
2256
2257      So we should consider:
2258      1) ideally: our own willingness / need to connect
2259      2) prior failures to connect to this peer (by plugin)
2260      3) ideally: reasons why other peer terminated (as far as knowable)
2261
2262      Most importantly, it must be POSSIBLE for another peer to terminate
2263      a connection for a while (without us instantly re-establishing it).
2264      Similarly, if another peer is gone we should quickly notify CORE.
2265      OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2266      on the other end), we should reconnect in such a way that BOTH CORE
2267      services never even notice.
2268      Furthermore, the same mechanism (or small variation) could be used
2269      to switch to a better-performing plugin (ATS).
2270
2271      Finally, this needs to be tested throughly... */
2272
2273   /*
2274    * GNUNET_NO in the call below makes transport disconnect the peer,
2275    * even if only a single address (out of say, six) went away.  This
2276    * function must be careful to ONLY disconnect if the peer is gone,
2277    * not just a specific address.
2278    *
2279    * More specifically, half the places it was used had it WRONG.
2280    */
2281
2282   /* No reconnect, signal disconnect instead! */
2283 #if DEBUG_TRANSPORT
2284 #endif
2285   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2286             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2287             "try_fast_reconnect");
2288
2289   GNUNET_STATISTICS_update (stats,
2290                             gettext_noop ("# disconnects due to try_fast_reconnect"),
2291                             1,
2292                             GNUNET_NO);
2293 #if DISCONNECT || 1
2294   disconnect_neighbour (nl, GNUNET_YES);
2295 #endif
2296 }
2297
2298
2299 /**
2300  * Function that will be called whenever the plugin internally
2301  * cleans up a session pointer and hence the service needs to
2302  * discard all of those sessions as well.  Plugins that do not
2303  * use sessions can simply omit calling this function and always
2304  * use NULL wherever a session pointer is needed.
2305  *
2306  * @param cls closure
2307  * @param peer which peer was the session for
2308  * @param session which session is being destoyed
2309  */
2310 static void
2311 plugin_env_session_end  (void *cls,
2312                          const struct GNUNET_PeerIdentity *peer,
2313                          struct Session *session)
2314 {
2315   struct TransportPlugin *p = cls;
2316   struct NeighbourList *nl;
2317   struct ReadyList *rl;
2318   struct ForeignAddressList *pos;
2319   struct ForeignAddressList *prev;
2320
2321 #if DEBUG_TRANSPORT
2322   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2323               "Session ended with peer `%4s', %s\n", 
2324               GNUNET_i2s(peer),
2325               "plugin_env_session_end");
2326 #endif
2327   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2328                                          &remove_session_validations,
2329                                          session);
2330   nl = find_neighbour (peer);
2331   if (nl == NULL)
2332     {
2333 #if DEBUG_TRANSPORT
2334       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2335                   "No neighbour record found for peer `%4s'\n", 
2336                   GNUNET_i2s(peer));
2337 #endif
2338       return; /* was never marked as connected */
2339     }
2340   rl = nl->plugins;
2341   while (rl != NULL)
2342     {
2343       if (rl->plugin == p)
2344         break;
2345       rl = rl->next;
2346     }
2347   if (rl == NULL)
2348     {
2349 #if DEBUG_TRANSPORT
2350       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2351                   "Plugin was associated with peer `%4s'\n", 
2352                   GNUNET_i2s(peer));
2353 #endif
2354       GNUNET_STATISTICS_update (stats,
2355                                 gettext_noop ("# disconnects due to session end"),
2356                                 1,
2357                                 GNUNET_NO);
2358       disconnect_neighbour (nl, GNUNET_YES);
2359       return;
2360     }
2361   prev = NULL;
2362   pos = rl->addresses;
2363   while ( (pos != NULL) &&
2364           (pos->session != session) )
2365     {
2366       prev = pos;
2367       pos = pos->next;
2368     }
2369   if (pos == NULL)
2370     {
2371 #if DEBUG_TRANSPORT
2372       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373                   "Session was never marked as ready for peer `%4s'\n", 
2374                   GNUNET_i2s(peer));
2375 #endif
2376
2377       int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2378
2379       /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2380       if (validations_pending ==GNUNET_YES)
2381         {
2382 #if DEBUG_TRANSPORT
2383       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2384                   "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2385 #endif
2386         return;
2387         }
2388
2389       //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2390       GNUNET_STATISTICS_update (stats,
2391                                 gettext_noop ("# disconnects due to unready session"),
2392                                 1,
2393                                 GNUNET_NO);
2394
2395       disconnect_neighbour (nl, GNUNET_YES);
2396       return; /* was never marked as connected */
2397     }
2398   pos->session = NULL;
2399   pos->connected = GNUNET_NO;
2400   if (pos->addrlen != 0)
2401     {
2402       if (nl->received_pong != GNUNET_NO)
2403         {
2404           GNUNET_STATISTICS_update (stats,
2405                                     gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2406                                     1,
2407                                     GNUNET_NO);
2408           if (GNUNET_YES == pos->connected)                  
2409               try_fast_reconnect (p, nl);           
2410         }
2411       else
2412         {
2413           GNUNET_STATISTICS_update (stats,
2414                                     gettext_noop ("# disconnects due to missing pong"),
2415                                     1,
2416                                     GNUNET_NO);
2417           /* FIXME this is never true?! See: line 2416*/
2418           if (GNUNET_YES == pos->connected)
2419             disconnect_neighbour (nl, GNUNET_YES);
2420         }
2421       return;
2422     }
2423
2424   GNUNET_STATISTICS_update (stats,
2425                               gettext_noop ("# connected addresses"),
2426                               -1,
2427                               GNUNET_NO);
2428
2429   /* was inbound connection, free 'pos' */
2430   if (prev == NULL)
2431     rl->addresses = pos->next;
2432   else
2433     prev->next = pos->next;
2434   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2435     {
2436       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2437       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2438     }
2439   GNUNET_free_non_null(pos->ressources);
2440   GNUNET_free_non_null(pos->quality);
2441   ats_modify_problem_state (ats, ATS_MODIFIED);
2442
2443   if (GNUNET_YES != pos->connected)
2444     {
2445       /* nothing else to do, connection was never up... */
2446       GNUNET_free (pos);
2447       return; 
2448     }
2449   GNUNET_free (pos);
2450
2451   if (nl->received_pong == GNUNET_NO)
2452     {
2453       GNUNET_STATISTICS_update (stats,
2454                                 gettext_noop ("# disconnects due to NO pong"),
2455                                 1,
2456                                 GNUNET_NO);
2457       disconnect_neighbour (nl, GNUNET_YES);
2458       return; /* nothing to do, never connected... */
2459     }
2460   /* check if we have any validated addresses left */
2461   pos = rl->addresses;
2462   while (pos != NULL)
2463     {
2464       if (GNUNET_YES == pos->validated)
2465         {
2466           GNUNET_STATISTICS_update (stats,
2467                                     gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2468                                     1,
2469                                     GNUNET_NO);
2470           try_fast_reconnect (p, nl);
2471           return;
2472         }
2473       pos = pos->next;
2474     }
2475   /* no valid addresses left, signal disconnect! */
2476
2477 #if DEBUG_TRANSPORT
2478   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2479               "Disconnecting peer `%4s', %s\n", 
2480               GNUNET_i2s(peer),
2481               "plugin_env_session_end");
2482 #endif
2483   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2484    * it means there aren't any left for this PLUGIN/PEER combination! So
2485    * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2486    * when it isn't necessary. Using GNUNET_YES at least checks to see
2487    * if there are any addresses that work first, so as not to overdo it.
2488    * --NE
2489    */
2490   GNUNET_STATISTICS_update (stats,
2491                             gettext_noop ("# disconnects due to plugin_env_session_end"),
2492                             1,
2493                             GNUNET_NO);
2494   disconnect_neighbour (nl, GNUNET_YES);
2495 }
2496
2497
2498 /**
2499  * Function that must be called by each plugin to notify the
2500  * transport service about the addresses under which the transport
2501  * provided by the plugin can be reached.
2502  *
2503  * @param cls closure
2504  * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2505  * @param addr one of the addresses of the host, NULL for the last address
2506  *        the specific address format depends on the transport
2507  * @param addrlen length of the address
2508  */
2509 static void
2510 plugin_env_notify_address (void *cls,
2511                            int add_remove,
2512                            const void *addr,
2513                            size_t addrlen)
2514 {
2515   struct TransportPlugin *p = cls;
2516   struct OwnAddressList *al;
2517   struct OwnAddressList *prev;
2518
2519   GNUNET_assert (p->api != NULL);
2520 #if DEBUG_TRANSPORT
2521   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2522               (add_remove == GNUNET_YES)
2523               ? "Adding `%s':%s to the set of our addresses\n"
2524               : "Removing `%s':%s from the set of our addresses\n",
2525               a2s (p->short_name,
2526                    addr, addrlen),
2527               p->short_name);
2528 #endif
2529   GNUNET_assert (addr != NULL);
2530   if (GNUNET_NO == add_remove)
2531     {
2532       prev = NULL;
2533       al = p->addresses;
2534       while (al != NULL)
2535         {
2536           if ( (addrlen == al->addrlen) &&
2537                (0 == memcmp (addr, &al[1], addrlen)) )
2538             {
2539               if (prev == NULL)
2540                 p->addresses = al->next;
2541               else
2542                 prev->next = al->next;
2543               GNUNET_free (al);
2544               refresh_hello ();
2545               return;
2546             }
2547           prev = al;
2548           al = al->next;
2549         }
2550       GNUNET_break (0);
2551       return;
2552     }
2553   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2554   al->next = p->addresses;
2555   p->addresses = al;
2556   al->addrlen = addrlen;
2557   memcpy (&al[1], addr, addrlen);
2558   refresh_hello ();
2559 }
2560
2561
2562 /**
2563  * Notify all of our clients about a peer connecting.
2564  */
2565 static void
2566 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2567                         struct GNUNET_TIME_Relative latency,
2568                         uint32_t distance)
2569 {
2570   struct ConnectInfoMessage * cim;
2571   struct TransportClient *cpos;
2572   uint32_t ats_count;
2573   size_t size;
2574
2575   if (0 == memcmp (peer,
2576                    &my_identity,
2577                    sizeof (struct GNUNET_PeerIdentity)))
2578     {
2579       GNUNET_break (0);
2580       return;
2581     }
2582 #if DEBUG_TRANSPORT
2583   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2584               "Notifying clients about connection with `%s'\n",
2585               GNUNET_i2s (peer));
2586 #endif
2587   GNUNET_STATISTICS_update (stats,
2588                             gettext_noop ("# peers connected"),
2589                             1,
2590                             GNUNET_NO);
2591
2592   ats_count = 2;
2593   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2594   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2595     {
2596       GNUNET_break(0);
2597     }
2598   cim = GNUNET_malloc (size);
2599   cim->header.size = htons (size);
2600   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2601   cim->ats_count = htonl(2);
2602   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2603   (&(cim->ats))[0].value = htonl (distance);
2604   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2605   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2606   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2607   (&(cim->ats))[2].value = htonl (0);
2608   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2609
2610   /* notify ats about connecting peer */
2611   /* notify ats about connecting peer */
2612   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2613   {
2614     ats_modify_problem_state(ats, ATS_MODIFIED);
2615     ats_calculate_bandwidth_distribution (ats, stats);
2616   }
2617
2618
2619   cpos = clients;
2620   while (cpos != NULL)
2621     {
2622       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2623       cpos = cpos->next;
2624     }
2625
2626   GNUNET_free (cim);
2627 }
2628
2629
2630 /**
2631  * Notify all of our clients about a peer disconnecting.
2632  */
2633 static void
2634 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2635 {
2636   struct DisconnectInfoMessage dim;
2637   struct TransportClient *cpos;
2638
2639   if (0 == memcmp (peer,
2640                    &my_identity,
2641                    sizeof (struct GNUNET_PeerIdentity)))
2642     {
2643       GNUNET_break (0);
2644       return;
2645     }
2646 #if DEBUG_TRANSPORT
2647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2648               "Notifying clients about lost connection to `%s'\n",
2649               GNUNET_i2s (peer));
2650 #endif
2651   GNUNET_STATISTICS_update (stats,
2652                             gettext_noop ("# peers connected"),
2653                             -1,
2654                             GNUNET_NO);
2655   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2656   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2657   dim.reserved = htonl (0);
2658   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2659
2660   /* notify ats about connecting peer */
2661   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2662   {
2663     ats_modify_problem_state(ats, ATS_MODIFIED);
2664     ats_calculate_bandwidth_distribution (ats, stats);
2665   }
2666
2667   cpos = clients;
2668   while (cpos != NULL)
2669     {
2670       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2671       cpos = cpos->next;
2672     }
2673 }
2674
2675
2676 /**
2677  * Find a ForeignAddressList entry for the given neighbour
2678  * that matches the given address and transport.
2679  *
2680  * @param neighbour which peer we care about
2681  * @param tname name of the transport plugin
2682  * @param session session to look for, NULL for 'any'; otherwise
2683  *        can be used for the service to "learn" this session ID
2684  *        if 'addr' matches
2685  * @param addr binary address
2686  * @param addrlen length of addr
2687  * @return NULL if no such entry exists
2688  */
2689 static struct ForeignAddressList *
2690 find_peer_address(struct NeighbourList *neighbour,
2691                   const char *tname,
2692                   struct Session *session,
2693                   const char *addr,
2694                   uint16_t addrlen)
2695 {
2696   struct ReadyList *head;
2697   struct ForeignAddressList *pos;
2698
2699   head = neighbour->plugins;
2700   while (head != NULL)
2701     {
2702       if (0 == strcmp (tname, head->plugin->short_name))
2703         break;
2704       head = head->next;
2705     }
2706   if (head == NULL)
2707     return NULL;
2708   pos = head->addresses;
2709   while ( (pos != NULL) &&
2710           ( (pos->addrlen != addrlen) ||
2711             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2712     {
2713       if ( (session != NULL) &&
2714            (pos->session == session) )
2715         return pos;
2716       pos = pos->next;
2717     }
2718   if ( (session != NULL) && (pos != NULL) )
2719     pos->session = session; /* learn it! */
2720   return pos;
2721 }
2722
2723
2724 /**
2725  * Get the peer address struct for the given neighbour and
2726  * address.  If it doesn't yet exist, create it.
2727  *
2728  * @param neighbour which peer we care about
2729  * @param tname name of the transport plugin
2730  * @param session session of the plugin, or NULL for none
2731  * @param addr binary address
2732  * @param addrlen length of addr
2733  * @return NULL if we do not have a transport plugin for 'tname'
2734  */
2735 static struct ForeignAddressList *
2736 add_peer_address (struct NeighbourList *neighbour,
2737                   const char *tname,
2738                   struct Session *session,
2739                   const char *addr,
2740                   uint16_t addrlen)
2741 {
2742   struct ReadyList *head;
2743   struct ForeignAddressList *ret;
2744   int c;
2745
2746   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2747   if (ret != NULL)
2748     return ret;
2749   head = neighbour->plugins;
2750
2751   while (head != NULL)
2752     {
2753       if (0 == strcmp (tname, head->plugin->short_name))
2754         break;
2755       head = head->next;
2756     }
2757   if (head == NULL)
2758     return NULL;
2759   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2760   ret->session = session;
2761   if ((addrlen > 0) && (addr != NULL))
2762     {
2763       ret->addr = (const char*) &ret[1];
2764       memcpy (&ret[1], addr, addrlen);
2765     }
2766   else
2767     {
2768       ret->addr = NULL;
2769     }
2770
2771   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2772   for (c=0; c<available_ressources; c++)
2773     {
2774       struct ATS_ressource_entry *r = ret->ressources;
2775       r[c].index = c;
2776       r[c].atis_index = ressources[c].atis_index;
2777       if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2778         {
2779           r[c].c = ressources[c].c_unix;
2780         }
2781       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2782         {
2783           r[c].c = ressources[c].c_udp;
2784         }
2785       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2786         {
2787           r[c].c = ressources[c].c_tcp;
2788         }
2789       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2790         {
2791           r[c].c = ressources[c].c_http;
2792         }
2793       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2794         {
2795           r[c].c = ressources[c].c_https;
2796         }
2797       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2798         {
2799           r[c].c = ressources[c].c_wlan;
2800         }
2801       else
2802         {
2803           r[c].c = ressources[c].c_default;
2804           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2805                       "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2806                       GNUNET_i2s(&neighbour->id),
2807                       neighbour->plugins->plugin->short_name);
2808         }
2809     }
2810
2811   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2812   ret->addrlen = addrlen;
2813   ret->expires = GNUNET_TIME_relative_to_absolute
2814     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2815   ret->latency = GNUNET_TIME_relative_get_forever();
2816   ret->distance = -1;
2817   ret->timeout = GNUNET_TIME_relative_to_absolute
2818     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2819   ret->ready_list = head;
2820   ret->next = head->addresses;
2821   head->addresses = ret;
2822   return ret;
2823 }
2824
2825
2826 /**
2827  * Closure for 'add_validated_address'.
2828  */
2829 struct AddValidatedAddressContext
2830 {
2831   /**
2832    * Entry that has been validated.
2833    */
2834   const struct ValidationEntry *ve;
2835
2836   /**
2837    * Flag set after we have added the address so
2838    * that we terminate the iteration next time.
2839    */
2840   int done;
2841 };
2842
2843
2844 /**
2845  * Callback function used to fill a buffer of max bytes with a list of
2846  * addresses in the format used by HELLOs.  Should use
2847  * "GNUNET_HELLO_add_address" as a helper function.
2848  *
2849  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2850  * @param max maximum number of bytes that can be written to buf
2851  * @param buf where to write the address information
2852  * @return number of bytes written, 0 to signal the
2853  *         end of the iteration.
2854  */
2855 static size_t
2856 add_validated_address (void *cls,
2857                        size_t max, void *buf)
2858 {
2859   struct AddValidatedAddressContext *avac = cls;
2860   const struct ValidationEntry *ve = avac->ve;
2861
2862   if (GNUNET_YES == avac->done)
2863     return 0;
2864   avac->done = GNUNET_YES;
2865   return GNUNET_HELLO_add_address (ve->transport_name,
2866                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2867                                    ve->addr,
2868                                    ve->addrlen,
2869                                    buf,
2870                                    max);
2871 }
2872
2873
2874
2875 /**
2876  * Closure for 'check_address_exists'.
2877  */
2878 struct CheckAddressExistsClosure
2879 {
2880   /**
2881    * Address to check for.
2882    */
2883   const void *addr;
2884
2885   /**
2886    * Name of the transport.
2887    */
2888   const char *tname;
2889
2890   /**
2891    * Session, or NULL.
2892    */
2893   struct Session *session;
2894
2895   /**
2896    * Set to GNUNET_YES if the address exists.
2897    */
2898   int exists;
2899
2900   /**
2901    * Length of addr.
2902    */
2903   uint16_t addrlen;
2904
2905 };
2906
2907
2908 /**
2909  * Iterator over hash map entries.  Checks if the given
2910  * validation entry is for the same address as what is given
2911  * in the closure.
2912  *
2913  * @param cls the 'struct CheckAddressExistsClosure*'
2914  * @param key current key code (ignored)
2915  * @param value value in the hash map ('struct ValidationEntry')
2916  * @return GNUNET_YES if we should continue to
2917  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2918  */
2919 static int
2920 check_address_exists (void *cls,
2921                       const GNUNET_HashCode * key,
2922                       void *value)
2923 {
2924   struct CheckAddressExistsClosure *caec = cls;
2925   struct ValidationEntry *ve = value;
2926
2927   if ( (0 == strcmp (caec->tname,
2928                      ve->transport_name)) &&
2929        (caec->addrlen == ve->addrlen) &&
2930        (0 == memcmp (caec->addr,
2931                      ve->addr,
2932                      caec->addrlen)) )
2933     {
2934       caec->exists = GNUNET_YES;
2935       return GNUNET_NO;
2936     }
2937   if ( (ve->session != NULL) &&
2938        (caec->session == ve->session) )
2939     {
2940       caec->exists = GNUNET_YES;
2941       return GNUNET_NO;
2942     }
2943   return GNUNET_YES;
2944 }
2945
2946
2947 static void
2948 neighbour_timeout_task (void *cls,
2949                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2950 {
2951   struct NeighbourList *n = cls;
2952
2953 #if DEBUG_TRANSPORT
2954   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2955               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2956 #endif
2957   GNUNET_STATISTICS_update (stats,
2958                             gettext_noop ("# disconnects due to timeout"),
2959                             1,
2960                             GNUNET_NO);
2961   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2962   disconnect_neighbour (n, GNUNET_NO);
2963 }
2964
2965
2966 /**
2967  * Schedule the job that will cause us to send a PING to the
2968  * foreign address to evaluate its validity and latency.
2969  *
2970  * @param fal address to PING
2971  */
2972 static void
2973 schedule_next_ping (struct ForeignAddressList *fal);
2974
2975
2976 /**
2977  * Add the given address to the list of foreign addresses
2978  * available for the given peer (check for duplicates).
2979  *
2980  * @param cls the respective 'struct NeighbourList' to update
2981  * @param tname name of the transport
2982  * @param expiration expiration time
2983  * @param addr the address
2984  * @param addrlen length of the address
2985  * @return GNUNET_OK (always)
2986  */
2987 static int
2988 add_to_foreign_address_list (void *cls,
2989                              const char *tname,
2990                              struct GNUNET_TIME_Absolute expiration,
2991                              const void *addr,
2992                              uint16_t addrlen)
2993 {
2994   struct NeighbourList *n = cls;
2995   struct ForeignAddressList *fal;
2996   int try;
2997
2998   GNUNET_STATISTICS_update (stats,
2999                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
3000                             1,
3001                             GNUNET_NO);
3002   try = GNUNET_NO;
3003   fal = find_peer_address (n, tname, NULL, addr, addrlen);
3004   if (fal == NULL)
3005     {
3006 #if DEBUG_TRANSPORT_HELLO
3007       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3008                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3009                   a2s (tname, addr, addrlen),
3010                   tname,
3011                   GNUNET_i2s (&n->id),
3012                   expiration.abs_value);
3013 #endif
3014       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3015       if (fal == NULL)
3016         {
3017           GNUNET_STATISTICS_update (stats,
3018                                     gettext_noop ("# previously validated addresses lacking transport"),
3019                                     1,
3020                                     GNUNET_NO);
3021         }
3022       else
3023         {
3024           fal->expires = GNUNET_TIME_absolute_max (expiration,
3025                                                    fal->expires);
3026           schedule_next_ping (fal);
3027         }
3028       try = GNUNET_YES;
3029     }
3030   else
3031     {
3032       fal->expires = GNUNET_TIME_absolute_max (expiration,
3033                                                fal->expires);
3034     }
3035   if (fal == NULL)
3036     {
3037 #if DEBUG_TRANSPORT
3038       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3039                   "Failed to add new address for `%4s'\n",
3040                   GNUNET_i2s (&n->id));
3041 #endif
3042       return GNUNET_OK;
3043     }
3044   if (fal->validated == GNUNET_NO)
3045     {
3046       fal->validated = GNUNET_YES;
3047       GNUNET_STATISTICS_update (stats,
3048                                 gettext_noop ("# peer addresses considered valid"),
3049                                 1,
3050                                 GNUNET_NO);
3051     }
3052   if (try == GNUNET_YES)
3053     {
3054 #if DEBUG_TRANSPORT
3055       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056                   "Have new addresses, will try to trigger transmissions.\n");
3057 #endif
3058       try_transmission_to_peer (n);
3059     }
3060   return GNUNET_OK;
3061 }
3062
3063
3064 /**
3065  * Add addresses in validated HELLO "h" to the set of addresses
3066  * we have for this peer.
3067  *
3068  * @param cls closure ('struct NeighbourList*')
3069  * @param peer id of the peer, NULL for last call
3070  * @param h hello message for the peer (can be NULL)
3071  * @param err_msg NULL if successful, otherwise contains error message
3072  */
3073 static void
3074 add_hello_for_peer (void *cls,
3075                     const struct GNUNET_PeerIdentity *peer,
3076                     const struct GNUNET_HELLO_Message *h,
3077                     const char *err_msg)
3078 {
3079   struct NeighbourList *n = cls;
3080
3081   if (err_msg != NULL)
3082     {
3083 #if DEBUG_TRANSPORT
3084       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3085                   _("Error in communication with PEERINFO service: %s\n"),
3086                   err_msg);
3087 #endif
3088       /* return; */
3089     }
3090   if (peer == NULL)
3091     {
3092       GNUNET_STATISTICS_update (stats,
3093                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3094                                 -1,
3095                                 GNUNET_NO);
3096       n->piter = NULL;
3097       return;
3098     }
3099   if (h == NULL)
3100     return; /* no HELLO available */
3101 #if DEBUG_TRANSPORT
3102   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3103               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3104               "HELLO",
3105               GNUNET_i2s (peer));
3106 #endif
3107   if (GNUNET_YES != n->public_key_valid)
3108     {
3109       GNUNET_HELLO_get_key (h, &n->publicKey);
3110       n->public_key_valid = GNUNET_YES;
3111     }
3112   GNUNET_HELLO_iterate_addresses (h,
3113                                   GNUNET_NO,
3114                                   &add_to_foreign_address_list,
3115                                   n);
3116 }
3117
3118
3119 /**
3120  * Create a fresh entry in our neighbour list for the given peer.
3121  * Will try to transmit our current HELLO to the new neighbour.
3122  * Do not call this function directly, use 'setup_peer_check_blacklist.
3123  *
3124  * @param peer the peer for which we create the entry
3125  * @param do_hello should we schedule transmitting a HELLO
3126  * @return the new neighbour list entry
3127  */
3128 static struct NeighbourList *
3129 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3130                      int do_hello)
3131 {
3132   struct NeighbourList *n;
3133   struct TransportPlugin *tp;
3134   struct ReadyList *rl;
3135
3136   GNUNET_assert (0 != memcmp (peer,
3137                               &my_identity,
3138                               sizeof (struct GNUNET_PeerIdentity)));
3139 #if DEBUG_TRANSPORT
3140   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3141               "Setting up state for neighbour `%4s'\n",
3142               GNUNET_i2s (peer));
3143 #endif
3144   GNUNET_STATISTICS_update (stats,
3145                             gettext_noop ("# active neighbours"),
3146                             1,
3147                             GNUNET_NO);
3148   n = GNUNET_malloc (sizeof (struct NeighbourList));
3149   n->next = neighbours;
3150   neighbours = n;
3151   n->id = *peer;
3152   n->peer_timeout =
3153     GNUNET_TIME_relative_to_absolute
3154     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3155   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3156                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3157                                  MAX_BANDWIDTH_CARRY_S);
3158   tp = plugins;
3159   while (tp != NULL)
3160     {
3161       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3162         {
3163           rl = GNUNET_malloc (sizeof (struct ReadyList));
3164           rl->neighbour = n;
3165           rl->next = n->plugins;
3166           n->plugins = rl;
3167           rl->plugin = tp;
3168           rl->addresses = NULL;
3169         }
3170       tp = tp->next;
3171     }
3172   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3173   n->distance = -1;
3174   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3175                                                   &neighbour_timeout_task, n);
3176   if (do_hello)
3177     {
3178       GNUNET_STATISTICS_update (stats,
3179                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3180                                 1,
3181                                 GNUNET_NO);
3182       GNUNET_STATISTICS_update (stats,
3183                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3184                                 1,
3185                                 GNUNET_NO);
3186       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3187                                           GNUNET_TIME_UNIT_FOREVER_REL,
3188                                           &add_hello_for_peer, n);
3189
3190       GNUNET_STATISTICS_update (stats,
3191                                 gettext_noop ("# HELLO's sent to new neighbors"),
3192                                 1,
3193                                 GNUNET_NO);
3194       if (NULL != our_hello)
3195         transmit_to_peer (NULL, NULL, 0,
3196                           HELLO_ADDRESS_EXPIRATION,
3197                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3198                           GNUNET_NO, n);
3199     }
3200   return n;
3201 }
3202
3203
3204 /**
3205  * Function called after we have checked if communicating
3206  * with a given peer is acceptable.
3207  *
3208  * @param cls closure
3209  * @param n NULL if communication is not acceptable
3210  */
3211 typedef void (*SetupContinuation)(void *cls,
3212                                   struct NeighbourList *n);
3213
3214
3215 /**
3216  * Information kept for each client registered to perform
3217  * blacklisting.
3218  */
3219 struct Blacklisters
3220 {
3221   /**
3222    * This is a linked list.
3223    */
3224   struct Blacklisters *next;
3225
3226   /**
3227    * This is a linked list.
3228    */
3229   struct Blacklisters *prev;
3230
3231   /**
3232    * Client responsible for this entry.
3233    */
3234   struct GNUNET_SERVER_Client *client;
3235
3236   /**
3237    * Blacklist check that we're currently performing.
3238    */
3239   struct BlacklistCheck *bc;
3240
3241 };
3242
3243
3244 /**
3245  * Head of DLL of blacklisting clients.
3246  */
3247 static struct Blacklisters *bl_head;
3248
3249 /**
3250  * Tail of DLL of blacklisting clients.
3251  */
3252 static struct Blacklisters *bl_tail;
3253
3254
3255 /**
3256  * Context we use when performing a blacklist check.
3257  */
3258 struct BlacklistCheck
3259 {
3260
3261   /**
3262    * This is a linked list.
3263    */
3264   struct BlacklistCheck *next;
3265
3266   /**
3267    * This is a linked list.
3268    */
3269   struct BlacklistCheck *prev;
3270
3271   /**
3272    * Peer being checked.
3273    */
3274   struct GNUNET_PeerIdentity peer;
3275
3276   /**
3277    * Option for setup neighbour afterwards.
3278    */
3279   int do_hello;
3280
3281   /**
3282    * Continuation to call with the result.
3283    */
3284   SetupContinuation cont;
3285
3286   /**
3287    * Closure for cont.
3288    */
3289   void *cont_cls;
3290
3291   /**
3292    * Current transmission request handle for this client, or NULL if no
3293    * request is pending.
3294    */
3295   struct GNUNET_CONNECTION_TransmitHandle *th;
3296
3297   /**
3298    * Our current position in the blacklisters list.
3299    */
3300   struct Blacklisters *bl_pos;
3301
3302   /**
3303    * Current task performing the check.
3304    */
3305   GNUNET_SCHEDULER_TaskIdentifier task;
3306
3307 };
3308
3309 /**
3310  * Head of DLL of active blacklisting queries.
3311  */
3312 static struct BlacklistCheck *bc_head;
3313
3314 /**
3315  * Tail of DLL of active blacklisting queries.
3316  */
3317 static struct BlacklistCheck *bc_tail;
3318
3319
3320 /**
3321  * Perform next action in the blacklist check.
3322  *
3323  * @param cls the 'struct BlacklistCheck*'
3324  * @param tc unused
3325  */
3326 static void
3327 do_blacklist_check (void *cls,
3328                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3329
3330 /**
3331  * Transmit blacklist query to the client.
3332  *
3333  * @param cls the 'struct BlacklistCheck'
3334  * @param size number of bytes allowed
3335  * @param buf where to copy the message
3336  * @return number of bytes copied to buf
3337  */
3338 static size_t
3339 transmit_blacklist_message (void *cls,
3340                             size_t size,
3341                             void *buf)
3342 {
3343   struct BlacklistCheck *bc = cls;
3344   struct Blacklisters *bl;
3345   struct BlacklistMessage bm;
3346
3347   bc->th = NULL;
3348   if (size == 0)
3349     {
3350       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3351       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3352                                            bc);
3353       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3354                   "Failed to send blacklist test for peer `%s' to client\n",
3355                   GNUNET_i2s (&bc->peer));
3356       return 0;
3357     }
3358 #if DEBUG_TRANSPORT
3359   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3360               "Sending blacklist test for peer `%s' to client\n",
3361               GNUNET_i2s (&bc->peer));
3362 #endif
3363   bl = bc->bl_pos;
3364   bm.header.size = htons (sizeof (struct BlacklistMessage));
3365   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3366   bm.is_allowed = htonl (0);
3367   bm.peer = bc->peer;
3368   memcpy (buf, &bm, sizeof (bm));
3369   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3370   return sizeof (bm);
3371 }
3372
3373
3374 /**
3375  * Perform next action in the blacklist check.
3376  *
3377  * @param cls the 'struct BlacklistCheck*'
3378  * @param tc unused
3379  */
3380 static void
3381 do_blacklist_check (void *cls,
3382                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3383 {
3384   struct BlacklistCheck *bc = cls;
3385   struct Blacklisters *bl;
3386
3387   bc->task = GNUNET_SCHEDULER_NO_TASK;
3388   bl = bc->bl_pos;
3389   if (bl == NULL)
3390     {
3391 #if DEBUG_TRANSPORT
3392       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3393                   "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3394                   GNUNET_i2s (&bc->peer));
3395 #endif
3396       bc->cont (bc->cont_cls,
3397                 setup_new_neighbour (&bc->peer, bc->do_hello));
3398       GNUNET_free (bc);
3399       return;
3400     }
3401   if (bl->bc == NULL)
3402     {
3403       bl->bc = bc;
3404       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3405                                                     sizeof (struct BlacklistMessage),
3406                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3407                                                     &transmit_blacklist_message,
3408                                                     bc);
3409     }
3410 }
3411
3412
3413 /**
3414  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3415  * does not yet exist, check the blacklist.  If the blacklist says creating
3416  * one is acceptable, create one and call the continuation; otherwise
3417  * call the continuation with NULL.
3418  *
3419  * @param peer peer to setup or look up a struct NeighbourList for
3420  * @param do_hello should we also schedule sending our HELLO to the peer
3421  *        if this is a new record
3422  * @param cont function to call with the 'struct NeigbhbourList*'
3423  * @param cont_cls closure for cont
3424  */
3425 static void
3426 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3427                             int do_hello,
3428                             SetupContinuation cont,
3429                             void *cont_cls)
3430 {
3431   struct NeighbourList *n;
3432   struct BlacklistCheck *bc;
3433
3434   n = find_neighbour(peer);
3435   if (n != NULL)
3436     {
3437 #if DEBUG_TRANSPORT
3438       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
3439                  "Neighbour record exists for peer `%s'\n", 
3440                  GNUNET_i2s(peer));
3441 #endif
3442       if (cont != NULL)
3443         cont (cont_cls, n);
3444       return;
3445     }
3446   if (bl_head == NULL)
3447     {
3448       if (cont != NULL)
3449         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3450       else
3451         setup_new_neighbour(peer, do_hello);
3452       return;
3453     }
3454   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3455   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3456   bc->peer = *peer;
3457   bc->do_hello = do_hello;
3458   bc->cont = cont;
3459   bc->cont_cls = cont_cls;
3460   bc->bl_pos = bl_head;
3461   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3462                                        bc);
3463 }
3464
3465
3466 /**
3467  * Function called with the result of querying a new blacklister about
3468  * it being allowed (or not) to continue to talk to an existing neighbour.
3469  *
3470  * @param cls the original 'struct NeighbourList'
3471  * @param n NULL if we need to disconnect
3472  */
3473 static void
3474 confirm_or_drop_neighbour (void *cls,
3475                            struct NeighbourList *n)
3476 {
3477   struct NeighbourList * orig = cls;
3478
3479   if (n == NULL)
3480     {
3481 #if DEBUG_TRANSPORT
3482       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3483               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3484               "confirm_or_drop_neighboUr");
3485 #endif
3486       GNUNET_STATISTICS_update (stats,
3487                                 gettext_noop ("# disconnects due to blacklist"),
3488                                 1,
3489                                 GNUNET_NO);
3490       disconnect_neighbour (orig, GNUNET_NO);
3491     }
3492 }
3493
3494
3495 /**
3496  * Handle a request to start a blacklist.
3497  *
3498  * @param cls closure (always NULL)
3499  * @param client identification of the client
3500  * @param message the actual message
3501  */
3502 static void
3503 handle_blacklist_init (void *cls,
3504                        struct GNUNET_SERVER_Client *client,
3505                        const struct GNUNET_MessageHeader *message)
3506 {
3507   struct Blacklisters *bl;
3508   struct BlacklistCheck *bc;
3509   struct NeighbourList *n;
3510
3511   bl = bl_head;
3512   while (bl != NULL)
3513     {
3514       if (bl->client == client)
3515         {
3516           GNUNET_break (0);
3517           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3518           return;
3519         }
3520       bl = bl->next;
3521     }
3522   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3523   bl->client = client;
3524   GNUNET_SERVER_client_keep (client);
3525   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3526   /* confirm that all existing connections are OK! */
3527   n = neighbours;
3528   while (NULL != n)
3529     {
3530       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3531       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3532       bc->peer = n->id;
3533       bc->do_hello = GNUNET_NO;
3534       bc->cont = &confirm_or_drop_neighbour;
3535       bc->cont_cls = n;
3536       bc->bl_pos = bl;
3537       if (n == neighbours) /* all would wait for the same client, no need to
3538                               create more than just the first task right now */
3539         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3540                                              bc);
3541       n = n->next;
3542     }
3543 }
3544
3545
3546 /**
3547  * Handle a request to blacklist a peer.
3548  *
3549  * @param cls closure (always NULL)
3550  * @param client identification of the client
3551  * @param message the actual message
3552  */
3553 static void
3554 handle_blacklist_reply (void *cls,
3555                         struct GNUNET_SERVER_Client *client,
3556                         const struct GNUNET_MessageHeader *message)
3557 {
3558   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3559   struct Blacklisters *bl;
3560   struct BlacklistCheck *bc;
3561
3562   bl = bl_head;
3563   while ( (bl != NULL) &&
3564           (bl->client != client) )
3565     bl = bl->next;
3566   if (bl == NULL)
3567     {
3568 #if DEBUG_TRANSPORT
3569       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3570                   "Blacklist client disconnected\n");
3571 #endif
3572       /* FIXME: other error handling here!? */
3573       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3574       return;
3575     }
3576   bc = bl->bc;
3577   bl->bc = NULL;
3578   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3579     {
3580 #if DEBUG_TRANSPORT
3581       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3582                   "Blacklist check failed, peer not allowed\n");
3583 #endif
3584       bc->cont (bc->cont_cls, NULL);
3585       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3586       GNUNET_free (bc);
3587     }
3588   else
3589     {
3590 #if DEBUG_TRANSPORT
3591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3592                   "Blacklist check succeeded, continuing with checks\n");
3593 #endif
3594       bc->bl_pos = bc->bl_pos->next;
3595       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3596                                            bc);
3597     }
3598   /* check if any other bc's are waiting for this blacklister */
3599   bc = bc_head;
3600   while (bc != NULL)
3601     {
3602       if ( (bc->bl_pos == bl) &&
3603            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3604         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3605                                              bc);
3606       bc = bc->next;
3607     }
3608 }
3609
3610
3611 /**
3612  * Send periodic PING messages to a given foreign address.
3613  *
3614  * @param cls our 'struct PeriodicValidationContext*'
3615  * @param tc task context
3616  */
3617 static void
3618 send_periodic_ping (void *cls,
3619                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3620 {
3621   struct ForeignAddressList *peer_address = cls;
3622   struct TransportPlugin *tp;
3623   struct ValidationEntry *va;
3624   struct NeighbourList *neighbour;
3625   struct TransportPingMessage ping;
3626   struct CheckAddressExistsClosure caec;
3627   char * message_buf;
3628   uint16_t hello_size;
3629   size_t slen;
3630   size_t tsize;
3631
3632   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3633   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3634     return;
3635   tp = peer_address->ready_list->plugin;
3636   neighbour = peer_address->ready_list->neighbour;
3637   if (GNUNET_YES != neighbour->public_key_valid)
3638     {
3639       /* no public key yet, try again later */
3640       schedule_next_ping (peer_address);
3641       return;
3642     }
3643   caec.addr = peer_address->addr;
3644   caec.addrlen = peer_address->addrlen;
3645   caec.tname = tp->short_name;
3646   caec.session = peer_address->session;
3647   caec.exists = GNUNET_NO;
3648
3649   /* Inbound address, we won't have in validation map! */
3650   if (0 == peer_address->addrlen)
3651     fprintf(stderr, "Sending periodic ping to inbound address!??\n");
3652
3653   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3654                                          &check_address_exists,
3655                                          &caec);
3656   if (caec.exists == GNUNET_YES)
3657     {
3658       /* During validation attempts we will likely trigger the other
3659          peer trying to validate our address which in turn will cause
3660          it to send us its HELLO, so we expect to hit this case rather
3661          frequently.  Only print something if we are very verbose. */
3662 #if DEBUG_TRANSPORT > 1
3663       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3664                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3665                   (peer_address->addr != NULL)
3666                   ? a2s (tp->short_name,
3667                          peer_address->addr,
3668                          peer_address->addrlen)
3669                   : "<inbound>",
3670                   tp->short_name,
3671                   GNUNET_i2s (&neighbour->id));
3672 #endif
3673       schedule_next_ping (peer_address);
3674       return;
3675     }
3676   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3677   va->transport_name = GNUNET_strdup (tp->short_name);
3678   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3679                                             UINT_MAX);
3680   va->send_time = GNUNET_TIME_absolute_get();
3681   va->session = peer_address->session;
3682   if (peer_address->addr != NULL)
3683     {
3684       va->addr = (const void*) &va[1];
3685       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3686       va->addrlen = peer_address->addrlen;
3687     }
3688   memcpy(&va->publicKey,
3689          &neighbour->publicKey,
3690          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3691
3692   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3693                                                    &timeout_hello_validation,
3694                                                    va);
3695   GNUNET_CONTAINER_multihashmap_put (validation_map,
3696                                      &neighbour->id.hashPubKey,
3697                                      va,
3698                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3699
3700   if (peer_address->validated != GNUNET_YES)
3701     hello_size = GNUNET_HELLO_size(our_hello);
3702   else
3703     hello_size = 0;
3704
3705   tsize = sizeof(struct TransportPingMessage) + hello_size;
3706
3707   if (peer_address->addr != NULL)
3708     {
3709       slen = strlen (tp->short_name) + 1;
3710       tsize += slen + peer_address->addrlen;
3711     }
3712   else
3713     {
3714       slen = 0; /* make gcc happy */
3715     }
3716   message_buf = GNUNET_malloc(tsize);
3717   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3718   ping.challenge = htonl(va->challenge);
3719   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3720   if (peer_address->validated != GNUNET_YES)
3721     {
3722       memcpy(message_buf, our_hello, hello_size);
3723     }
3724
3725   if (peer_address->addr != NULL)
3726     {
3727       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3728                                peer_address->addrlen +
3729                                slen);
3730       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3731              tp->short_name,
3732              slen);
3733       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3734              peer_address->addr,
3735              peer_address->addrlen);
3736     }
3737   else
3738     {
3739       ping.header.size = htons(sizeof(struct TransportPingMessage));
3740     }
3741
3742   memcpy(&message_buf[hello_size],
3743          &ping,
3744          sizeof(struct TransportPingMessage));
3745
3746 #if DEBUG_TRANSPORT_REVALIDATION
3747   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3748               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3749               (peer_address->addr != NULL)
3750               ? a2s (peer_address->plugin->short_name,
3751                      peer_address->addr,
3752                      peer_address->addrlen)
3753               : "<inbound>",
3754               tp->short_name,
3755               GNUNET_i2s (&neighbour->id),
3756               "HELLO", hello_size,
3757               "PING");
3758 #endif
3759   if (peer_address->validated != GNUNET_YES)
3760     GNUNET_STATISTICS_update (stats,
3761                               gettext_noop ("# PING with HELLO messages sent"),
3762                               1,
3763                               GNUNET_NO);
3764   else
3765     GNUNET_STATISTICS_update (stats,
3766                               gettext_noop ("# PING without HELLO messages sent"),
3767                               1,
3768                               GNUNET_NO);
3769   GNUNET_STATISTICS_update (stats,
3770                             gettext_noop ("# PING messages sent for re-validation"),
3771                             1,
3772                             GNUNET_NO);
3773   transmit_to_peer (NULL, peer_address,
3774                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3775                     HELLO_VERIFICATION_TIMEOUT,
3776                     message_buf, tsize,
3777                     GNUNET_YES, neighbour);
3778   GNUNET_free(message_buf);
3779   schedule_next_ping (peer_address);
3780 }
3781
3782
3783 /**
3784  * Schedule the job that will cause us to send a PING to the
3785  * foreign address to evaluate its validity and latency.
3786  *
3787  * @param fal address to PING
3788  */
3789 static void
3790 schedule_next_ping (struct ForeignAddressList *fal)
3791 {
3792   struct GNUNET_TIME_Relative delay;
3793
3794   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3795     {
3796       GNUNET_SCHEDULER_cancel(fal->revalidate_task);
3797       fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3798     }
3799   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3800   delay.rel_value /= 2; /* do before expiration */
3801   delay = GNUNET_TIME_relative_min (delay,
3802                                     LATENCY_EVALUATION_MAX_DELAY);
3803   if (GNUNET_YES != fal->estimated)
3804     {
3805       delay = GNUNET_TIME_UNIT_ZERO;
3806       fal->estimated = GNUNET_YES;
3807     }
3808
3809   if (GNUNET_YES == fal->connected)
3810     {
3811       delay = GNUNET_TIME_relative_min (delay,
3812                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3813     }
3814   /* FIXME: also adjust delay based on how close the last
3815      observed latency is to the latency of the best alternative */
3816   /* bound how fast we can go */
3817   delay = GNUNET_TIME_relative_max (delay,
3818                                     GNUNET_TIME_UNIT_SECONDS);
3819   /* randomize a bit (to avoid doing all at the same time) */
3820   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3821   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3822                                                       &send_periodic_ping,
3823                                                       fal);
3824 }
3825
3826
3827
3828
3829 /**
3830  * Function that will be called if we receive some payload
3831  * from another peer.
3832  *
3833  * @param message the payload
3834  * @param n peer who claimed to be the sender
3835  */
3836 static void
3837 handle_payload_message (const struct GNUNET_MessageHeader *message,
3838                         struct NeighbourList *n)
3839 {
3840   struct InboundMessage *im;
3841   struct TransportClient *cpos;
3842   uint16_t msize;
3843
3844   msize = ntohs (message->size);
3845   if (n->received_pong == GNUNET_NO)
3846     {
3847 #if DEBUG_TRANSPORT
3848       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3849                   "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3850                   ntohs (message->type),
3851                   ntohs (message->size),
3852                   GNUNET_i2s (&n->id));
3853 #endif
3854       GNUNET_free_non_null (n->pre_connect_message_buffer);
3855       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3856       memcpy (n->pre_connect_message_buffer, message, msize);
3857       return;
3858     }
3859
3860 #if DEBUG_TRANSPORT
3861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3862               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3863               ntohs (message->type),
3864               ntohs (message->size),
3865               GNUNET_i2s (&n->id));
3866 #endif
3867   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3868                                                       (ssize_t) msize))
3869     {
3870       n->quota_violation_count++;
3871 #if DEBUG_TRANSPORT
3872       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3873                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3874                   n->in_tracker.available_bytes_per_s__,
3875                   n->quota_violation_count);
3876 #endif
3877       /* Discount 32k per violation */
3878       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3879                                         - 32 * 1024);
3880     }
3881   else
3882     {
3883       if (n->quota_violation_count > 0)
3884         {
3885           /* try to add 32k back */
3886           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3887                                             32 * 1024);
3888           n->quota_violation_count--;
3889         }
3890     }
3891   GNUNET_STATISTICS_update (stats,
3892                             gettext_noop ("# payload received from other peers"),
3893                             msize,
3894                             GNUNET_NO);
3895   /* transmit message to all clients */
3896   uint32_t ats_count = 2;
3897   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3898   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3899           GNUNET_break(0);
3900
3901   im = GNUNET_malloc (size);
3902   im->header.size = htons (size);
3903   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3904   im->peer = n->id;
3905   im->ats_count = htonl(ats_count);
3906   /* Setting ATS data */
3907   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3908   (&(im->ats))[0].value = htonl (n->distance);
3909   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3910   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3911   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3912   (&(im->ats))[ats_count].value = htonl (0);
3913
3914   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3915   cpos = clients;
3916   while (cpos != NULL)
3917     {
3918       transmit_to_client (cpos, &im->header, GNUNET_YES);
3919       cpos = cpos->next;
3920     }
3921   GNUNET_free (im);
3922 }
3923
3924
3925 /**
3926  * Iterator over hash map entries.  Checks if the given validation
3927  * entry is for the same challenge as what is given in the PONG.
3928  *
3929  * @param cls the 'struct TransportPongMessage*'
3930  * @param key peer identity
3931  * @param value value in the hash map ('struct ValidationEntry')
3932  * @return GNUNET_YES if we should continue to
3933  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3934  */
3935 static int
3936 check_pending_validation (void *cls,
3937                           const GNUNET_HashCode * key,
3938                           void *value)
3939 {
3940   const struct TransportPongMessage *pong = cls;
3941   struct ValidationEntry *ve = value;
3942   struct AddValidatedAddressContext avac;
3943   unsigned int challenge = ntohl(pong->challenge);
3944   struct GNUNET_HELLO_Message *hello;
3945   struct GNUNET_PeerIdentity target;
3946   struct NeighbourList *n;
3947   struct ForeignAddressList *fal;
3948   struct OwnAddressList *oal;
3949   struct TransportPlugin *tp;
3950   struct GNUNET_MessageHeader *prem;
3951   uint16_t ps;
3952   const char *addr;
3953   size_t slen;
3954   size_t alen;
3955
3956   ps = ntohs (pong->header.size);
3957   if (ps < sizeof (struct TransportPongMessage))
3958     {
3959       GNUNET_break_op (0);
3960       return GNUNET_NO;
3961     }
3962   addr = (const char*) &pong[1];
3963   slen = strlen (ve->transport_name) + 1;
3964   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3965        (ve->challenge != challenge) ||
3966        (addr[slen-1] != '\0') ||
3967        (0 != strcmp (addr, ve->transport_name)) ||
3968        (ntohl (pong->purpose.size)
3969         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3970         sizeof (uint32_t) +
3971         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3972         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3973     {
3974       return GNUNET_YES;
3975     }
3976
3977   alen = ps - sizeof (struct TransportPongMessage) - slen;
3978   switch (ntohl (pong->purpose.purpose))
3979     {
3980     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3981       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3982            (0 != memcmp (&addr[slen],
3983                          ve->addr,
3984                          ve->addrlen)) )
3985         {
3986           return GNUNET_YES; /* different entry, keep trying! */
3987         }
3988       if (0 != memcmp (&pong->pid,
3989                        key,
3990                        sizeof (struct GNUNET_PeerIdentity)))
3991         {
3992           GNUNET_break_op (0);
3993           return GNUNET_NO;
3994         }
3995       if (GNUNET_OK !=
3996           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3997                                     &pong->purpose,
3998                                     &pong->signature,
3999                                     &ve->publicKey))
4000         {
4001           GNUNET_break_op (0);
4002           return GNUNET_NO;
4003         }
4004
4005 #if DEBUG_TRANSPORT
4006       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4007                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4008                   GNUNET_h2s (key),
4009                   a2s (ve->transport_name,
4010                        (const struct sockaddr *) ve->addr,
4011                        ve->addrlen),
4012                   ve->transport_name);
4013 #endif
4014       break;
4015     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4016       if (0 != memcmp (&pong->pid,
4017                          &my_identity,
4018                          sizeof (struct GNUNET_PeerIdentity)))
4019         {
4020           char * peer;
4021
4022           GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4023 #if DEBUG_TRANSPORT
4024           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4025                       "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4026                       GNUNET_i2s (&my_identity), 
4027                       peer );
4028 #endif
4029           GNUNET_free (peer);
4030           return GNUNET_NO;
4031         }
4032       if (ve->addrlen != 0)
4033         {
4034           /* must have been for a different validation entry */
4035           return GNUNET_YES;
4036         }
4037       tp = find_transport (ve->transport_name);
4038       if (tp == NULL)
4039         {
4040           GNUNET_break (0);
4041           return GNUNET_YES;
4042         }
4043       oal = tp->addresses;
4044       while (NULL != oal)
4045         {
4046           if ( (oal->addrlen == alen) &&
4047                (0 == memcmp (&oal[1],
4048                              &addr[slen],
4049                              alen)) )
4050             break;
4051           oal = oal->next;
4052         }
4053       if (oal == NULL)
4054         {
4055           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4056                       _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4057                       GNUNET_i2s (&pong->pid),
4058                       a2s (ve->transport_name,
4059                            &addr[slen],
4060                            alen));
4061           /* FIXME: since the sender of the PONG currently uses the
4062              wrong address (see FIMXE there!), we cannot run a 
4063              proper check here... */
4064 #if FIXME_URGENT
4065           return GNUNET_NO;
4066 #endif
4067         }
4068       if (GNUNET_OK !=
4069           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4070                                     &pong->purpose,
4071                                     &pong->signature,
4072                                     &ve->publicKey))
4073         {
4074           GNUNET_break_op (0);
4075           return GNUNET_NO;
4076         }
4077
4078 #if DEBUG_TRANSPORT
4079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4080                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4081                   GNUNET_h2s (key),
4082                   a2s (ve->transport_name,
4083                        &addr[slen],
4084                        alen),
4085                   ve->transport_name);
4086 #endif
4087       break;
4088     default:
4089       GNUNET_break_op (0);
4090       return GNUNET_NO;
4091     }
4092   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4093     {
4094       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4095                   _("Received expired signature.  Check system time.\n"));
4096       return GNUNET_NO;
4097     }
4098   GNUNET_STATISTICS_update (stats,
4099                             gettext_noop ("# address validation successes"),
4100                             1,
4101                             GNUNET_NO);
4102   /* create the updated HELLO */
4103   GNUNET_CRYPTO_hash (&ve->publicKey,
4104                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4105                       &target.hashPubKey);
4106   if (ve->addr != NULL)
4107     {
4108       avac.done = GNUNET_NO;
4109       avac.ve = ve;
4110       hello = GNUNET_HELLO_create (&ve->publicKey,
4111                                    &add_validated_address,
4112                                    &avac);
4113       GNUNET_PEERINFO_add_peer (peerinfo,
4114                                 hello);
4115       GNUNET_free (hello);
4116     }
4117   n = find_neighbour (&target);
4118   if (n != NULL)
4119     {
4120       n->publicKey = ve->publicKey;
4121       n->public_key_valid = GNUNET_YES;
4122       fal = add_peer_address (n,
4123                               ve->transport_name,
4124                               ve->session,
4125                               ve->addr,
4126                               ve->addrlen);
4127       GNUNET_assert (fal != NULL);
4128       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4129       fal->validated = GNUNET_YES;
4130       mark_address_connected (fal);
4131       GNUNET_STATISTICS_update (stats,
4132                                 gettext_noop ("# peer addresses considered valid"),
4133                                 1,
4134                                 GNUNET_NO);
4135       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4136       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4137
4138       schedule_next_ping (fal);
4139       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4140         n->latency = fal->latency;
4141       else
4142         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4143
4144       n->distance = fal->distance;
4145       if (GNUNET_NO == n->received_pong)
4146         {
4147           n->received_pong = GNUNET_YES;
4148           notify_clients_connect (&target, n->latency, n->distance);
4149           if (NULL != (prem = n->pre_connect_message_buffer))
4150             {
4151               n->pre_connect_message_buffer = NULL;
4152               handle_payload_message (prem, n);
4153               GNUNET_free (prem);
4154             }
4155         }
4156       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4157         {
4158           GNUNET_SCHEDULER_cancel (n->retry_task);
4159           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4160           try_transmission_to_peer (n);
4161         }
4162     }
4163
4164   /* clean up validation entry */
4165   GNUNET_assert (GNUNET_YES ==
4166                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4167                                                        key,
4168                                                        ve));
4169   abort_validation (NULL, NULL, ve);
4170   return GNUNET_NO;
4171 }
4172
4173
4174 /**
4175  * Function that will be called if we receive a validation
4176  * of an address challenge that we transmitted to another
4177  * peer.  Note that the validation should only be considered
4178  * acceptable if the challenge matches AND if the sender
4179  * address is at least a plausible address for this peer
4180  * (otherwise we may be seeing a MiM attack).
4181  *
4182  * @param cls closure
4183  * @param message the pong message
4184  * @param peer who responded to our challenge
4185  * @param sender_address string describing our sender address (as observed
4186  *         by the other peer in binary format)
4187  * @param sender_address_len number of bytes in 'sender_address'
4188  */
4189 static void
4190 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4191              const struct GNUNET_PeerIdentity *peer,
4192              const char *sender_address,
4193              size_t sender_address_len)
4194 {
4195   if (0 == memcmp (peer,
4196                    &my_identity,
4197                    sizeof (struct GNUNET_PeerIdentity)))
4198     {
4199       /* PONG send to self, ignore */
4200       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4201                   "Receiving `%s' message from myself\n", 
4202                   "PONG");
4203       return;
4204     }
4205 #if DEBUG_TRANSPORT > 1
4206   /* we get tons of these that just get discarded, only log
4207      if we are quite verbose */
4208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4209               "Receiving `%s' message from `%4s'.\n", "PONG",
4210               GNUNET_i2s (peer));
4211 #endif
4212   GNUNET_STATISTICS_update (stats,
4213                             gettext_noop ("# PONG messages received"),
4214                             1,
4215                             GNUNET_NO);
4216   if (GNUNET_SYSERR !=
4217       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4218                                                   &peer->hashPubKey,
4219                                                   &check_pending_validation,
4220                                                   (void*) message))
4221     {
4222       /* This is *expected* to happen a lot since we send
4223          PONGs to *all* known addresses of the sender of
4224          the PING, so most likely we get multiple PONGs
4225          per PING, and all but the first PONG will end up
4226          here. So really we should not print anything here
4227          unless we want to be very, very verbose... */
4228 #if DEBUG_TRANSPORT > 2
4229       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4230                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4231                   "PONG",
4232                   GNUNET_i2s (peer),
4233                   "PING");
4234 #endif
4235       return;
4236     }
4237
4238 }
4239
4240
4241 /**
4242  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4243  *
4244  * @param cls the 'struct ValidationEntry*'
4245  * @param neighbour neighbour to validate, NULL if validation failed
4246  */
4247 static void
4248 transmit_hello_and_ping (void *cls,
4249                          struct NeighbourList *neighbour)
4250 {
4251   struct ValidationEntry *va = cls;
4252   struct ForeignAddressList *peer_address;
4253   struct TransportPingMessage ping;
4254   uint16_t hello_size;
4255   size_t tsize;
4256   char * message_buf;
4257   struct GNUNET_PeerIdentity id;
4258   size_t slen;
4259
4260   GNUNET_CRYPTO_hash (&va->publicKey,
4261                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4262                       &id.hashPubKey);
4263   if (neighbour == NULL)
4264     {
4265       /* FIXME: stats... */
4266       GNUNET_break (GNUNET_OK ==
4267                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4268                                                           &id.hashPubKey,
4269                                                           va));
4270       abort_validation (NULL, NULL, va);
4271       return;
4272     }
4273   neighbour->publicKey = va->publicKey;
4274   neighbour->public_key_valid = GNUNET_YES;
4275   peer_address = add_peer_address (neighbour,
4276                                    va->transport_name, NULL,
4277                                    (const void*) &va[1],
4278                                    va->addrlen);
4279   if (peer_address == NULL)
4280     {
4281       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4282                   "Failed to add peer `%4s' for plugin `%s'\n",
4283                   GNUNET_i2s (&neighbour->id),
4284                   va->transport_name);
4285       GNUNET_break (GNUNET_OK ==
4286                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4287                                                           &id.hashPubKey,
4288                                                           va));
4289       abort_validation (NULL, NULL, va);
4290       return;
4291     }
4292   if (NULL == our_hello)
4293     refresh_hello_task (NULL, NULL);
4294   hello_size = GNUNET_HELLO_size(our_hello);
4295   slen = strlen(va->transport_name) + 1;
4296   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4297   message_buf = GNUNET_malloc(tsize);
4298   ping.challenge = htonl(va->challenge);
4299   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4300   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4301   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4302   memcpy(message_buf, our_hello, hello_size);
4303   memcpy(&message_buf[hello_size],
4304          &ping,
4305          sizeof(struct TransportPingMessage));
4306   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4307          va->transport_name,
4308          slen);
4309   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4310          &va[1],
4311          va->addrlen);
4312 #if DEBUG_TRANSPORT
4313   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4314               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4315               (va->addrlen == 0)
4316               ? "<inbound>"
4317               : a2s (va->transport_name,
4318                      (const void*) &va[1], va->addrlen),
4319               va->transport_name,
4320               GNUNET_i2s (&neighbour->id),
4321               "HELLO", hello_size,
4322               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4323 #endif
4324
4325   GNUNET_STATISTICS_update (stats,
4326                             gettext_noop ("# PING messages sent for initial validation"),
4327                             1,
4328                             GNUNET_NO);
4329   transmit_to_peer (NULL, peer_address,
4330                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4331                     HELLO_VERIFICATION_TIMEOUT,
4332                     message_buf, tsize,
4333                     GNUNET_YES, neighbour);
4334   GNUNET_free(message_buf);
4335 }
4336
4337
4338 /**
4339  * Check if the given address is already being validated; if not,
4340  * append the given address to the list of entries that are being be
4341  * validated and initiate validation.
4342  *
4343  * @param cls closure ('struct CheckHelloValidatedContext *')
4344  * @param tname name of the transport
4345  * @param expiration expiration time
4346  * @param addr the address
4347  * @param addrlen length of the address
4348  * @return GNUNET_OK (always)
4349  */
4350 static int
4351 run_validation (void *cls,
4352                 const char *tname,
4353                 struct GNUNET_TIME_Absolute expiration,
4354                 const void *addr,
4355                 uint16_t addrlen)
4356 {
4357   struct CheckHelloValidatedContext *chvc = cls;
4358   struct GNUNET_PeerIdentity id;
4359   struct TransportPlugin *tp;
4360   struct ValidationEntry *va;
4361   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4362   struct CheckAddressExistsClosure caec;
4363   struct OwnAddressList *oal;
4364
4365   GNUNET_assert (addr != NULL);
4366
4367   GNUNET_STATISTICS_update (stats,
4368                             gettext_noop ("# peer addresses scheduled for validation"),
4369                             1,
4370                             GNUNET_NO);
4371   tp = find_transport (tname);
4372   if (tp == NULL)
4373     {
4374       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4375                   GNUNET_ERROR_TYPE_BULK,
4376                   _
4377                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4378                   tname);
4379       GNUNET_STATISTICS_update (stats,
4380                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4381                                 1,
4382                                 GNUNET_NO);
4383       return GNUNET_OK;
4384     }
4385   /* check if this is one of our own addresses */
4386   oal = tp->addresses;
4387   while (NULL != oal)
4388     {
4389       if ( (oal->addrlen == addrlen) &&
4390            (0 == memcmp (&oal[1],
4391                          addr,
4392                          addrlen)) )
4393         {
4394           /* not plausible, this address is equivalent to our own address! */
4395           GNUNET_STATISTICS_update (stats,
4396                                     gettext_noop ("# peer addresses not validated (loopback)"),
4397                                     1,
4398                                     GNUNET_NO);
4399           return GNUNET_OK;
4400         }
4401       oal = oal->next;
4402     }
4403   GNUNET_HELLO_get_key (chvc->hello, &pk);
4404   GNUNET_CRYPTO_hash (&pk,
4405                       sizeof (struct
4406                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4407                       &id.hashPubKey);
4408
4409   if (is_blacklisted(&id, tp))
4410     {
4411 #if DEBUG_TRANSPORT
4412       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4413                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4414                   GNUNET_i2s(&id),
4415                   tname);
4416 #endif
4417       return GNUNET_OK;
4418     }
4419
4420   caec.addr = addr;
4421   caec.addrlen = addrlen;
4422   caec.session = NULL;
4423   caec.tname = tname;
4424   caec.exists = GNUNET_NO;
4425   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4426                                          &check_address_exists,
4427                                          &caec);
4428   if (caec.exists == GNUNET_YES)
4429     {
4430       /* During validation attempts we will likely trigger the other
4431          peer trying to validate our address which in turn will cause
4432          it to send us its HELLO, so we expect to hit this case rather
4433          frequently.  Only print something if we are very verbose. */
4434 #if DEBUG_TRANSPORT > 1
4435       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4436                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4437                   a2s (tname, addr, addrlen),
4438                   tname,
4439                   GNUNET_i2s (&id));
4440 #endif
4441       GNUNET_STATISTICS_update (stats,
4442                                 gettext_noop ("# peer addresses not validated (in progress)"),
4443                                 1,
4444                                 GNUNET_NO);
4445       return GNUNET_OK;
4446     }
4447   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4448   va->chvc = chvc;
4449   chvc->ve_count++;
4450   va->transport_name = GNUNET_strdup (tname);
4451   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4452                                             UINT_MAX);
4453   va->send_time = GNUNET_TIME_absolute_get();
4454   va->addr = (const void*) &va[1];
4455   memcpy (&va[1], addr, addrlen);
4456   va->addrlen = addrlen;
4457   GNUNET_HELLO_get_key (chvc->hello,
4458                         &va->publicKey);
4459   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4460                                                    &timeout_hello_validation,
4461                                                    va);
4462   GNUNET_CONTAINER_multihashmap_put (validation_map,
4463                                      &id.hashPubKey,
4464                                      va,
4465                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4466   setup_peer_check_blacklist (&id, GNUNET_NO,
4467                               &transmit_hello_and_ping,
4468                               va);
4469   return GNUNET_OK;
4470 }
4471
4472
4473 /**
4474  * Check if addresses in validated hello "h" overlap with
4475  * those in "chvc->hello" and validate the rest.
4476  *
4477  * @param cls closure
4478  * @param peer id of the peer, NULL for last call
4479  * @param h hello message for the peer (can be NULL)
4480  * @param err_msg NULL if successful, otherwise contains error message
4481  */
4482 static void
4483 check_hello_validated (void *cls,
4484                        const struct GNUNET_PeerIdentity *peer,
4485                        const struct GNUNET_HELLO_Message *h,
4486                        const char *err_msg)
4487 {
4488   struct CheckHelloValidatedContext *chvc = cls;
4489   struct GNUNET_HELLO_Message *plain_hello;
4490   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4491   struct GNUNET_PeerIdentity target;
4492   struct NeighbourList *n;
4493
4494   if (err_msg != NULL)
4495     {
4496 #if DEBUG_TRANSPORT
4497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4498                   _("Error in communication with PEERINFO service: %s\n"),
4499                   err_msg);
4500 #endif
4501       /* return; */
4502   }
4503
4504   if (peer == NULL)
4505     {
4506       GNUNET_STATISTICS_update (stats,
4507                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4508                                 -1,
4509                                 GNUNET_NO);
4510       chvc->piter = NULL;
4511       if (GNUNET_NO == chvc->hello_known)
4512         {
4513           /* notify PEERINFO about the peer now, so that we at least
4514              have the public key if some other component needs it */
4515           GNUNET_HELLO_get_key (chvc->hello, &pk);
4516           GNUNET_CRYPTO_hash (&pk,
4517                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4518                               &target.hashPubKey);
4519           plain_hello = GNUNET_HELLO_create (&pk,
4520                                              NULL,
4521                                              NULL);
4522           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4523           GNUNET_free (plain_hello);
4524 #if DEBUG_TRANSPORT_HELLO
4525           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4526                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4527                       "HELLO",
4528                       GNUNET_i2s (&target));
4529 #endif
4530           GNUNET_STATISTICS_update (stats,
4531                                     gettext_noop ("# new HELLOs requiring full validation"),
4532                                     1,
4533                                     GNUNET_NO);
4534           GNUNET_HELLO_iterate_addresses (chvc->hello,
4535                                           GNUNET_NO,
4536                                           &run_validation,
4537                                           chvc);
4538         }
4539       else
4540         {
4541           GNUNET_STATISTICS_update (stats,
4542                                     gettext_noop ("# duplicate HELLO (peer known)"),
4543                                     1,
4544                                     GNUNET_NO);
4545         }
4546       chvc->ve_count--;
4547       if (chvc->ve_count == 0)
4548         {
4549           GNUNET_CONTAINER_DLL_remove (chvc_head,
4550                                        chvc_tail,
4551                                        chvc);
4552           GNUNET_free (chvc);
4553         }
4554       return;
4555     }
4556   if (h == NULL)
4557     return;
4558 #if DEBUG_TRANSPORT_HELLO
4559   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4560               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4561               "HELLO",
4562               GNUNET_i2s (peer));
4563 #endif
4564   chvc->hello_known = GNUNET_YES;
4565   n = find_neighbour (peer);
4566   if (n != NULL)
4567     {
4568 #if DEBUG_TRANSPORT_HELLO
4569       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4570                   "Calling hello_iterate_addresses for %s!\n",
4571                   GNUNET_i2s (peer));
4572 #endif
4573       GNUNET_HELLO_iterate_addresses (h,
4574                                       GNUNET_NO,
4575                                       &add_to_foreign_address_list,
4576                                       n);
4577       try_transmission_to_peer (n);
4578     }
4579   else
4580     {
4581 #if DEBUG_TRANSPORT_HELLO
4582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4583                   "No existing neighbor record for %s!\n",
4584                   GNUNET_i2s (peer));
4585 #endif
4586       GNUNET_STATISTICS_update (stats,
4587                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4588                                 1,
4589                                 GNUNET_NO);
4590     }
4591   GNUNET_STATISTICS_update (stats,
4592                             gettext_noop ("# HELLO validations (update case)"),
4593                             1,
4594                             GNUNET_NO);
4595   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4596                                       h,
4597                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4598                                       &run_validation,
4599                                       chvc);
4600 }
4601
4602
4603 /**
4604  * Process HELLO-message.
4605  *
4606  * @param plugin transport involved, may be NULL
4607  * @param message the actual message
4608  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4609  */
4610 static int
4611 process_hello (struct TransportPlugin *plugin,
4612                const struct GNUNET_MessageHeader *message)
4613 {
4614   uint16_t hsize;
4615   struct GNUNET_PeerIdentity target;
4616   const struct GNUNET_HELLO_Message *hello;
4617   struct CheckHelloValidatedContext *chvc;
4618   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4619   struct NeighbourList *n;
4620 #if DEBUG_TRANSPORT_HELLO > 2
4621   char *my_id;
4622 #endif
4623
4624   hsize = ntohs (message->size);
4625   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4626       (hsize < sizeof (struct GNUNET_MessageHeader)))
4627     {
4628       GNUNET_break (0);
4629       return GNUNET_SYSERR;
4630     }
4631   GNUNET_STATISTICS_update (stats,
4632                             gettext_noop ("# HELLOs received for validation"),
4633                             1,
4634                             GNUNET_NO);
4635
4636   hello = (const struct GNUNET_HELLO_Message *) message;
4637   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4638     {
4639 #if DEBUG_TRANSPORT_HELLO
4640       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4641                   "Unable to get public key from `%s' for `%4s'!\n",
4642                   "HELLO",
4643                   GNUNET_i2s (&target));
4644 #endif
4645       GNUNET_break_op (0);
4646       return GNUNET_SYSERR;
4647     }
4648   GNUNET_CRYPTO_hash (&publicKey,
4649                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4650                       &target.hashPubKey);
4651
4652 #if DEBUG_TRANSPORT_HELLO
4653   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4654               "Received `%s' message for `%4s'\n",
4655               "HELLO",
4656               GNUNET_i2s (&target));
4657 #endif
4658   if (0 == memcmp (&my_identity,
4659                    &target,
4660                    sizeof (struct GNUNET_PeerIdentity)))
4661     {
4662       GNUNET_STATISTICS_update (stats,
4663                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4664                                 1,
4665                                 GNUNET_NO);
4666       return GNUNET_OK;
4667     }
4668   n = find_neighbour (&target);
4669   if ( (NULL != n) &&
4670        (! n->public_key_valid) )
4671     {
4672       GNUNET_HELLO_get_key (hello, &n->publicKey);
4673       n->public_key_valid = GNUNET_YES;
4674     }
4675
4676   /* check if load is too high before doing expensive stuff */
4677   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4678     {
4679       GNUNET_STATISTICS_update (stats,
4680                                 gettext_noop ("# HELLOs ignored due to high load"),
4681                                 1,
4682                                 GNUNET_NO);
4683 #if DEBUG_TRANSPORT_HELLO
4684       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4685                   "Ignoring `%s' for `%4s', load too high.\n",
4686                   "HELLO",
4687                   GNUNET_i2s (&target));
4688 #endif
4689       return GNUNET_OK;
4690     }
4691
4692
4693   chvc = chvc_head;
4694   while (NULL != chvc)
4695     {
4696       if (GNUNET_HELLO_equals (hello,
4697                                chvc->hello,
4698                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4699         {
4700 #if DEBUG_TRANSPORT_HELLO > 2
4701           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4702                       "Received duplicate `%s' message for `%4s'; ignored\n",
4703                       "HELLO",
4704                       GNUNET_i2s (&target));
4705 #endif
4706           return GNUNET_OK; /* validation already pending */
4707         }
4708       if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4709         GNUNET_break (0 != memcmp (hello, chvc->hello,
4710                                    GNUNET_HELLO_size(hello)));
4711       chvc = chvc->next;
4712     }
4713
4714 #if BREAK_TESTS
4715   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4716   if ((NULL != temp_neighbor))
4717     {
4718       fprintf(stderr, "Already know peer, ignoring hello\n");
4719       return GNUNET_OK;
4720     }
4721 #endif
4722
4723 #if DEBUG_TRANSPORT_HELLO > 2
4724   if (plugin != NULL)
4725     {
4726       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4727 #if DEBUG_TRANSPORT
4728       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4729                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4730                   my_id,
4731                   "HELLO",
4732                   GNUNET_i2s (&target),
4733                   plugin->short_name,
4734                   GNUNET_HELLO_size(hello));
4735 #endif
4736       GNUNET_free(my_id);
4737     }
4738 #endif
4739   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4740   chvc->ve_count = 1;
4741   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4742   memcpy (&chvc[1], hello, hsize);
4743   GNUNET_CONTAINER_DLL_insert (chvc_head,
4744                                chvc_tail,
4745                                chvc);
4746   /* finally, check if HELLO was previously validated
4747      (continuation will then schedule actual validation) */
4748   GNUNET_STATISTICS_update (stats,
4749                             gettext_noop ("# peerinfo process hello iterate requests"),
4750                             1,
4751                             GNUNET_NO);
4752   GNUNET_STATISTICS_update (stats,
4753                             gettext_noop ("# outstanding peerinfo iterate requests"),
4754                             1,
4755                             GNUNET_NO);
4756   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4757                                          &target,
4758                                          HELLO_VERIFICATION_TIMEOUT,
4759                                          &check_hello_validated, chvc);
4760   return GNUNET_OK;
4761 }
4762
4763
4764 /**
4765  * The peer specified by the given neighbour has timed-out or a plugin
4766  * has disconnected.  We may either need to do nothing (other plugins
4767  * still up), or trigger a full disconnect and clean up.  This
4768  * function updates our state and does the necessary notifications.
4769  * Also notifies our clients that the neighbour is now officially
4770  * gone.
4771  *
4772  * @param n the neighbour list entry for the peer
4773  * @param check GNUNET_YES to check if ALL addresses for this peer
4774  *              are gone, GNUNET_NO to force a disconnect of the peer
4775  *              regardless of whether other addresses exist.
4776  */
4777 static void
4778 disconnect_neighbour (struct NeighbourList *n, int check)
4779 {
4780   struct ReadyList *rpos;
4781   struct NeighbourList *npos;
4782   struct NeighbourList *nprev;
4783   struct MessageQueue *mq;
4784   struct ForeignAddressList *peer_addresses;
4785   struct ForeignAddressList *peer_pos;
4786
4787   if (GNUNET_YES == check)
4788     {
4789       rpos = n->plugins;
4790       while (NULL != rpos)
4791         {
4792           peer_addresses = rpos->addresses;
4793           while (peer_addresses != NULL)
4794             {
4795               // Do not disconnect if: an address is connected or an inbound address exists
4796               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4797                 {
4798 #if DEBUG_TRANSPORT
4799                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4800                               "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4801                               GNUNET_i2s (&n->id),
4802                               a2s (peer_addresses->ready_list->plugin->short_name,
4803                                    peer_addresses->addr,
4804                                    peer_addresses->addrlen));
4805 #endif
4806                   return;             /* still connected */
4807                 }
4808               peer_addresses = peer_addresses->next;
4809             }
4810           rpos = rpos->next;
4811         }
4812     }
4813 #if DEBUG_TRANSPORT
4814   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4815               "Disconnecting from `%4s'\n",
4816               GNUNET_i2s (&n->id));
4817 #endif
4818
4819   /* remove n from neighbours list */
4820   nprev = NULL;
4821   npos = neighbours;
4822   while ((npos != NULL) && (npos != n))
4823     {
4824       nprev = npos;
4825       npos = npos->next;
4826     }
4827   GNUNET_assert (npos != NULL);
4828   if (nprev == NULL)
4829     neighbours = n->next;
4830   else
4831     nprev->next = n->next;
4832
4833   /* notify all clients about disconnect */
4834   if (GNUNET_YES == n->received_pong)
4835     notify_clients_disconnect (&n->id);
4836
4837   ats_modify_problem_state(ats, ATS_MODIFIED);
4838
4839   /* clean up all plugins, cancel connections and pending transmissions */
4840   while (NULL != (rpos = n->plugins))
4841     {
4842       n->plugins = rpos->next;
4843       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4844       while (rpos->addresses != NULL)
4845         {
4846           peer_pos = rpos->addresses;
4847           rpos->addresses = peer_pos->next;
4848           if (peer_pos->connected == GNUNET_YES)
4849             GNUNET_STATISTICS_update (stats,
4850                                       gettext_noop ("# connected addresses"),
4851                                       -1,
4852                                       GNUNET_NO);
4853           if (GNUNET_YES == peer_pos->validated)
4854             GNUNET_STATISTICS_update (stats,
4855                                       gettext_noop ("# peer addresses considered valid"),
4856                                       -1,
4857                                       GNUNET_NO);
4858           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4859             {
4860               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4861               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4862             }
4863           GNUNET_free(peer_pos->ressources);
4864           peer_pos->ressources = NULL;
4865           GNUNET_free(peer_pos->quality);
4866           peer_pos->ressources = NULL;
4867           GNUNET_free(peer_pos);
4868         }
4869       GNUNET_free (rpos);
4870     }
4871
4872   /* free all messages on the queue */
4873   while (NULL != (mq = n->messages_head))
4874     {
4875       GNUNET_STATISTICS_update (stats,
4876                                 gettext_noop ("# bytes in message queue for other peers"),
4877                                 - (int64_t) mq->message_buf_size,
4878                                 GNUNET_NO);
4879       GNUNET_STATISTICS_update (stats,
4880                                 gettext_noop ("# bytes discarded due to disconnect"),
4881                                 mq->message_buf_size,
4882                                 GNUNET_NO);
4883       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4884                                    n->messages_tail,
4885                                    mq);
4886       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4887                                  &n->id,
4888                                  sizeof(struct GNUNET_PeerIdentity)));
4889       GNUNET_free (mq);
4890     }
4891
4892   while (NULL != (mq = n->cont_head))
4893     {
4894
4895       GNUNET_CONTAINER_DLL_remove (n->cont_head,
4896                                    n->cont_tail,
4897                                    mq);
4898       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4899                                  &n->id,
4900                                  sizeof(struct GNUNET_PeerIdentity)));
4901       GNUNET_free (mq);
4902     }
4903
4904   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4905     {
4906       GNUNET_SCHEDULER_cancel (n->timeout_task);
4907       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4908     }
4909   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4910     {
4911       GNUNET_SCHEDULER_cancel (n->retry_task);
4912       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4913     }
4914   if (n->piter != NULL)
4915     {
4916       GNUNET_PEERINFO_iterate_cancel (n->piter);
4917       GNUNET_STATISTICS_update (stats,
4918                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4919                                 -1,
4920                                 GNUNET_NO);
4921       n->piter = NULL;
4922     }
4923   /* finally, free n itself */
4924   GNUNET_STATISTICS_update (stats,
4925                             gettext_noop ("# active neighbours"),
4926                             -1,
4927                             GNUNET_NO);
4928   GNUNET_free_non_null (n->pre_connect_message_buffer);
4929   GNUNET_free (n);
4930 }
4931
4932
4933 /**
4934  * We have received a PING message from someone.  Need to send a PONG message
4935  * in response to the peer by any means necessary.
4936  */
4937 static int
4938 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4939              const struct GNUNET_PeerIdentity *peer,
4940              struct Session *session,
4941              const char *sender_address,
4942              uint16_t sender_address_len)
4943 {
4944   struct TransportPlugin *plugin = cls;
4945   struct SessionHeader *session_header = (struct SessionHeader*) session;
4946   struct TransportPingMessage *ping;
4947   struct TransportPongMessage *pong;
4948   struct NeighbourList *n;
4949   struct ReadyList *rl;
4950   struct ForeignAddressList *fal;
4951   struct OwnAddressList *oal;
4952   const char *addr;
4953   size_t alen;
4954   size_t slen;
4955   int did_pong;
4956
4957   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4958     {
4959       GNUNET_break_op (0);
4960       return GNUNET_SYSERR;
4961     }
4962
4963   ping = (struct TransportPingMessage *) message;
4964   if (0 != memcmp (&ping->target,
4965                    plugin->env.my_identity,
4966                    sizeof (struct GNUNET_PeerIdentity)))
4967     {
4968 #if DEBUG_TRANSPORT
4969       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4970                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4971                   "PING",
4972                   (sender_address != NULL)
4973                   ? a2s (plugin->short_name,
4974                          (const struct sockaddr *)sender_address,
4975                          sender_address_len)
4976                   : "<inbound>",
4977                   GNUNET_i2s (&ping->target));
4978 #endif
4979       return GNUNET_SYSERR;
4980     }
4981 #if DEBUG_PING_PONG
4982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4983               "Processing `%s' from `%s'\n",
4984               "PING",
4985               (sender_address != NULL)
4986               ? a2s (plugin->short_name,
4987                      (const struct sockaddr *)sender_address,
4988                      sender_address_len)
4989               : "<inbound>");
4990 #endif
4991   GNUNET_STATISTICS_update (stats,
4992                             gettext_noop ("# PING messages received"),
4993                             1,
4994                             GNUNET_NO);
4995   addr = (const char*) &ping[1];
4996   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4997   slen = strlen (plugin->short_name) + 1;
4998   if (alen == 0)
4999     {
5000       /* peer wants to confirm that we have an outbound connection to him */
5001       if (session == NULL)
5002         {
5003           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5004                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5005                       GNUNET_i2s (peer));
5006           return GNUNET_SYSERR;
5007         }
5008       /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5009         1) it is NULL when we need to have a real value
5010         2) it is documented to be the address of the sender (source-IP), where
5011         what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5012         have...
5013       */
5014       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5015                   "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5016                   a2s (plugin->short_name,
5017                        sender_address,
5018                        sender_address_len),                    
5019                   GNUNET_i2s (peer));
5020
5021       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5022       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5023       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5024       pong->purpose.size =
5025         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5026                sizeof (uint32_t) +
5027                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5028                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5029       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5030       pong->challenge = ping->challenge;
5031       pong->addrlen = htonl(sender_address_len + slen);
5032       memcpy(&pong->pid,
5033              peer,
5034              sizeof(struct GNUNET_PeerIdentity));
5035       memcpy (&pong[1],
5036               plugin->short_name,
5037               slen);
5038       if ((sender_address!=NULL) && (sender_address_len > 0))
5039                   memcpy (&((char*)&pong[1])[slen],
5040                           sender_address,
5041                           sender_address_len);
5042       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5043         {
5044           /* create / update cached sig */
5045 #if DEBUG_TRANSPORT
5046           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5047                       "Creating PONG signature to indicate active connection.\n");
5048 #endif
5049           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5050           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5051           GNUNET_assert (GNUNET_OK ==
5052                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5053                                                  &pong->purpose,
5054                                                  &session_header->pong_signature));
5055         }
5056       else
5057         {
5058           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5059         }
5060       memcpy (&pong->signature,
5061               &session_header->pong_signature,
5062               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5063
5064
5065     }
5066   else
5067     {
5068       /* peer wants to confirm that this is one of our addresses */
5069       addr += slen;
5070       alen -= slen;
5071       if (GNUNET_OK !=
5072           plugin->api->check_address (plugin->api->cls,
5073                                       addr,
5074                                       alen))
5075         {
5076           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5077                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5078                       a2s (plugin->short_name,
5079                            addr,
5080                            alen));
5081           return GNUNET_NO;
5082         }
5083       oal = plugin->addresses;
5084       while (NULL != oal)
5085         {
5086           if ( (oal->addrlen == alen) &&
5087                (0 == memcmp (addr,
5088                              &oal[1],
5089                              alen)) )
5090             break;
5091           oal = oal->next;
5092         }
5093       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5094       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5095       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5096       pong->purpose.size =
5097         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5098                sizeof (uint32_t) +
5099                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5100                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5101       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5102       pong->challenge = ping->challenge;
5103       pong->addrlen = htonl(alen + slen);
5104       memcpy(&pong->pid,
5105              &my_identity,
5106              sizeof(struct GNUNET_PeerIdentity));
5107       memcpy (&pong[1], plugin->short_name, slen);
5108       memcpy (&((char*)&pong[1])[slen], addr, alen);
5109       if ( (oal != NULL) &&
5110            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5111         {
5112           /* create / update cached sig */
5113 #if DEBUG_TRANSPORT
5114           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5115                       "Creating PONG signature to indicate ownership.\n");
5116 #endif
5117           oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5118           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5119           GNUNET_assert (GNUNET_OK ==
5120                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5121                                                  &pong->purpose,
5122                                                  &oal->pong_signature));
5123           memcpy (&pong->signature,
5124                   &oal->pong_signature,
5125                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5126         }
5127       else if (oal == NULL)
5128         {
5129           /* not using cache (typically DV-only) */
5130           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5131           GNUNET_assert (GNUNET_OK ==
5132                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5133                                                  &pong->purpose,
5134                                                  &pong->signature));
5135         }
5136       else
5137         {
5138           /* can used cached version */
5139           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5140           memcpy (&pong->signature,
5141                   &oal->pong_signature,
5142                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5143         }
5144     }
5145   n = find_neighbour(peer);
5146   GNUNET_assert (n != NULL);
5147   did_pong = GNUNET_NO;
5148   /* first try reliable response transmission */
5149   rl = n->plugins;
5150   while (rl != NULL)
5151     {
5152       fal = rl->addresses;
5153       while (fal != NULL)
5154         {
5155           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5156                                            peer,
5157                                            (const char*) pong,
5158                                            ntohs (pong->header.size),
5159                                            TRANSPORT_PONG_PRIORITY,
5160                                            HELLO_VERIFICATION_TIMEOUT,
5161                                            fal->session,
5162                                            fal->addr,
5163                                            fal->addrlen,
5164                                            GNUNET_SYSERR,
5165                                            NULL, NULL))
5166             {
5167               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5168                           "Transmitted PONG to `%s' via reliable mechanism\n",
5169                           GNUNET_i2s (peer));
5170               /* done! */
5171               GNUNET_STATISTICS_update (stats,
5172                                         gettext_noop ("# PONGs unicast via reliable transport"),
5173                                         1,
5174                                         GNUNET_NO);
5175               GNUNET_free (pong);
5176               return GNUNET_OK;
5177             }
5178           did_pong = GNUNET_YES;
5179           fal = fal->next;
5180         }
5181       rl = rl->next;
5182     }
5183   /* no reliable method found, do multicast */
5184   GNUNET_STATISTICS_update (stats,
5185                             gettext_noop ("# PONGs multicast to all available addresses"),
5186                             1,
5187                             GNUNET_NO);
5188   rl = n->plugins;
5189   while (rl != NULL)
5190     {
5191       fal = rl->addresses;
5192       while (fal != NULL)
5193         {
5194           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5195                       "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5196                       GNUNET_i2s (peer),
5197                       a2s (rl->plugin->short_name,
5198                            fal->addr,
5199                            fal->addrlen),
5200                       rl->plugin->short_name);
5201           transmit_to_peer(NULL, fal,
5202                            TRANSPORT_PONG_PRIORITY,
5203                            HELLO_VERIFICATION_TIMEOUT,
5204                            (const char *)pong,
5205                            ntohs(pong->header.size),
5206                            GNUNET_YES,
5207                            n);
5208           did_pong = GNUNET_YES;
5209           fal = fal->next;
5210         }
5211       rl = rl->next;
5212     }
5213   GNUNET_free(pong);
5214   if (GNUNET_YES != did_pong)
5215     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5216                 _("Could not send PONG to `%s': no address available\n"),
5217                 GNUNET_i2s (peer));
5218   return GNUNET_OK;
5219 }
5220
5221
5222 /**
5223  * Function called by the plugin for each received message.  Update
5224  * data volumes, possibly notify plugins about reducing the rate at
5225  * which they read from the socket and generally forward to our
5226  * receive callback.
5227  *
5228  * @param cls the "struct TransportPlugin *" we gave to the plugin
5229  * @param peer (claimed) identity of the other peer
5230  * @param message the message, NULL if we only care about
5231  *                learning about the delay until we should receive again
5232  * @param ats_data information for automatic transport selection
5233  * @param ats_count number of elements in ats not including 0-terminator
5234  * @param session identifier used for this session (can be NULL)
5235  * @param sender_address binary address of the sender (if observed)
5236  * @param sender_address_len number of bytes in sender_address
5237  * @return how long in ms the plugin should wait until receiving more data
5238  *         (plugins that do not support this, can ignore the return value)
5239  */
5240 static struct GNUNET_TIME_Relative
5241 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5242                     const struct GNUNET_MessageHeader *message,
5243                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5244                     uint32_t ats_count,
5245                     struct Session *session,
5246                     const char *sender_address,
5247                     uint16_t sender_address_len)
5248 {
5249   struct TransportPlugin *plugin = cls;
5250   struct ReadyList *service_context;
5251   struct ForeignAddressList *peer_address;
5252   uint16_t msize;
5253   struct NeighbourList *n;
5254   struct GNUNET_TIME_Relative ret;
5255   uint32_t distance;
5256   int c;
5257
5258   if (0 == memcmp (peer,
5259                    &my_identity,
5260                    sizeof (struct GNUNET_PeerIdentity)))
5261     {
5262       /* refuse to receive from myself */
5263       GNUNET_break (0); 
5264       return GNUNET_TIME_UNIT_FOREVER_REL;
5265     }
5266   if (is_blacklisted (peer, plugin))
5267     return GNUNET_TIME_UNIT_FOREVER_REL;
5268   n = find_neighbour (peer);
5269   if (n == NULL)
5270     n = setup_new_neighbour (peer, GNUNET_YES);
5271   service_context = n->plugins;
5272   while ((service_context != NULL) && (plugin != service_context->plugin))
5273     service_context = service_context->next;
5274   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5275   peer_address = NULL;
5276   distance = 1;
5277
5278   for (c=0; c<ats_count; c++)
5279     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5280       distance = ntohl(ats_data[c].value);
5281
5282
5283   if (message != NULL)
5284     {
5285       if ( (session != NULL) ||
5286            (sender_address != NULL) )
5287         peer_address = add_peer_address (n,
5288                                          plugin->short_name,
5289                                          session,
5290                                          sender_address,
5291                                          sender_address_len);
5292       if (peer_address != NULL)
5293         {
5294           update_addr_ats(peer_address, ats_data, ats_count);
5295           update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5296           
5297           peer_address->distance = distance;
5298           if (GNUNET_YES == peer_address->validated)
5299             mark_address_connected (peer_address);
5300           peer_address->timeout
5301             = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5302           schedule_next_ping (peer_address);
5303         }
5304       /* update traffic received amount ... */
5305       msize = ntohs (message->size);
5306
5307       GNUNET_STATISTICS_update (stats,
5308                                 gettext_noop ("# bytes received from other peers"),
5309                                 msize,
5310                                 GNUNET_NO);
5311       n->distance = distance;
5312       n->peer_timeout =
5313         GNUNET_TIME_relative_to_absolute
5314         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5315       GNUNET_SCHEDULER_cancel (n->timeout_task);
5316       n->timeout_task =
5317         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5318                                       &neighbour_timeout_task, n);
5319       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5320         {
5321           /* dropping message due to frequent inbound volume violations! */
5322           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5323                       GNUNET_ERROR_TYPE_BULK,
5324                       _
5325                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5326                       n->in_tracker.available_bytes_per_s__,
5327                       n->quota_violation_count);
5328           GNUNET_STATISTICS_update (stats,
5329                                     gettext_noop ("# bandwidth quota violations by other peers"),
5330                                     1,
5331                                     GNUNET_NO);
5332           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5333         }
5334     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5335         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5336       {
5337         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5338         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5339         /* Force ressource and quality update */
5340         if ((value == 4) && (ats != NULL))
5341             ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5342         /* Force cost update */
5343         if ((value == 3) && (ats != NULL))
5344           ats_modify_problem_state(ats, ATS_COST_UPDATED);
5345         /* Force quality update */
5346         if ((value == 2) && (ats != NULL))
5347           ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5348         /* Force full rebuild */
5349         if ((value == 1) && (ats != NULL))
5350           ats_modify_problem_state(ats, ATS_MODIFIED);
5351       }
5352     
5353 #if DEBUG_PING_PONG
5354     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5355                 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5356                 ntohs (message->type),
5357                 ntohs (message->size),
5358                 GNUNET_i2s (peer));
5359 #endif
5360       switch (ntohs (message->type))
5361         {
5362         case GNUNET_MESSAGE_TYPE_HELLO:
5363           GNUNET_STATISTICS_update (stats,
5364                                     gettext_noop ("# HELLO messages received from other peers"),
5365                                     1,
5366                                     GNUNET_NO);
5367           process_hello (plugin, message);
5368           break;
5369         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5370           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5371           if (! n->received_pong)
5372             transmit_plain_ping (n);
5373           break;
5374         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5375           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5376           break;
5377         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5378           break;
5379         default:
5380           handle_payload_message (message, n);
5381           break;
5382         }
5383     }
5384   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5385   if (ret.rel_value > 0)
5386     {
5387 #if DEBUG_TRANSPORT 
5388       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5389                   "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5390                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5391                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5392                   (unsigned long long) ret.rel_value);
5393 #endif
5394       GNUNET_STATISTICS_update (stats,
5395                                 gettext_noop ("# ms throttling suggested"),
5396                                 (int64_t) ret.rel_value,
5397                                 GNUNET_NO);
5398     }
5399   return ret;
5400 }
5401
5402 /**
5403  * Handle START-message.  This is the first message sent to us
5404  * by any client which causes us to add it to our list.
5405  *
5406  * @param cls closure (always NULL)
5407  * @param client identification of the client
5408  * @param message the actual message
5409  */
5410 static void
5411 handle_start (void *cls,
5412               struct GNUNET_SERVER_Client *client,
5413               const struct GNUNET_MessageHeader *message)
5414 {
5415   const struct StartMessage *start;
5416   struct TransportClient *c;
5417   struct ConnectInfoMessage * cim;
5418   struct NeighbourList *n;
5419   uint32_t ats_count;
5420   size_t size;
5421
5422   start = (const struct StartMessage*) message;
5423 #if DEBUG_TRANSPORT
5424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5425               "Received `%s' request from client\n", "START");
5426 #endif
5427   c = clients;
5428   while (c != NULL)
5429     {
5430       if (c->client == client)
5431         {
5432           /* client already on our list! */
5433           GNUNET_break (0);
5434           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5435           return;
5436         }
5437       c = c->next;
5438     }
5439   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5440        (0 != memcmp (&start->self,
5441                      &my_identity,
5442                      sizeof (struct GNUNET_PeerIdentity))) )
5443     {
5444       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5445                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5446                   GNUNET_i2s (&start->self));
5447       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5448       return;
5449     }
5450   c = GNUNET_malloc (sizeof (struct TransportClient));
5451   c->next = clients;
5452   clients = c;
5453   c->client = client;
5454   if (our_hello != NULL)
5455     {
5456 #if DEBUG_TRANSPORT
5457       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5458                   "Sending our own `%s' to new client\n", "HELLO");
5459 #endif
5460       transmit_to_client (c,
5461                           (const struct GNUNET_MessageHeader *) our_hello,
5462                           GNUNET_NO);
5463       /* tell new client about all existing connections */
5464       ats_count = 2;
5465       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5466       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5467         {
5468           GNUNET_break(0);
5469         }
5470       cim = GNUNET_malloc (size);
5471       cim->header.size = htons (size);
5472       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5473       cim->ats_count = htonl(ats_count);
5474       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5475       (&(cim->ats))[2].value = htonl (0);
5476       n = neighbours;
5477       while (n != NULL)
5478         {
5479           if (GNUNET_YES == n->received_pong)
5480             {
5481               (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5482               (&(cim->ats))[0].value = htonl (n->distance);
5483               (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5484               (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5485               cim->id = n->id;
5486               transmit_to_client (c, &cim->header, GNUNET_NO);
5487             }
5488           n = n->next;
5489         }
5490       GNUNET_free (cim);
5491     }
5492   else
5493     {
5494 #if DEBUG_TRANSPORT_HELLO
5495       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5496                   "No HELLO created yet, will transmit HELLO to client later!\n");
5497 #endif
5498       refresh_hello ();
5499     }
5500   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5501 }
5502
5503
5504 /**
5505  * Handle HELLO-message.
5506  *
5507  * @param cls closure (always NULL)
5508  * @param client identification of the client
5509  * @param message the actual message
5510  */
5511 static void
5512 handle_hello (void *cls,
5513               struct GNUNET_SERVER_Client *client,
5514               const struct GNUNET_MessageHeader *message)
5515 {
5516   int ret;
5517
5518   GNUNET_STATISTICS_update (stats,
5519                             gettext_noop ("# HELLOs received from clients"),
5520                             1,
5521                             GNUNET_NO);
5522   ret = process_hello (NULL, message);
5523   GNUNET_SERVER_receive_done (client, ret);
5524 }
5525
5526
5527 /**
5528  * Closure for 'transmit_client_message'; followed by
5529  * 'msize' bytes of the actual message.
5530  */
5531 struct TransmitClientMessageContext
5532 {
5533   /**
5534    * Client on whom's behalf we are sending.
5535    */
5536   struct GNUNET_SERVER_Client *client;
5537
5538   /**
5539    * Timeout for the transmission.
5540    */
5541   struct GNUNET_TIME_Absolute timeout;
5542
5543   /**
5544    * Message priority.
5545    */
5546   uint32_t priority;
5547
5548   /**
5549    * Size of the message in bytes.
5550    */
5551   uint16_t msize;
5552 };
5553
5554
5555 /**
5556  * Schedule transmission of a message we got from a client to a peer.
5557  *
5558  * @param cls the 'struct TransmitClientMessageContext*'
5559  * @param n destination, or NULL on error (in that case, drop the message)
5560  */
5561 static void
5562 transmit_client_message (void *cls,
5563                          struct NeighbourList *n)
5564 {
5565   struct TransmitClientMessageContext *tcmc = cls;
5566   struct TransportClient *tc;
5567
5568   tc = clients;
5569   while ((tc != NULL) && (tc->client != tcmc->client))
5570     tc = tc->next;
5571
5572   if (n != NULL)
5573     {
5574       transmit_to_peer (tc, NULL, tcmc->priority,
5575                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5576                         (char *)&tcmc[1],
5577                         tcmc->msize, GNUNET_NO, n);
5578     }
5579   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5580   GNUNET_SERVER_client_drop (tcmc->client);
5581   GNUNET_free (tcmc);
5582 }
5583
5584
5585 /**
5586  * Handle SEND-message.
5587  *
5588  * @param cls closure (always NULL)
5589  * @param client identification of the client
5590  * @param message the actual message
5591  */
5592 static void
5593 handle_send (void *cls,
5594              struct GNUNET_SERVER_Client *client,
5595              const struct GNUNET_MessageHeader *message)
5596 {
5597   const struct OutboundMessage *obm;
5598   const struct GNUNET_MessageHeader *obmm;
5599   struct TransmitClientMessageContext *tcmc;
5600   uint16_t size;
5601   uint16_t msize;
5602
5603   size = ntohs (message->size);
5604   if (size <
5605       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5606     {
5607       GNUNET_break (0);
5608       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5609       return;
5610     }
5611   GNUNET_STATISTICS_update (stats,
5612                             gettext_noop ("# payload received for other peers"),
5613                             size,
5614                             GNUNET_NO);
5615   obm = (const struct OutboundMessage *) message;
5616   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5617   msize = size - sizeof (struct OutboundMessage);
5618 #if DEBUG_TRANSPORT
5619   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5620               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5621               "SEND", GNUNET_i2s (&obm->peer),
5622               ntohs (obmm->type),
5623               msize);
5624 #endif
5625   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5626   tcmc->client = client;
5627   tcmc->priority = ntohl (obm->priority);
5628   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5629   tcmc->msize = msize;
5630   /* FIXME: this memcpy can be up to 7% of our total runtime */
5631   memcpy (&tcmc[1], obmm, msize);
5632   GNUNET_SERVER_client_keep (client);
5633   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5634                               &transmit_client_message,
5635                               tcmc);
5636 }
5637
5638
5639 /**
5640  * Handle request connect message
5641  *
5642  * @param cls closure (always NULL)
5643  * @param client identification of the client
5644  * @param message the actual message
5645  */
5646 static void
5647 handle_request_connect (void *cls,
5648                         struct GNUNET_SERVER_Client *client,
5649                         const struct GNUNET_MessageHeader *message)
5650 {
5651   const struct TransportRequestConnectMessage *trcm =
5652     (const struct TransportRequestConnectMessage *) message;
5653
5654   GNUNET_STATISTICS_update (stats,
5655                             gettext_noop ("# REQUEST CONNECT messages received"),
5656                             1,
5657                             GNUNET_NO);
5658 #if DEBUG_TRANSPORT
5659   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
5660              "Received a request connect message for peer `%s'\n", 
5661              GNUNET_i2s(&trcm->peer));
5662 #endif
5663   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5664                               NULL, NULL);
5665   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5666 }
5667
5668
5669 /**
5670  * Handle SET_QUOTA-message.
5671  *
5672  * @param cls closure (always NULL)
5673  * @param client identification of the client
5674  * @param message the actual message
5675  */
5676 static void
5677 handle_set_quota (void *cls,
5678                   struct GNUNET_SERVER_Client *client,
5679                   const struct GNUNET_MessageHeader *message)
5680 {
5681   const struct QuotaSetMessage *qsm =
5682     (const struct QuotaSetMessage *) message;
5683   struct NeighbourList *n;
5684
5685   GNUNET_STATISTICS_update (stats,
5686                             gettext_noop ("# SET QUOTA messages received"),
5687                             1,
5688                             GNUNET_NO);
5689   n = find_neighbour (&qsm->peer);
5690   if (n == NULL)
5691     {
5692       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5693       GNUNET_STATISTICS_update (stats,
5694                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5695                                 1,
5696                                 GNUNET_NO);
5697       return;
5698     }
5699 #if DEBUG_TRANSPORT 
5700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5701               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5702               "SET_QUOTA",
5703               (unsigned int) ntohl (qsm->quota.value__),
5704               (unsigned int) n->in_tracker.available_bytes_per_s__,
5705               GNUNET_i2s (&qsm->peer));
5706 #endif
5707   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5708                                          qsm->quota);
5709   if (0 == ntohl (qsm->quota.value__))
5710     {
5711 #if DEBUG_TRANSPORT
5712       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5713                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5714                 "SET_QUOTA");
5715 #endif
5716       GNUNET_STATISTICS_update (stats,
5717                                 gettext_noop ("# disconnects due to quota of 0"),
5718                                 1,
5719                                 GNUNET_NO);
5720       disconnect_neighbour (n, GNUNET_NO);
5721     }
5722   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5723 }
5724
5725
5726 /**
5727  * Take the given address and append it to the set of results sent back to
5728  * the client.
5729  *
5730  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5731  * @param address the resolved name, NULL to indicate the last response
5732  */
5733 static void
5734 transmit_address_to_client (void *cls, const char *address)
5735 {
5736   struct GNUNET_SERVER_TransmitContext *tc = cls;
5737   size_t slen;
5738
5739   if (NULL != address)
5740     {
5741       slen = strlen (address) + 1;
5742       GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5743                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5744     }
5745   else
5746     {
5747       GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5748     }
5749 }
5750
5751
5752 /**
5753  * Handle AddressLookup-message.
5754  *
5755  * @param cls closure (always NULL)
5756  * @param client identification of the client
5757  * @param message the actual message
5758  */
5759 static void
5760 handle_address_lookup (void *cls,
5761                        struct GNUNET_SERVER_Client *client,
5762                        const struct GNUNET_MessageHeader *message)
5763 {
5764   const struct AddressLookupMessage *alum;
5765   struct TransportPlugin *lsPlugin;
5766   const char *nameTransport;
5767   const char *address;
5768   uint16_t size;
5769   struct GNUNET_SERVER_TransmitContext *tc;
5770   struct GNUNET_TIME_Absolute timeout;
5771   struct GNUNET_TIME_Relative rtimeout;
5772   int32_t numeric;
5773
5774   size = ntohs (message->size);
5775   if (size < sizeof (struct AddressLookupMessage))
5776     {
5777       GNUNET_break_op (0);
5778       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5779       return;
5780     }
5781   alum = (const struct AddressLookupMessage *) message;
5782   uint32_t addressLen = ntohl (alum->addrlen);
5783   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5784     {
5785       GNUNET_break_op (0);
5786       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5787       return;
5788     }
5789   address = (const char *) &alum[1];
5790   nameTransport = (const char *) &address[addressLen];
5791   if (nameTransport
5792       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5793     {
5794       GNUNET_break_op (0);
5795       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5796       return;
5797     }
5798   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5799   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5800   numeric = ntohl (alum->numeric_only);
5801   lsPlugin = find_transport (nameTransport);
5802   if (NULL == lsPlugin)
5803     {
5804       tc = GNUNET_SERVER_transmit_context_create (client);
5805       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5806                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5807       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5808       return;
5809     }
5810   GNUNET_SERVER_disable_receive_done_warning (client);
5811   tc = GNUNET_SERVER_transmit_context_create (client);
5812   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5813                                          nameTransport,
5814                                          address, addressLen,
5815                                          numeric,
5816                                          rtimeout,
5817                                          &transmit_address_to_client, tc);
5818 }
5819
5820 /**
5821  * Handle PeerAddressLookupMessage.
5822  *
5823  * @param cls closure (always NULL)
5824  * @param client identification of the client
5825  * @param message the actual message
5826  */
5827 static void
5828 handle_peer_address_lookup (void *cls,
5829                        struct GNUNET_SERVER_Client *client,
5830                        const struct GNUNET_MessageHeader *message)
5831 {
5832   const struct PeerAddressLookupMessage *peer_address_lookup;
5833   struct NeighbourList *neighbor_iterator;
5834   struct ReadyList *ready_iterator;
5835   struct ForeignAddressList *foreign_address_iterator;
5836   struct TransportPlugin *transport_plugin;
5837
5838   uint16_t size;
5839   struct GNUNET_SERVER_TransmitContext *tc;
5840   struct GNUNET_TIME_Absolute timeout;
5841   struct GNUNET_TIME_Relative rtimeout;
5842   char *addr_buf;
5843
5844   size = ntohs (message->size);
5845   if (size < sizeof (struct PeerAddressLookupMessage))
5846     {
5847       GNUNET_break_op (0);
5848       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5849       return;
5850     }
5851   peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5852
5853   timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5854   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5855
5856   neighbor_iterator = neighbours;
5857   while (neighbor_iterator != NULL)
5858     {
5859       if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5860         break;
5861       neighbor_iterator = neighbor_iterator->next;
5862     }
5863
5864   /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5865   if (neighbor_iterator == NULL)
5866     {
5867       GNUNET_break(0);
5868       tc = GNUNET_SERVER_transmit_context_create (client);
5869       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5870                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5871       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5872       return;
5873     }
5874
5875   ready_iterator = neighbor_iterator->plugins;
5876   GNUNET_SERVER_disable_receive_done_warning (client);
5877   tc = GNUNET_SERVER_transmit_context_create (client);
5878   while(ready_iterator != NULL)
5879     {
5880       foreign_address_iterator = ready_iterator->addresses;
5881       while (foreign_address_iterator != NULL)
5882         {
5883           transport_plugin = foreign_address_iterator->ready_list->plugin;
5884           if (foreign_address_iterator->addr != NULL)
5885             {
5886               GNUNET_asprintf (&addr_buf, "%s --- %s",
5887                                a2s (transport_plugin->short_name,
5888                                     foreign_address_iterator->addr,
5889                                     foreign_address_iterator->addrlen),
5890                                (foreign_address_iterator->connected
5891                                    == GNUNET_YES) ? "CONNECTED"
5892                                    : "DISCONNECTED");
5893               transmit_address_to_client(tc, addr_buf);
5894               GNUNET_free(addr_buf);
5895             }
5896           else if (foreign_address_iterator->addrlen == 0)
5897             {
5898               GNUNET_asprintf (&addr_buf, "%s --- %s", "<inbound>",
5899                                (foreign_address_iterator->connected
5900                                    == GNUNET_YES) ? "CONNECTED"
5901                                    : "DISCONNECTED");
5902               transmit_address_to_client (tc, addr_buf);
5903               GNUNET_free(addr_buf);
5904             }
5905
5906           foreign_address_iterator = foreign_address_iterator->next;
5907         }
5908       ready_iterator = ready_iterator->next;
5909     }
5910   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5911                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5912   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5913 }
5914
5915 /**
5916  * Handle AddressIterateMessage
5917  *
5918  * @param cls closure (always NULL)
5919  * @param client identification of the client
5920  * @param message the actual message
5921  */
5922 static void
5923 handle_address_iterate (void *cls,
5924                         struct GNUNET_SERVER_Client *client,
5925                         const struct GNUNET_MessageHeader *message)
5926 {
5927   const struct AddressIterateMessage *address_iterate;
5928   struct NeighbourList *neighbor_iterator;
5929   struct ReadyList *ready_iterator;
5930   struct ForeignAddressList *foreign_address_iterator;
5931   struct TransportPlugin *transport_plugin;
5932
5933   uint16_t size;
5934   struct GNUNET_SERVER_TransmitContext *tc;
5935   struct GNUNET_TIME_Absolute timeout;
5936   struct GNUNET_TIME_Relative rtimeout;
5937   char *addr_buf;
5938
5939   size = ntohs (message->size);
5940   if (size < sizeof (struct AddressIterateMessage))
5941     {
5942       GNUNET_break_op (0);
5943       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5944       return;
5945     }
5946   address_iterate = (const struct AddressIterateMessage *) message;
5947
5948   timeout = GNUNET_TIME_absolute_ntoh (address_iterate->timeout);
5949   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5950
5951   GNUNET_SERVER_disable_receive_done_warning (client);
5952   tc = GNUNET_SERVER_transmit_context_create (client);
5953
5954   neighbor_iterator = neighbours;
5955   while (neighbor_iterator != NULL)
5956     {
5957       ready_iterator = neighbor_iterator->plugins;
5958       while (ready_iterator != NULL)
5959         {
5960           foreign_address_iterator = ready_iterator->addresses;
5961           while (foreign_address_iterator != NULL)
5962             {
5963               transport_plugin = foreign_address_iterator->ready_list->plugin;
5964               if (foreign_address_iterator->addr != NULL)
5965                 {
5966                   GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5967                                    GNUNET_i2s(&neighbor_iterator->id),
5968                                    a2s (transport_plugin->short_name,
5969                                         foreign_address_iterator->addr,
5970                                         foreign_address_iterator->addrlen),
5971                                    (foreign_address_iterator->connected
5972                                        == GNUNET_YES) ? "CONNECTED"
5973                                        : "DISCONNECTED",
5974                                    (foreign_address_iterator->validated
5975                                        == GNUNET_YES) ? "VALIDATED"
5976                                        : "UNVALIDATED");
5977                   transmit_address_to_client (tc, addr_buf);
5978                   GNUNET_free(addr_buf);
5979                 }
5980               else if (foreign_address_iterator->addrlen == 0)
5981                 {
5982                   GNUNET_asprintf (&addr_buf, "%s:%s --- %s",
5983                                      GNUNET_i2s (&neighbor_iterator->id),
5984                                      "<inbound>",
5985                                      (foreign_address_iterator->connected
5986                                          == GNUNET_YES) ? "CONNECTED"
5987                                          : "DISCONNECTED",
5988                                      (foreign_address_iterator->validated
5989                                          == GNUNET_YES) ? "VALIDATED"
5990                                          : "UNVALIDATED");
5991                   transmit_address_to_client (tc, addr_buf);
5992                   GNUNET_free(addr_buf);
5993                 }
5994
5995               foreign_address_iterator = foreign_address_iterator->next;
5996             }
5997           ready_iterator = ready_iterator->next;
5998         }
5999       neighbor_iterator = neighbor_iterator->next;
6000     }
6001
6002   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
6003                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
6004   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
6005 }
6006
6007
6008 /**
6009  * Setup the environment for this plugin.
6010  */
6011 static void
6012 create_environment (struct TransportPlugin *plug)
6013 {
6014   plug->env.cfg = cfg;
6015   plug->env.my_identity = &my_identity;
6016   plug->env.our_hello = &our_hello;
6017   plug->env.cls = plug;
6018   plug->env.receive = &plugin_env_receive;
6019   plug->env.notify_address = &plugin_env_notify_address;
6020   plug->env.session_end = &plugin_env_session_end;
6021   plug->env.max_connections = max_connect_per_transport;
6022   plug->env.stats = stats;
6023 }
6024
6025
6026 /**
6027  * Start the specified transport (load the plugin).
6028  */
6029 static void
6030 start_transport (struct GNUNET_SERVER_Handle *server,
6031                  const char *name)
6032 {
6033   struct TransportPlugin *plug;
6034   char *libname;
6035
6036   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6037               _("Loading `%s' transport plugin\n"), name);
6038   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6039   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6040   create_environment (plug);
6041   plug->short_name = GNUNET_strdup (name);
6042   plug->lib_name = libname;
6043   plug->next = plugins;
6044   plugins = plug;
6045   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6046   if (plug->api == NULL)
6047     {
6048       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6049                   _("Failed to load transport plugin for `%s'\n"), name);
6050       GNUNET_free (plug->short_name);
6051       plugins = plug->next;
6052       GNUNET_free (libname);
6053       GNUNET_free (plug);
6054     }
6055 }
6056
6057
6058 /**
6059  * Called whenever a client is disconnected.  Frees our
6060  * resources associated with that client.
6061  *
6062  * @param cls closure
6063  * @param client identification of the client
6064  */
6065 static void
6066 client_disconnect_notification (void *cls,
6067                                 struct GNUNET_SERVER_Client *client)
6068 {
6069   struct TransportClient *pos;
6070   struct TransportClient *prev;
6071   struct ClientMessageQueueEntry *mqe;
6072   struct Blacklisters *bl;
6073   struct BlacklistCheck *bc;
6074
6075   if (client == NULL)
6076     return;
6077 #if DEBUG_TRANSPORT
6078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6079               "Client disconnected, cleaning up.\n");
6080 #endif
6081   /* clean up blacklister */
6082   bl = bl_head;
6083   while (bl != NULL)
6084     {
6085       if (bl->client == client)
6086         {
6087           bc = bc_head;
6088           while (bc != NULL)
6089             {
6090               if (bc->bl_pos == bl)
6091                 {
6092                   bc->bl_pos = bl->next;
6093                   if (bc->th != NULL)
6094                     {
6095                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6096                       bc->th = NULL;
6097                     }
6098                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6099                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6100                                                          bc);
6101                   break;
6102                 }
6103               bc = bc->next;
6104             }
6105           GNUNET_CONTAINER_DLL_remove (bl_head,
6106                                        bl_tail,
6107                                        bl);
6108           GNUNET_SERVER_client_drop (bl->client);
6109           GNUNET_free (bl);
6110           break;
6111         }
6112       bl = bl->next;
6113     }
6114   /* clean up 'normal' clients */
6115   prev = NULL;
6116   pos = clients;
6117   while ((pos != NULL) && (pos->client != client))
6118     {
6119       prev = pos;
6120       pos = pos->next;
6121     }
6122   if (pos == NULL)
6123     return;
6124   while (NULL != (mqe = pos->message_queue_head))
6125     {
6126       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6127                                    pos->message_queue_tail,
6128                                    mqe);
6129       pos->message_count--;
6130       GNUNET_free (mqe);
6131     }
6132   if (prev == NULL)
6133     clients = pos->next;
6134   else
6135     prev->next = pos->next;
6136   if (GNUNET_YES == pos->tcs_pending)
6137     {
6138       pos->client = NULL;
6139       return;
6140     }
6141   if (pos->th != NULL)
6142     {
6143       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6144       pos->th = NULL;
6145     }
6146   GNUNET_break (0 == pos->message_count);
6147   GNUNET_free (pos);
6148 }
6149
6150
6151 /**
6152  * Function called when the service shuts down.  Unloads our plugins
6153  * and cancels pending validations.
6154  *
6155  * @param cls closure, unused
6156  * @param tc task context (unused)
6157  */
6158 static void
6159 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6160 {
6161   struct TransportPlugin *plug;
6162   struct TransportPlugin *tmp;
6163   struct OwnAddressList *al;
6164   struct CheckHelloValidatedContext *chvc;
6165
6166   shutdown_in_progress = GNUNET_YES;
6167   while (neighbours != NULL)
6168     {
6169 #if DEBUG_TRANSPORT
6170       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6171                   "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6172                   "SHUTDOWN_TASK");
6173 #endif
6174       disconnect_neighbour (neighbours, GNUNET_NO);
6175     }
6176 #if DEBUG_TRANSPORT
6177   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6178               "Transport service is unloading plugins...\n");
6179 #endif
6180   plug = plugins;
6181   while (plug != NULL)
6182     {
6183       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6184         {
6185           GNUNET_SCHEDULER_cancel (plug->address_update_task);
6186           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6187         }
6188       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6189       GNUNET_free (plug->lib_name);
6190       GNUNET_free (plug->short_name);
6191       while (NULL != (al = plug->addresses))
6192         {
6193           plug->addresses = al->next;
6194           GNUNET_free (al);
6195         }
6196       tmp = plug->next;
6197       GNUNET_free (plug);
6198       plug = tmp;
6199     }
6200   if (my_private_key != NULL)
6201     GNUNET_CRYPTO_rsa_key_free (my_private_key);
6202   GNUNET_free_non_null (our_hello);
6203
6204   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6205                                          &abort_validation,
6206                                          NULL);
6207   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6208   validation_map = NULL;
6209
6210
6211   if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6212   {
6213     GNUNET_SCHEDULER_cancel(ats_task);
6214     ats_task = GNUNET_SCHEDULER_NO_TASK;
6215   }
6216   if (ats != NULL)
6217     ats_shutdown (ats);
6218
6219   /* free 'chvc' data structure */
6220   while (NULL != (chvc = chvc_head))
6221     {
6222       chvc_head = chvc->next;
6223       if (chvc->piter != NULL)
6224         {
6225           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6226           GNUNET_STATISTICS_update (stats,
6227                                     gettext_noop ("# outstanding peerinfo iterate requests"),
6228                                     -1,
6229                                     GNUNET_NO);
6230           chvc->ve_count --;
6231         }
6232       else
6233           GNUNET_break (0);
6234       GNUNET_assert (chvc->ve_count == 0);
6235       GNUNET_free (chvc);
6236     }
6237   chvc_tail = NULL;
6238
6239   if (stats != NULL)
6240     {
6241       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6242       stats = NULL;
6243     }
6244   if (peerinfo != NULL)
6245     {
6246       GNUNET_PEERINFO_disconnect (peerinfo);
6247       peerinfo = NULL;
6248     }
6249   if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6250     {
6251       GNUNET_SCHEDULER_cancel (hello_task);
6252       hello_task = GNUNET_SCHEDULER_NO_TASK;
6253     }
6254   /* Can we assume those are gone by now, or do we need to clean up
6255      explicitly!? */
6256   GNUNET_break (bl_head == NULL);
6257   GNUNET_break (bc_head == NULL);
6258 }
6259
6260
6261 void ats_result_cb ()
6262 {
6263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6264       "ATS Result callback\n");
6265 }
6266
6267
6268 void create_ats_information ( struct ATS_peer **p,
6269                               int * c_p,
6270                               struct ATS_mechanism ** m,
6271                               int * c_m )
6272 {
6273 #if VERBOSE_ATS
6274   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6275       "ATS requires clean address information\n");
6276 #endif
6277   struct ATS_mechanism * mechanisms;
6278   struct ATS_peer *peers;
6279
6280   int connected_addresses = 0;
6281   int c_peers = 0;
6282   int c_mechs = 0;
6283   struct NeighbourList *next = neighbours;
6284
6285   while (next!=NULL)
6286   {
6287     int found_addresses = GNUNET_NO;
6288     struct ReadyList *r_next = next->plugins;
6289     while (r_next != NULL)
6290     {
6291         struct ForeignAddressList * a_next = r_next->addresses;
6292         while (a_next != NULL)
6293         {
6294             c_mechs++;
6295             found_addresses = GNUNET_YES;
6296             a_next = a_next->next;
6297         }
6298         r_next = r_next->next;
6299     }
6300     if (found_addresses) c_peers++;
6301     next = next->next;
6302   }
6303
6304 #if VERBOSE_ATS
6305   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6306       "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6307 #endif
6308
6309   if ((c_peers == 0) && (c_mechs == 0))
6310   {
6311     peers = NULL;
6312     (*c_p) = 0;
6313     mechanisms = NULL;
6314     (*c_m) = 0;
6315     return;
6316   }
6317
6318   mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6319   peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6320
6321   c_mechs = 1;
6322   c_peers = 1;
6323
6324   next = neighbours;
6325   while (next!=NULL)
6326   {
6327     int found_addresses = GNUNET_NO;
6328     struct ReadyList *r_next = next->plugins;
6329     while (r_next != NULL)
6330     {
6331         struct ForeignAddressList * a_next = r_next->addresses;
6332         while (a_next != NULL)
6333         {
6334             if (a_next->connected == GNUNET_YES)
6335               connected_addresses ++;
6336             if (found_addresses == GNUNET_NO)
6337             {
6338               peers[c_peers].peer = next->id;
6339               peers[c_peers].m_head = NULL;
6340               peers[c_peers].m_tail = NULL;
6341               peers[c_peers].f = 1.0 / c_mechs;
6342             }
6343
6344             mechanisms[c_mechs].addr = a_next;
6345             mechanisms[c_mechs].col_index = c_mechs;
6346             mechanisms[c_mechs].peer = &peers[c_peers];
6347             mechanisms[c_mechs].next = NULL;
6348             mechanisms[c_mechs].plugin = r_next->plugin;
6349             mechanisms[c_mechs].ressources = a_next->ressources;
6350             mechanisms[c_mechs].quality = a_next->quality;
6351
6352             GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6353                                              peers[c_peers].m_tail,
6354                                              &mechanisms[c_mechs]);
6355             found_addresses = GNUNET_YES;
6356             c_mechs++;
6357
6358             a_next = a_next->next;
6359         }
6360         r_next = r_next->next;
6361     }
6362     if (found_addresses == GNUNET_YES)
6363         c_peers++;
6364     next = next->next;
6365   }
6366   c_mechs--;
6367   c_peers--;
6368   (*c_m) = c_mechs;
6369   (*c_p) = c_peers;
6370   (*p) = peers;
6371   (*m) = mechanisms;
6372
6373   GNUNET_STATISTICS_set(stats,
6374                         gettext_noop ("# connected addresses"),
6375                         connected_addresses,
6376                         GNUNET_NO);
6377 }
6378
6379 static void
6380 schedule_ats (void *cls,
6381               const struct GNUNET_SCHEDULER_TaskContext *tc)
6382 {
6383   struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6384   if (ats==NULL)
6385     return;
6386
6387   ats_task = GNUNET_SCHEDULER_NO_TASK;
6388   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6389       return;
6390
6391   if (shutdown_in_progress == GNUNET_YES)
6392           return;
6393
6394   struct GNUNET_TIME_Relative delta =
6395       GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6396   if (delta.rel_value < ats_minimum_interval.rel_value)
6397   {
6398 #if DEBUG_ATS
6399     GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6400         "Minimum time between cycles not reached\n");
6401 #endif
6402     return;
6403   }
6404
6405 #if DEBUG_ATS
6406   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6407 #endif
6408   ats_calculate_bandwidth_distribution (ats, stats);
6409   last_ats_execution = GNUNET_TIME_absolute_get();
6410
6411   ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6412                                   &schedule_ats, ats);
6413 }
6414
6415 struct ForeignAddressList * get_preferred_ats_address (
6416                 struct NeighbourList *n)
6417 {
6418   // TODO get ATS prefered address
6419   return find_ready_address(n);
6420 }
6421
6422 /**
6423  * Initiate transport service.
6424  *
6425  * @param cls closure
6426  * @param server the initialized server
6427  * @param c configuration to use
6428  */
6429 static void
6430 run (void *cls,
6431      struct GNUNET_SERVER_Handle *server,
6432      const struct GNUNET_CONFIGURATION_Handle *c)
6433 {
6434   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6435     {&handle_start, NULL,
6436      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6437     {&handle_hello, NULL,
6438      GNUNET_MESSAGE_TYPE_HELLO, 0},
6439     {&handle_send, NULL,
6440      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6441     {&handle_request_connect, NULL,
6442      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6443     {&handle_set_quota, NULL,
6444      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6445     {&handle_address_lookup, NULL,
6446      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6447      0},
6448     {&handle_peer_address_lookup, NULL,
6449      GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6450      0},
6451     {&handle_address_iterate, NULL,
6452      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6453      0},
6454     {&handle_blacklist_init, NULL,
6455      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6456     {&handle_blacklist_reply, NULL,
6457      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6458     {NULL, NULL, 0, 0}
6459   };
6460   char *plugs;
6461   char *pos;
6462   int no_transports;
6463   unsigned long long tneigh;
6464   char *keyfile;
6465
6466   shutdown_in_progress = GNUNET_NO;
6467   cfg = c;
6468   stats = GNUNET_STATISTICS_create ("transport", cfg);
6469   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6470   /* parse configuration */
6471   if ((GNUNET_OK !=
6472        GNUNET_CONFIGURATION_get_value_number (c,
6473                                               "TRANSPORT",
6474                                               "NEIGHBOUR_LIMIT",
6475                                               &tneigh)) ||
6476       (GNUNET_OK !=
6477        GNUNET_CONFIGURATION_get_value_filename (c,
6478                                                 "GNUNETD",
6479                                                 "HOSTKEY", &keyfile)))
6480     {
6481       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6482                   _
6483                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
6484       GNUNET_SCHEDULER_shutdown ();
6485       if (stats != NULL)
6486         {
6487           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6488           stats = NULL;
6489         }
6490       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6491       validation_map = NULL;
6492       return;
6493     }
6494
6495   max_connect_per_transport = (uint32_t) tneigh;
6496   peerinfo = GNUNET_PEERINFO_connect (cfg);
6497   if (peerinfo == NULL)
6498     {
6499       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6500                   _("Could not access PEERINFO service.  Exiting.\n"));
6501       GNUNET_SCHEDULER_shutdown ();
6502       if (stats != NULL)
6503         {
6504           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6505           stats = NULL;
6506         }
6507       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6508       validation_map = NULL;
6509       GNUNET_free (keyfile);
6510       return;
6511     }
6512   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6513   GNUNET_free (keyfile);
6514   if (my_private_key == NULL)
6515     {
6516       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6517                   _
6518                   ("Transport service could not access hostkey.  Exiting.\n"));
6519       GNUNET_SCHEDULER_shutdown ();
6520       if (stats != NULL)
6521         {
6522           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6523           stats = NULL;
6524         }
6525       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6526       validation_map = NULL;
6527       return;
6528     }
6529   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6530   GNUNET_CRYPTO_hash (&my_public_key,
6531                       sizeof (my_public_key), &my_identity.hashPubKey);
6532   /* setup notification */
6533   GNUNET_SERVER_disconnect_notify (server,
6534                                    &client_disconnect_notification, NULL);
6535   /* load plugins... */
6536   no_transports = 1;
6537   if (GNUNET_OK ==
6538       GNUNET_CONFIGURATION_get_value_string (c,
6539                                              "TRANSPORT", "PLUGINS", &plugs))
6540     {
6541       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6542                   _("Starting transport plugins `%s'\n"), plugs);
6543       pos = strtok (plugs, " ");
6544       while (pos != NULL)
6545         {
6546           start_transport (server, pos);
6547           no_transports = 0;
6548           pos = strtok (NULL, " ");
6549         }
6550       GNUNET_free (plugs);
6551     }
6552   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6553                                 &shutdown_task, NULL);
6554   if (no_transports)
6555     refresh_hello ();
6556
6557   /* Initializing ATS */
6558   int co;
6559   char * section;
6560   unsigned long long  value;
6561
6562   double D = 1.0;
6563   double U = 1.0;
6564   double R = 1.0;
6565   int v_b_min = 64000;
6566   int v_n_min = 5;
6567
6568   ats_minimum_interval = ATS_MIN_INTERVAL;
6569   ats_regular_interval = ATS_EXEC_INTERVAL;
6570
6571   /* loading cost ressources */
6572   for (co=0; co<available_ressources; co++)
6573   {
6574     GNUNET_asprintf(&section,"%s_UP",ressources[co].cfg_param);
6575     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6576     {
6577       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6578           "transport",
6579           section,
6580           &value))
6581       {
6582 #if DEBUG_ATS
6583               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6584                   "Found ressource cost: [%s] = %llu\n",
6585                   section, value);
6586 #endif
6587               ressources[co].c_max = value;
6588       }
6589     }
6590     GNUNET_free (section);
6591     GNUNET_asprintf(&section,"%s_DOWN",ressources[co].cfg_param);
6592     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6593     {
6594       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6595           "transport",
6596           section,
6597           &value))
6598       {
6599 #if DEBUG_ATS
6600               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6601                   "Found ressource cost: [%s] = %llu\n",
6602                   section, value);
6603 #endif
6604               ressources[co].c_min = value;
6605       }
6606     }
6607     GNUNET_free (section);
6608   }
6609
6610   ats = ats_init (D, U, R, v_b_min, v_n_min,
6611                   ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6612                   create_ats_information,
6613                   ats_result_cb);
6614
6615   int log_problem = GNUNET_NO;
6616   int log_solution = GNUNET_NO;
6617   int overwrite_dump = GNUNET_NO;
6618   int minimum_peers = 0;
6619   int minimum_addresses = 0;
6620
6621   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6622     log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6623                              "transport","DUMP_MLP");
6624
6625   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6626     log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6627                                   "transport","DUMP_SOLUTION");
6628   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
6629     overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6630                                   "transport","DUMP_OVERWRITE");
6631   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
6632   {
6633           GNUNET_CONFIGURATION_get_value_number(cfg,
6634               "transport","DUMP_MIN_PEERS", &value);
6635           minimum_peers = value;
6636   }
6637   if (GNUNET_CONFIGURATION_have_value(cfg,
6638       "transport", "DUMP_MIN_ADDRS"))
6639   {
6640       GNUNET_CONFIGURATION_get_value_number(cfg,
6641         "transport","DUMP_MIN_ADDRS", &value);
6642       minimum_addresses= value;
6643   }
6644   if (GNUNET_CONFIGURATION_have_value(cfg,
6645       "transport", "DUMP_OVERWRITE"))
6646   {
6647       GNUNET_CONFIGURATION_get_value_number(cfg,
6648           "transport","DUMP_OVERWRITE", &value);
6649       overwrite_dump = value;
6650   }
6651
6652   if (GNUNET_CONFIGURATION_have_value(cfg,
6653       "transport", "ATS_MIN_INTERVAL"))
6654   {
6655       GNUNET_CONFIGURATION_get_value_number(cfg,
6656           "transport","ATS_MIN_INTERVAL", &value);
6657       ats_minimum_interval.rel_value = value;
6658   }
6659
6660   if (GNUNET_CONFIGURATION_have_value(cfg,
6661       "transport", "ATS_EXEC_INTERVAL"))
6662   {
6663       GNUNET_CONFIGURATION_get_value_number(cfg,
6664           "transport","ATS_EXEC_INTERVAL", &value);
6665       ats_regular_interval.rel_value = value;
6666   }
6667   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
6668   {
6669       GNUNET_CONFIGURATION_get_value_number(cfg,
6670           "transport","ATS_MIN_INTERVAL", &value);
6671       ats_minimum_interval.rel_value = value;
6672   }
6673
6674   ats_set_logging_options (ats,
6675                           minimum_addresses,
6676                           minimum_peers,
6677                           overwrite_dump,
6678                           log_solution,
6679                           log_problem);
6680
6681   if (ats != NULL)
6682     ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6683
6684
6685
6686
6687 #if DEBUG_TRANSPORT
6688   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
6689               _("Transport service ready.\n"));
6690 #endif
6691   /* If we have a blacklist file, read from it */
6692   read_blacklist_file(cfg);
6693   /* process client requests */
6694   GNUNET_SERVER_add_handlers (server, handlers);
6695 }
6696
6697
6698 /**
6699  * The main function for the transport service.
6700  *
6701  * @param argc number of arguments from the command line
6702  * @param argv command line arguments
6703  * @return 0 ok, 1 on error
6704  */
6705 int
6706 main (int argc, char *const *argv)
6707 {
6708   a2s (NULL, NULL, 0); /* make compiler happy */
6709   return (GNUNET_OK ==
6710           GNUNET_SERVICE_run (argc,
6711                               argv,
6712                               "transport",
6713                               GNUNET_SERVICE_OPTION_NONE,
6714                               &run, NULL)) ? 0 : 1;
6715 }
6716
6717 /* end of gnunet-service-transport.c */