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