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