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