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