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