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