better debug message
[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       return GNUNET_OK;
3848     }
3849   hello = (const struct GNUNET_HELLO_Message *) message;
3850   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3851     {
3852       GNUNET_break_op (0);
3853       return GNUNET_SYSERR;
3854     }
3855   GNUNET_CRYPTO_hash (&publicKey,
3856                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3857                       &target.hashPubKey);
3858   if (0 == memcmp (&my_identity,
3859                    &target,
3860                    sizeof (struct GNUNET_PeerIdentity)))
3861     {
3862       GNUNET_STATISTICS_update (stats,
3863                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3864                                 1,
3865                                 GNUNET_NO);      
3866       return GNUNET_OK;      
3867     }
3868   chvc = chvc_head;
3869   while (NULL != chvc)
3870     {
3871       if (GNUNET_HELLO_equals (hello,
3872                                chvc->hello,
3873                                GNUNET_TIME_absolute_get ()).value > 0)
3874         {
3875 #if DEBUG_TRANSPORT
3876           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3877                       "Received duplicate `%s' message for `%4s'; ignored\n",
3878                       "HELLO", 
3879                       GNUNET_i2s (&target));
3880 #endif
3881           return GNUNET_OK; /* validation already pending */
3882         }
3883       if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
3884         GNUNET_break (0 != memcmp (hello, chvc->hello,
3885                                    GNUNET_HELLO_size(hello)));
3886       chvc = chvc->next;
3887     }
3888 #if DEBUG_TRANSPORT_HELLO
3889   if (plugin != NULL)
3890     {
3891       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
3892       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3893                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
3894                   my_id,
3895                   "HELLO",
3896                   GNUNET_i2s (&target),
3897                   (plugin == NULL) ? "???" : plugin->short_name,
3898                   GNUNET_HELLO_size(hello));
3899       GNUNET_free(my_id);
3900     }
3901 #endif
3902   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3903   chvc->ve_count = 1;
3904   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3905   memcpy (&chvc[1], hello, hsize);
3906   GNUNET_CONTAINER_DLL_insert (chvc_head,
3907                                chvc_tail,
3908                                chvc);
3909   /* finally, check if HELLO was previously validated
3910      (continuation will then schedule actual validation) */
3911   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
3912                                          &target,
3913                                          0,
3914                                          HELLO_VERIFICATION_TIMEOUT,
3915                                          &check_hello_validated, chvc);
3916   return GNUNET_OK;
3917 }
3918
3919
3920 /**
3921  * The peer specified by the given neighbour has timed-out or a plugin
3922  * has disconnected.  We may either need to do nothing (other plugins
3923  * still up), or trigger a full disconnect and clean up.  This
3924  * function updates our state and does the necessary notifications.
3925  * Also notifies our clients that the neighbour is now officially
3926  * gone.
3927  *
3928  * @param n the neighbour list entry for the peer
3929  * @param check should we just check if all plugins
3930  *        disconnected or must we ask all plugins to
3931  *        disconnect?
3932  */
3933 static void
3934 disconnect_neighbour (struct NeighbourList *n, int check)
3935 {
3936   struct ReadyList *rpos;
3937   struct NeighbourList *npos;
3938   struct NeighbourList *nprev;
3939   struct MessageQueue *mq;
3940   struct ForeignAddressList *peer_addresses;
3941   struct ForeignAddressList *peer_pos;
3942
3943   if (GNUNET_YES == check)
3944     {
3945       rpos = n->plugins;
3946       while (NULL != rpos)
3947         {
3948           peer_addresses = rpos->addresses;
3949           while (peer_addresses != NULL)
3950             {
3951               if (GNUNET_YES == peer_addresses->connected)
3952                 return;             /* still connected */
3953               peer_addresses = peer_addresses->next;
3954             }
3955           rpos = rpos->next;
3956         }
3957     }
3958 #if DEBUG_TRANSPORT
3959   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3960               "Disconnecting from `%4s'\n",
3961               GNUNET_i2s (&n->id));
3962 #endif
3963   /* remove n from neighbours list */
3964   nprev = NULL;
3965   npos = neighbours;
3966   while ((npos != NULL) && (npos != n))
3967     {
3968       nprev = npos;
3969       npos = npos->next;
3970     }
3971   GNUNET_assert (npos != NULL);
3972   if (nprev == NULL)
3973     neighbours = n->next;
3974   else
3975     nprev->next = n->next;
3976
3977   /* notify all clients about disconnect */
3978   if (GNUNET_YES == n->received_pong)
3979     notify_clients_disconnect (&n->id);
3980
3981   /* clean up all plugins, cancel connections and pending transmissions */
3982   while (NULL != (rpos = n->plugins))
3983     {
3984       n->plugins = rpos->next;
3985       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3986       while (rpos->addresses != NULL)
3987         {
3988           peer_pos = rpos->addresses;
3989           rpos->addresses = peer_pos->next;
3990           if (peer_pos->connected == GNUNET_YES)
3991             GNUNET_STATISTICS_update (stats,
3992                                       gettext_noop ("# connected addresses"),
3993                                       -1,
3994                                       GNUNET_NO); 
3995           if (GNUNET_YES == peer_pos->validated)
3996             GNUNET_STATISTICS_update (stats,
3997                                       gettext_noop ("# peer addresses considered valid"),
3998                                       -1,
3999                                       GNUNET_NO);      
4000           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4001             {
4002               GNUNET_SCHEDULER_cancel (sched,
4003                                        peer_pos->revalidate_task);
4004               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4005             }
4006           GNUNET_free(peer_pos);
4007         }
4008       GNUNET_free (rpos);
4009     }
4010
4011   /* free all messages on the queue */
4012   while (NULL != (mq = n->messages_head))
4013     {
4014       GNUNET_STATISTICS_update (stats,
4015                                 gettext_noop ("# bytes in message queue for other peers"),
4016                                 - (int64_t) mq->message_buf_size,
4017                                 GNUNET_NO);
4018       GNUNET_STATISTICS_update (stats,
4019                                 gettext_noop ("# bytes discarded due to disconnect"),
4020                                 mq->message_buf_size,
4021                                 GNUNET_NO);
4022       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4023                                    n->messages_tail,
4024                                    mq);
4025       GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
4026                                  &n->id,
4027                                  sizeof(struct GNUNET_PeerIdentity)));
4028       GNUNET_free (mq);
4029     }
4030   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4031     {
4032       GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
4033       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4034     }
4035   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4036     {
4037       GNUNET_SCHEDULER_cancel (sched, n->retry_task);
4038       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4039     }
4040   if (n->piter != NULL)
4041     {
4042       GNUNET_PEERINFO_iterate_cancel (n->piter);
4043       n->piter = NULL;
4044     }
4045   /* finally, free n itself */
4046   GNUNET_STATISTICS_update (stats,
4047                             gettext_noop ("# active neighbours"),
4048                             -1,
4049                             GNUNET_NO);
4050   GNUNET_free_non_null (n->pre_connect_message_buffer);
4051   GNUNET_free (n);
4052 }
4053
4054
4055 /**
4056  * We have received a PING message from someone.  Need to send a PONG message
4057  * in response to the peer by any means necessary. 
4058  */
4059 static int 
4060 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4061             const struct GNUNET_PeerIdentity *peer,
4062             const char *sender_address,
4063             uint16_t sender_address_len)
4064 {
4065   struct TransportPlugin *plugin = cls;
4066   struct TransportPingMessage *ping;
4067   struct TransportPongMessage *pong;
4068   struct NeighbourList *n;
4069   struct ReadyList *rl;
4070   struct ForeignAddressList *fal;
4071
4072   if (ntohs (message->size) != sizeof (struct TransportPingMessage))
4073     {
4074       GNUNET_break_op (0);
4075       return GNUNET_SYSERR;
4076     }
4077
4078   ping = (struct TransportPingMessage *) message;
4079   if (0 != memcmp (&ping->target,
4080                    plugin->env.my_identity,
4081                    sizeof (struct GNUNET_PeerIdentity)))
4082     {
4083       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4084                   _("Received `%s' message not destined for me!\n"), 
4085                   "PING");
4086       return GNUNET_SYSERR;
4087     }
4088 #if DEBUG_PING_PONG
4089   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4090               "Processing `%s' from `%s'\n",
4091               "PING", 
4092               (sender_address != NULL) 
4093               ? a2s (plugin->short_name,
4094                      (const struct sockaddr *)sender_address, 
4095                      sender_address_len)
4096               : "<inbound>");
4097 #endif
4098   GNUNET_STATISTICS_update (stats,
4099                             gettext_noop ("# PING messages received"),
4100                             1,
4101                             GNUNET_NO);
4102   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
4103   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
4104   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4105   pong->purpose.size =
4106     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4107            sizeof (uint32_t) +
4108            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
4109   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
4110   pong->challenge = ping->challenge;
4111   pong->addrlen = htons(sender_address_len);
4112   memcpy(&pong->signer, 
4113          &my_public_key, 
4114          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
4115   if (sender_address != NULL)
4116     memcpy (&pong[1], sender_address, sender_address_len);
4117 #if SIGN_USELESS
4118   GNUNET_assert (GNUNET_OK ==
4119                  GNUNET_CRYPTO_rsa_sign (my_private_key,
4120                                          &pong->purpose, &pong->signature));
4121 #endif
4122   n = find_neighbour(peer);
4123   GNUNET_assert (n != NULL);
4124   /* first try reliable response transmission */
4125   rl = n->plugins;
4126   while (rl != NULL)
4127     {
4128       fal = rl->addresses;
4129       while (fal != NULL)
4130         {
4131           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4132                                            peer,
4133                                            (const char*) pong,
4134                                            ntohs (pong->header.size),
4135                                            TRANSPORT_PONG_PRIORITY, 
4136                                            HELLO_VERIFICATION_TIMEOUT,
4137                                            fal->session,
4138                                            fal->addr,
4139                                            fal->addrlen,
4140                                            GNUNET_SYSERR,
4141                                            NULL, NULL))
4142             {
4143               /* done! */
4144               GNUNET_STATISTICS_update (stats,
4145                                         gettext_noop ("# PONGs unicast via reliable transport"),
4146                                         1,
4147                                         GNUNET_NO);      
4148               GNUNET_free (pong);
4149               return GNUNET_OK;
4150             }
4151           fal = fal->next;
4152         }
4153       rl = rl->next;
4154     }
4155   /* no reliable method found, do multicast */
4156   GNUNET_STATISTICS_update (stats,
4157                             gettext_noop ("# PONGs multicast to all available addresses"),
4158                             1,
4159                             GNUNET_NO);      
4160   rl = n->plugins;
4161   while (rl != NULL)
4162     {
4163       fal = rl->addresses;
4164       while (fal != NULL)
4165         {
4166           transmit_to_peer(NULL, fal,
4167                            TRANSPORT_PONG_PRIORITY, 
4168                            HELLO_VERIFICATION_TIMEOUT,
4169                            (const char *)pong, 
4170                            ntohs(pong->header.size), 
4171                            GNUNET_YES, 
4172                            n);
4173           fal = fal->next;
4174         }
4175       rl = rl->next;
4176     }
4177   GNUNET_free(pong);
4178   return GNUNET_OK;
4179 }
4180
4181
4182 /**
4183  * Function called by the plugin for each received message.
4184  * Update data volumes, possibly notify plugins about
4185  * reducing the rate at which they read from the socket
4186  * and generally forward to our receive callback.
4187  *
4188  * @param cls the "struct TransportPlugin *" we gave to the plugin
4189  * @param peer (claimed) identity of the other peer
4190  * @param message the message, NULL if we only care about
4191  *                learning about the delay until we should receive again
4192  * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
4193  * @param session identifier used for this session (can be NULL)
4194  * @param sender_address binary address of the sender (if observed)
4195  * @param sender_address_len number of bytes in sender_address
4196  * @return how long the plugin should wait until receiving more data
4197  *         (plugins that do not support this, can ignore the return value)
4198  */
4199 static struct GNUNET_TIME_Relative
4200 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4201                     const struct GNUNET_MessageHeader *message,
4202                     uint32_t distance,
4203                     struct Session *session,
4204                     const char *sender_address,
4205                     uint16_t sender_address_len)
4206 {
4207   struct TransportPlugin *plugin = cls;
4208   struct ReadyList *service_context;
4209   struct ForeignAddressList *peer_address;
4210   uint16_t msize;
4211   struct NeighbourList *n;
4212   struct GNUNET_TIME_Relative ret;
4213
4214   if (is_blacklisted (peer, plugin))
4215     return GNUNET_TIME_UNIT_FOREVER_REL;
4216
4217   n = find_neighbour (peer);
4218   if (n == NULL)
4219     n = setup_new_neighbour (peer, GNUNET_YES);
4220   service_context = n->plugins;
4221   while ((service_context != NULL) && (plugin != service_context->plugin))
4222     service_context = service_context->next;
4223   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4224   peer_address = NULL;
4225   if (message != NULL)
4226     {
4227       if ( (session != NULL) ||
4228            (sender_address != NULL) )
4229         peer_address = add_peer_address (n, 
4230                                          plugin->short_name,
4231                                          session,
4232                                          sender_address, 
4233                                          sender_address_len);  
4234       if (peer_address != NULL)
4235         {
4236           peer_address->distance = distance;
4237           if (GNUNET_YES == peer_address->validated)
4238             mark_address_connected (peer_address);
4239           peer_address->timeout
4240             =
4241             GNUNET_TIME_relative_to_absolute
4242             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4243           schedule_next_ping (peer_address);
4244         }
4245       /* update traffic received amount ... */
4246       msize = ntohs (message->size);      
4247       GNUNET_STATISTICS_update (stats,
4248                                 gettext_noop ("# bytes received from other peers"),
4249                                 msize,
4250                                 GNUNET_NO);
4251       n->distance = distance;
4252       n->peer_timeout =
4253         GNUNET_TIME_relative_to_absolute
4254         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4255       GNUNET_SCHEDULER_cancel (sched,
4256                                n->timeout_task);
4257       n->timeout_task =
4258         GNUNET_SCHEDULER_add_delayed (sched,
4259                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4260                                       &neighbour_timeout_task, n);
4261       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4262         {
4263           /* dropping message due to frequent inbound volume violations! */
4264           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4265                       GNUNET_ERROR_TYPE_BULK,
4266                       _
4267                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
4268                       n->in_tracker.available_bytes_per_s__,
4269                       n->quota_violation_count);
4270           GNUNET_STATISTICS_update (stats,
4271                                     gettext_noop ("# bandwidth quota violations by other peers"),
4272                                     1,
4273                                     GNUNET_NO);
4274           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4275         }
4276 #if DEBUG_PING_PONG
4277           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4278                       "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4279                       ntohs (message->type), 
4280                       ntohs (message->size), 
4281                       GNUNET_i2s (peer));
4282 #endif
4283       switch (ntohs (message->type))
4284         {
4285         case GNUNET_MESSAGE_TYPE_HELLO:
4286           GNUNET_STATISTICS_update (stats,
4287                                     gettext_noop ("# HELLO messages received from other peers"),
4288                                     1,
4289                                     GNUNET_NO);
4290           process_hello (plugin, message);
4291           break;
4292         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4293           handle_ping (plugin, message, peer, sender_address, sender_address_len);
4294           break;
4295         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4296           handle_pong (plugin, message, peer, sender_address, sender_address_len);
4297           break;
4298         default:
4299           handle_payload_message (message, n);
4300           break;
4301         }
4302     }  
4303   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4304   if (ret.value > 0)
4305     {
4306       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4307                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4308                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
4309                   (unsigned int) n->in_tracker.available_bytes_per_s__,
4310                   (unsigned long long) ret.value);
4311       GNUNET_STATISTICS_update (stats,
4312                                 gettext_noop ("# ms throttling suggested"),
4313                                 (int64_t) ret.value,
4314                                 GNUNET_NO);      
4315     }
4316   return ret;
4317 }
4318
4319 /**
4320  * Handle START-message.  This is the first message sent to us
4321  * by any client which causes us to add it to our list.
4322  *
4323  * @param cls closure (always NULL)
4324  * @param client identification of the client
4325  * @param message the actual message
4326  */
4327 static void
4328 handle_start (void *cls,
4329               struct GNUNET_SERVER_Client *client,
4330               const struct GNUNET_MessageHeader *message)
4331 {
4332   struct TransportClient *c;
4333   struct ConnectInfoMessage cim;
4334   struct NeighbourList *n;
4335
4336 #if DEBUG_TRANSPORT
4337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4338               "Received `%s' request from client\n", "START");
4339 #endif
4340   c = clients;
4341   while (c != NULL)
4342     {
4343       if (c->client == client)
4344         {
4345           /* client already on our list! */
4346           GNUNET_break (0);
4347           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4348           return;
4349         }
4350       c = c->next;
4351     }
4352   c = GNUNET_malloc (sizeof (struct TransportClient));
4353   c->next = clients;
4354   clients = c;
4355   c->client = client;
4356   if (our_hello != NULL)
4357     {
4358 #if DEBUG_TRANSPORT
4359       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4360                   "Sending our own `%s' to new client\n", "HELLO");
4361 #endif
4362       transmit_to_client (c,
4363                           (const struct GNUNET_MessageHeader *) our_hello,
4364                           GNUNET_NO);
4365       /* tell new client about all existing connections */
4366       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
4367       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4368       n = neighbours; 
4369       while (n != NULL)
4370         {
4371           if (GNUNET_YES == n->received_pong)
4372             {
4373               cim.id = n->id;
4374               cim.latency = GNUNET_TIME_relative_hton (n->latency);
4375               cim.distance = htonl (n->distance);
4376               transmit_to_client (c, &cim.header, GNUNET_NO);
4377             }
4378             n = n->next;
4379         }
4380     }
4381   GNUNET_SERVER_receive_done (client, GNUNET_OK);
4382 }
4383
4384
4385 /**
4386  * Handle HELLO-message.
4387  *
4388  * @param cls closure (always NULL)
4389  * @param client identification of the client
4390  * @param message the actual message
4391  */
4392 static void
4393 handle_hello (void *cls,
4394               struct GNUNET_SERVER_Client *client,
4395               const struct GNUNET_MessageHeader *message)
4396 {
4397   int ret;
4398
4399   GNUNET_STATISTICS_update (stats,
4400                             gettext_noop ("# HELLOs received from clients"),
4401                             1,
4402                             GNUNET_NO);      
4403   ret = process_hello (NULL, message);
4404   GNUNET_SERVER_receive_done (client, ret);
4405 }
4406
4407
4408 /**
4409  * Closure for 'transmit_client_message'; followed by
4410  * 'msize' bytes of the actual message.
4411  */
4412 struct TransmitClientMessageContext 
4413 {
4414   /**
4415    * Client on whom's behalf we are sending.
4416    */
4417   struct GNUNET_SERVER_Client *client;
4418
4419   /**
4420    * Timeout for the transmission.
4421    */
4422   struct GNUNET_TIME_Absolute timeout;
4423   
4424   /**
4425    * Message priority.
4426    */
4427   uint32_t priority;
4428
4429   /**
4430    * Size of the message in bytes.
4431    */ 
4432   uint16_t msize;
4433 };
4434
4435
4436 /**
4437  * Schedule transmission of a message we got from a client to a peer.
4438  *
4439  * @param cls the 'struct TransmitClientMessageContext*'
4440  * @param n destination, or NULL on error (in that case, drop the message)
4441  */
4442 static void
4443 transmit_client_message (void *cls,
4444                          struct NeighbourList *n)
4445 {
4446   struct TransmitClientMessageContext *tcmc = cls;
4447   struct TransportClient *tc;
4448
4449   tc = clients;
4450   while ((tc != NULL) && (tc->client != tcmc->client))
4451     tc = tc->next;
4452
4453   if (n != NULL)
4454     {
4455       transmit_to_peer (tc, NULL, tcmc->priority, 
4456                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
4457                         (char *)&tcmc[1],
4458                         tcmc->msize, GNUNET_NO, n);
4459     }
4460   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
4461   GNUNET_SERVER_client_drop (tcmc->client);
4462   GNUNET_free (tcmc);
4463 }
4464
4465
4466 /**
4467  * Handle SEND-message.
4468  *
4469  * @param cls closure (always NULL)
4470  * @param client identification of the client
4471  * @param message the actual message
4472  */
4473 static void
4474 handle_send (void *cls,
4475              struct GNUNET_SERVER_Client *client,
4476              const struct GNUNET_MessageHeader *message)
4477 {
4478   const struct OutboundMessage *obm;
4479   const struct GNUNET_MessageHeader *obmm;
4480   struct TransmitClientMessageContext *tcmc;
4481   uint16_t size;
4482   uint16_t msize;
4483
4484   size = ntohs (message->size);
4485   if (size <
4486       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
4487     {
4488       GNUNET_break (0);
4489       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4490       return;
4491     }
4492   GNUNET_STATISTICS_update (stats,
4493                             gettext_noop ("# payload received for other peers"),
4494                             size,
4495                             GNUNET_NO);      
4496   obm = (const struct OutboundMessage *) message;
4497   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4498   msize = size - sizeof (struct OutboundMessage);
4499 #if DEBUG_TRANSPORT
4500   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4501               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
4502               "SEND", GNUNET_i2s (&obm->peer),
4503               ntohs (obmm->type),
4504               msize);
4505 #endif
4506   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
4507   tcmc->client = client;
4508   tcmc->priority = ntohl (obm->priority);
4509   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
4510   tcmc->msize = msize;
4511   memcpy (&tcmc[1], obmm, msize);
4512   GNUNET_SERVER_client_keep (client);
4513   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
4514                               &transmit_client_message,
4515                               tcmc);
4516 }
4517
4518
4519 /**
4520  * Handle SET_QUOTA-message.
4521  *
4522  * @param cls closure (always NULL)
4523  * @param client identification of the client
4524  * @param message the actual message
4525  */
4526 static void
4527 handle_set_quota (void *cls,
4528                   struct GNUNET_SERVER_Client *client,
4529                   const struct GNUNET_MessageHeader *message)
4530 {
4531   const struct QuotaSetMessage *qsm =
4532     (const struct QuotaSetMessage *) message;
4533   struct NeighbourList *n;
4534   
4535   GNUNET_STATISTICS_update (stats,
4536                             gettext_noop ("# SET QUOTA messages received"),
4537                             1,
4538                             GNUNET_NO);      
4539   n = find_neighbour (&qsm->peer);
4540   if (n == NULL)
4541     {
4542       GNUNET_SERVER_receive_done (client, GNUNET_OK);
4543       GNUNET_STATISTICS_update (stats,
4544                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
4545                                 1,
4546                                 GNUNET_NO);      
4547       return;
4548     }
4549 #if DEBUG_TRANSPORT
4550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4551               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
4552               "SET_QUOTA", 
4553               (unsigned int) ntohl (qsm->quota.value__),
4554               (unsigned int) n->in_tracker.available_bytes_per_s__,
4555               GNUNET_i2s (&qsm->peer));
4556 #endif
4557   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
4558                                          qsm->quota);
4559   if (0 == ntohl (qsm->quota.value__)) 
4560     disconnect_neighbour (n, GNUNET_NO);    
4561   GNUNET_SERVER_receive_done (client, GNUNET_OK);
4562 }
4563
4564
4565 /**
4566  * Take the given address and append it to the set of results sent back to
4567  * the client.
4568  * 
4569  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
4570  * @param address the resolved name, NULL to indicate the last response
4571  */
4572 static void
4573 transmit_address_to_client (void *cls, const char *address)
4574 {
4575   struct GNUNET_SERVER_TransmitContext *tc = cls;
4576   size_t slen;
4577
4578   if (NULL == address)
4579     slen = 0;
4580   else
4581     slen = strlen (address) + 1;
4582
4583   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
4584                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4585   if (NULL == address)
4586     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
4587 }
4588
4589
4590 /**
4591  * Handle AddressLookup-message.
4592  *
4593  * @param cls closure (always NULL)
4594  * @param client identification of the client
4595  * @param message the actual message
4596  */
4597 static void
4598 handle_address_lookup (void *cls,
4599                        struct GNUNET_SERVER_Client *client,
4600                        const struct GNUNET_MessageHeader *message)
4601 {
4602   const struct AddressLookupMessage *alum;
4603   struct TransportPlugin *lsPlugin;
4604   const char *nameTransport;
4605   const char *address;
4606   uint16_t size;
4607   struct GNUNET_SERVER_TransmitContext *tc;
4608   struct GNUNET_TIME_Absolute timeout;
4609   struct GNUNET_TIME_Relative rtimeout;
4610   int32_t numeric;
4611
4612   size = ntohs (message->size);
4613   if (size < sizeof (struct AddressLookupMessage))
4614     {
4615       GNUNET_break_op (0);
4616       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4617       return;
4618     }
4619   alum = (const struct AddressLookupMessage *) message;
4620   uint32_t addressLen = ntohl (alum->addrlen);
4621   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
4622     {
4623       GNUNET_break_op (0);
4624       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4625       return;
4626     }
4627   address = (const char *) &alum[1];
4628   nameTransport = (const char *) &address[addressLen];
4629   if (nameTransport
4630       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
4631     {
4632       GNUNET_break_op (0);
4633       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4634       return;
4635     }
4636   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4637   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4638   numeric = ntohl (alum->numeric_only);
4639   lsPlugin = find_transport (nameTransport);
4640   if (NULL == lsPlugin)
4641     {
4642       tc = GNUNET_SERVER_transmit_context_create (client);
4643       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4644                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4645       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4646       return;
4647     }
4648   tc = GNUNET_SERVER_transmit_context_create (client);
4649   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4650                                          nameTransport,
4651                                          address, addressLen, 
4652                                          numeric,
4653                                          rtimeout,
4654                                          &transmit_address_to_client, tc);
4655 }
4656
4657
4658 /**
4659  * Setup the environment for this plugin.
4660  */
4661 static void
4662 create_environment (struct TransportPlugin *plug)
4663 {
4664   plug->env.cfg = cfg;
4665   plug->env.sched = sched;
4666   plug->env.my_identity = &my_identity;
4667   plug->env.cls = plug;
4668   plug->env.receive = &plugin_env_receive;
4669   plug->env.notify_address = &plugin_env_notify_address;
4670   plug->env.session_end = &plugin_env_session_end;
4671   plug->env.max_connections = max_connect_per_transport;
4672   plug->env.stats = stats;
4673 }
4674
4675
4676 /**
4677  * Start the specified transport (load the plugin).
4678  */
4679 static void
4680 start_transport (struct GNUNET_SERVER_Handle *server, 
4681                  const char *name)
4682 {
4683   struct TransportPlugin *plug;
4684   char *libname;
4685
4686   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4687               _("Loading `%s' transport plugin\n"), name);
4688   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4689   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4690   create_environment (plug);
4691   plug->short_name = GNUNET_strdup (name);
4692   plug->lib_name = libname;
4693   plug->next = plugins;
4694   plugins = plug;
4695   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4696   if (plug->api == NULL)
4697     {
4698       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4699                   _("Failed to load transport plugin for `%s'\n"), name);
4700       GNUNET_free (plug->short_name);
4701       plugins = plug->next;
4702       GNUNET_free (libname);
4703       GNUNET_free (plug);
4704     }
4705 }
4706
4707
4708 /**
4709  * Called whenever a client is disconnected.  Frees our
4710  * resources associated with that client.
4711  *
4712  * @param cls closure
4713  * @param client identification of the client
4714  */
4715 static void
4716 client_disconnect_notification (void *cls,
4717                                 struct GNUNET_SERVER_Client *client)
4718 {
4719   struct TransportClient *pos;
4720   struct TransportClient *prev;
4721   struct ClientMessageQueueEntry *mqe;
4722   struct Blacklisters *bl;
4723   struct BlacklistCheck *bc;
4724
4725   if (client == NULL)
4726     return;
4727 #if DEBUG_TRANSPORT
4728   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4729               "Client disconnected, cleaning up.\n");
4730 #endif
4731   /* clean up blacklister */
4732   bl = bl_head;
4733   while (bl != NULL)
4734     {
4735       if (bl->client == client)
4736         {
4737           bc = bc_head;
4738           while (bc != NULL)
4739             {
4740               if (bc->bl_pos == bl)
4741                 {
4742                   bc->bl_pos = bl->next;
4743                   if (bc->th != NULL)
4744                     {
4745                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
4746                       bc->th = NULL;                  
4747                     }
4748                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
4749                     bc->task = GNUNET_SCHEDULER_add_now (sched,
4750                                                          &do_blacklist_check,
4751                                                          bc);
4752                   break;
4753                 }
4754               bc = bc->next;
4755             }
4756           GNUNET_CONTAINER_DLL_remove (bl_head,
4757                                        bl_tail,
4758                                        bl);
4759           GNUNET_SERVER_client_drop (bl->client);
4760           GNUNET_free (bl);
4761           break;
4762         }
4763       bl = bl->next;
4764     }
4765   /* clean up 'normal' clients */
4766   prev = NULL;
4767   pos = clients;
4768   while ((pos != NULL) && (pos->client != client))
4769     {
4770       prev = pos;
4771       pos = pos->next;
4772     }
4773   if (pos == NULL)
4774     return;
4775   while (NULL != (mqe = pos->message_queue_head))
4776     {
4777       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4778                                    pos->message_queue_tail,
4779                                    mqe);
4780       pos->message_count--;
4781       GNUNET_free (mqe);
4782     }
4783   if (prev == NULL)
4784     clients = pos->next;
4785   else
4786     prev->next = pos->next;
4787   if (GNUNET_YES == pos->tcs_pending)
4788     {
4789       pos->client = NULL;
4790       return;
4791     }
4792   if (pos->th != NULL)
4793     {
4794       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4795       pos->th = NULL;
4796     }
4797   GNUNET_break (0 == pos->message_count);
4798   GNUNET_free (pos);
4799 }
4800
4801
4802 /**
4803  * Function called when the service shuts down.  Unloads our plugins
4804  * and cancels pending validations.
4805  *
4806  * @param cls closure, unused
4807  * @param tc task context (unused)
4808  */
4809 static void
4810 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4811 {
4812   struct TransportPlugin *plug;
4813   struct OwnAddressList *al;
4814   struct CheckHelloValidatedContext *chvc;
4815
4816   while (neighbours != NULL)
4817     disconnect_neighbour (neighbours, GNUNET_NO);
4818 #if DEBUG_TRANSPORT
4819   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4820               "Transport service is unloading plugins...\n");
4821 #endif
4822   while (NULL != (plug = plugins))
4823     {
4824       plugins = plug->next;
4825       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4826         {
4827           GNUNET_SCHEDULER_cancel (plug->env.sched, 
4828                                    plug->address_update_task);
4829           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4830         }
4831       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4832       GNUNET_free (plug->lib_name);
4833       GNUNET_free (plug->short_name);
4834       while (NULL != (al = plug->addresses))
4835         {
4836           plug->addresses = al->next;
4837           GNUNET_free (al);
4838         }
4839       GNUNET_free (plug);
4840     }
4841   if (my_private_key != NULL)
4842     GNUNET_CRYPTO_rsa_key_free (my_private_key);
4843   GNUNET_free_non_null (our_hello);
4844
4845   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4846                                          &abort_validation,
4847                                          NULL);
4848   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4849   validation_map = NULL;
4850
4851   /* free 'chvc' data structure */
4852   while (NULL != (chvc = chvc_head))
4853     {
4854       chvc_head = chvc->next;
4855       if (chvc->piter != NULL)
4856         GNUNET_PEERINFO_iterate_cancel (chvc->piter);      
4857       else
4858         GNUNET_break (0);
4859       GNUNET_assert (chvc->ve_count == 0);
4860       GNUNET_free (chvc);
4861     }
4862   chvc_tail = NULL;
4863
4864   if (stats != NULL)
4865     {
4866       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4867       stats = NULL;
4868     }
4869   if (peerinfo != NULL)
4870     {
4871       GNUNET_PEERINFO_disconnect (peerinfo);
4872       peerinfo = NULL;
4873     }
4874   /* Can we assume those are gone by now, or do we need to clean up
4875      explicitly!? */
4876   GNUNET_break (bl_head == NULL);
4877   GNUNET_break (bc_head == NULL);
4878 }
4879
4880
4881 /**
4882  * Initiate transport service.
4883  *
4884  * @param cls closure
4885  * @param s scheduler to use
4886  * @param server the initialized server
4887  * @param c configuration to use
4888  */
4889 static void
4890 run (void *cls,
4891      struct GNUNET_SCHEDULER_Handle *s,
4892      struct GNUNET_SERVER_Handle *server,
4893      const struct GNUNET_CONFIGURATION_Handle *c)
4894 {
4895   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
4896     {&handle_start, NULL,
4897      GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4898     {&handle_hello, NULL,
4899      GNUNET_MESSAGE_TYPE_HELLO, 0},
4900     {&handle_send, NULL,
4901      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4902     {&handle_set_quota, NULL,
4903      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4904     {&handle_address_lookup, NULL,
4905      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4906      0},
4907     {&handle_blacklist_init, NULL,
4908      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
4909     {&handle_blacklist_reply, NULL,
4910      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
4911     {NULL, NULL, 0, 0}
4912   };
4913   char *plugs;
4914   char *pos;
4915   int no_transports;
4916   unsigned long long tneigh;
4917   char *keyfile;
4918
4919   sched = s;
4920   cfg = c;
4921   stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4922   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4923   /* parse configuration */
4924   if ((GNUNET_OK !=
4925        GNUNET_CONFIGURATION_get_value_number (c,
4926                                               "TRANSPORT",
4927                                               "NEIGHBOUR_LIMIT",
4928                                               &tneigh)) ||
4929       (GNUNET_OK !=
4930        GNUNET_CONFIGURATION_get_value_filename (c,
4931                                                 "GNUNETD",
4932                                                 "HOSTKEY", &keyfile)))
4933     {
4934       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4935                   _
4936                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
4937       GNUNET_SCHEDULER_shutdown (s);
4938       if (stats != NULL)
4939         {
4940           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4941           stats = NULL;
4942         }
4943       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4944       validation_map = NULL;
4945       return;
4946     }
4947   max_connect_per_transport = (uint32_t) tneigh;
4948   peerinfo = GNUNET_PEERINFO_connect (sched, cfg);
4949   if (peerinfo == NULL)
4950     {
4951       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4952                   _("Could not access PEERINFO service.  Exiting.\n"));     
4953       GNUNET_SCHEDULER_shutdown (s);
4954       if (stats != NULL)
4955         {
4956           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4957           stats = NULL;
4958         }
4959       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4960       validation_map = NULL;
4961       GNUNET_free (keyfile);
4962       return;
4963     }
4964   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4965   GNUNET_free (keyfile);
4966   if (my_private_key == NULL)
4967     {
4968       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4969                   _
4970                   ("Transport service could not access hostkey.  Exiting.\n"));
4971       GNUNET_SCHEDULER_shutdown (s);
4972       if (stats != NULL)
4973         {
4974           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4975           stats = NULL;
4976         }
4977       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4978       validation_map = NULL;
4979       return;
4980     }
4981   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4982   GNUNET_CRYPTO_hash (&my_public_key,
4983                       sizeof (my_public_key), &my_identity.hashPubKey);
4984   /* setup notification */
4985   GNUNET_SERVER_disconnect_notify (server,
4986                                    &client_disconnect_notification, NULL);
4987   /* load plugins... */
4988   no_transports = 1;
4989   if (GNUNET_OK ==
4990       GNUNET_CONFIGURATION_get_value_string (c,
4991                                              "TRANSPORT", "PLUGINS", &plugs))
4992     {
4993       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4994                   _("Starting transport plugins `%s'\n"), plugs);
4995       pos = strtok (plugs, " ");
4996       while (pos != NULL)
4997         {
4998           start_transport (server, pos);
4999           no_transports = 0;
5000           pos = strtok (NULL, " ");
5001         }
5002       GNUNET_free (plugs);
5003     }
5004   GNUNET_SCHEDULER_add_delayed (sched,
5005                                 GNUNET_TIME_UNIT_FOREVER_REL,
5006                                 &shutdown_task, NULL);
5007   if (no_transports)
5008     refresh_hello ();
5009
5010 #if DEBUG_TRANSPORT
5011   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
5012 #endif
5013   /* If we have a blacklist file, read from it */
5014   read_blacklist_file(cfg);
5015   /* process client requests */
5016   GNUNET_SERVER_add_handlers (server, handlers);
5017 }
5018
5019
5020 /**
5021  * The main function for the transport service.
5022  *
5023  * @param argc number of arguments from the command line
5024  * @param argv command line arguments
5025  * @return 0 ok, 1 on error
5026  */
5027 int
5028 main (int argc, char *const *argv)
5029 {
5030   a2s (NULL, NULL, 0); /* make compiler happy */
5031   return (GNUNET_OK ==
5032           GNUNET_SERVICE_run (argc,
5033                               argv,
5034                               "transport",
5035                               GNUNET_SERVICE_OPTION_NONE,
5036                               &run, NULL)) ? 0 : 1;
5037 }
5038
5039 /* end of gnunet-service-transport.c */