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