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