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