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