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