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