fmt
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/gnunet-service-transport.c
23  * @brief low-level P2P messaging
24  * @author Christian Grothoff
25  *
26  * 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 /**
3664  * Process HELLO-message.
3665  *
3666  * @param plugin transport involved, may be NULL
3667  * @param message the actual message
3668  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
3669  */
3670 static int
3671 process_hello (struct TransportPlugin *plugin,
3672                const struct GNUNET_MessageHeader *message)
3673 {
3674   uint16_t hsize;
3675   struct GNUNET_PeerIdentity target;
3676   const struct GNUNET_HELLO_Message *hello;
3677   struct CheckHelloValidatedContext *chvc;
3678   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
3679
3680   hsize = ntohs (message->size);
3681   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
3682       (hsize < sizeof (struct GNUNET_MessageHeader)))
3683     {
3684       GNUNET_break (0);
3685       return GNUNET_SYSERR;
3686     }
3687   GNUNET_STATISTICS_update (stats,
3688                             gettext_noop ("# HELLOs received for validation"),
3689                             1,
3690                             GNUNET_NO);      
3691   /* first, check if load is too high */
3692   if (GNUNET_SCHEDULER_get_load (sched,
3693                                  GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
3694     {
3695       GNUNET_STATISTICS_update (stats,
3696                                 gettext_noop ("# HELLOs ignored due to high load"),
3697                                 1,
3698                                 GNUNET_NO);      
3699       return GNUNET_OK;
3700     }
3701   hello = (const struct GNUNET_HELLO_Message *) message;
3702   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3703     {
3704       GNUNET_break_op (0);
3705       return GNUNET_SYSERR;
3706     }
3707   GNUNET_CRYPTO_hash (&publicKey,
3708                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3709                       &target.hashPubKey);
3710   if (0 == memcmp (&my_identity,
3711                    &target,
3712                    sizeof (struct GNUNET_PeerIdentity)))
3713     {
3714       GNUNET_STATISTICS_update (stats,
3715                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3716                                 1,
3717                                 GNUNET_NO);      
3718       return GNUNET_OK;      
3719     }
3720 #if DEBUG_TRANSPORT > 1
3721   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3722               "Processing `%s' message for `%4s' of size %u\n",
3723               "HELLO", 
3724               GNUNET_i2s (&target), 
3725               GNUNET_HELLO_size(hello));
3726 #endif
3727   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3728   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3729   memcpy (&chvc[1], hello, hsize);
3730   GNUNET_CONTAINER_DLL_insert (chvc_head,
3731                                chvc_tail,
3732                                chvc);
3733   /* finally, check if HELLO was previously validated
3734      (continuation will then schedule actual validation) */
3735   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
3736                                          sched,
3737                                          &target,
3738                                          0,
3739                                          HELLO_VERIFICATION_TIMEOUT,
3740                                          &check_hello_validated, chvc);
3741   return GNUNET_OK;
3742 }
3743
3744
3745 /**
3746  * The peer specified by the given neighbour has timed-out or a plugin
3747  * has disconnected.  We may either need to do nothing (other plugins
3748  * still up), or trigger a full disconnect and clean up.  This
3749  * function updates our state and does the necessary notifications.
3750  * Also notifies our clients that the neighbour is now officially
3751  * gone.
3752  *
3753  * @param n the neighbour list entry for the peer
3754  * @param check should we just check if all plugins
3755  *        disconnected or must we ask all plugins to
3756  *        disconnect?
3757  */
3758 static void
3759 disconnect_neighbour (struct NeighbourList *n, int check)
3760 {
3761   struct ReadyList *rpos;
3762   struct NeighbourList *npos;
3763   struct NeighbourList *nprev;
3764   struct MessageQueue *mq;
3765   struct ForeignAddressList *peer_addresses;
3766   struct ForeignAddressList *peer_pos;
3767
3768   if (GNUNET_YES == check)
3769     {
3770       rpos = n->plugins;
3771       while (NULL != rpos)
3772         {
3773           peer_addresses = rpos->addresses;
3774           while (peer_addresses != NULL)
3775             {
3776               if (GNUNET_YES == peer_addresses->connected)
3777                 return;             /* still connected */
3778               peer_addresses = peer_addresses->next;
3779             }
3780           rpos = rpos->next;
3781         }
3782     }
3783 #if DEBUG_TRANSPORT
3784   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3785               "Disconnecting from `%4s'\n",
3786               GNUNET_i2s (&n->id));
3787 #endif
3788   /* remove n from neighbours list */
3789   nprev = NULL;
3790   npos = neighbours;
3791   while ((npos != NULL) && (npos != n))
3792     {
3793       nprev = npos;
3794       npos = npos->next;
3795     }
3796   GNUNET_assert (npos != NULL);
3797   if (nprev == NULL)
3798     neighbours = n->next;
3799   else
3800     nprev->next = n->next;
3801
3802   /* notify all clients about disconnect */
3803   if (GNUNET_YES == n->received_pong)
3804     notify_clients_disconnect (&n->id);
3805
3806   /* clean up all plugins, cancel connections and pending transmissions */
3807   while (NULL != (rpos = n->plugins))
3808     {
3809       n->plugins = rpos->next;
3810       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3811       while (rpos->addresses != NULL)
3812         {
3813           peer_pos = rpos->addresses;
3814           rpos->addresses = peer_pos->next;
3815           if (peer_pos->connected == GNUNET_YES)
3816             GNUNET_STATISTICS_update (stats,
3817                                       gettext_noop ("# connected addresses"),
3818                                       -1,
3819                                       GNUNET_NO); 
3820           if (GNUNET_YES == peer_pos->validated)
3821             GNUNET_STATISTICS_update (stats,
3822                                       gettext_noop ("# peer addresses considered valid"),
3823                                       -1,
3824                                       GNUNET_NO);      
3825           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3826             {
3827               GNUNET_SCHEDULER_cancel (sched,
3828                                        peer_pos->revalidate_task);
3829               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3830             }
3831           GNUNET_free(peer_pos);
3832         }
3833       GNUNET_free (rpos);
3834     }
3835
3836   /* free all messages on the queue */
3837   while (NULL != (mq = n->messages_head))
3838     {
3839       GNUNET_STATISTICS_update (stats,
3840                                 gettext_noop ("# bytes in message queue for other peers"),
3841                                 - (int64_t) mq->message_buf_size,
3842                                 GNUNET_NO);
3843       GNUNET_STATISTICS_update (stats,
3844                                 gettext_noop ("# bytes discarded due to disconnect"),
3845                                 mq->message_buf_size,
3846                                 GNUNET_NO);
3847       GNUNET_CONTAINER_DLL_remove (n->messages_head,
3848                                    n->messages_tail,
3849                                    mq);
3850       GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
3851                                  &n->id,
3852                                  sizeof(struct GNUNET_PeerIdentity)));
3853       GNUNET_free (mq);
3854     }
3855   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3856     {
3857       GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3858       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3859     }
3860   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3861     {
3862       GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3863       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3864     }
3865   if (n->piter != NULL)
3866     {
3867       GNUNET_PEERINFO_iterate_cancel (n->piter);
3868       n->piter = NULL;
3869     }
3870   /* finally, free n itself */
3871   GNUNET_STATISTICS_update (stats,
3872                             gettext_noop ("# active neighbours"),
3873                             -1,
3874                             GNUNET_NO);
3875   GNUNET_free_non_null (n->pre_connect_message_buffer);
3876   GNUNET_free (n);
3877 }
3878
3879
3880 /**
3881  * We have received a PING message from someone.  Need to send a PONG message
3882  * in response to the peer by any means necessary. 
3883  */
3884 static int 
3885 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3886             const struct GNUNET_PeerIdentity *peer,
3887             const char *sender_address,
3888             size_t sender_address_len)
3889 {
3890   struct TransportPlugin *plugin = cls;
3891   struct TransportPingMessage *ping;
3892   struct TransportPongMessage *pong;
3893   struct NeighbourList *n;
3894   struct ReadyList *rl;
3895   struct ForeignAddressList *fal;
3896
3897   if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3898     {
3899       GNUNET_break_op (0);
3900       return GNUNET_SYSERR;
3901     }
3902
3903   ping = (struct TransportPingMessage *) message;
3904   if (0 != memcmp (&ping->target,
3905                    plugin->env.my_identity,
3906                    sizeof (struct GNUNET_PeerIdentity)))
3907     {
3908       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3909                   _("Received `%s' message not destined for me!\n"), 
3910                   "PING");
3911       return GNUNET_SYSERR;
3912     }
3913 #if DEBUG_PING_PONG
3914   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3915               "Processing `%s' from `%s'\n",
3916               "PING", 
3917               (sender_address != NULL) 
3918               ? GNUNET_a2s ((const struct sockaddr *)sender_address, 
3919                             sender_address_len)
3920               : "<inbound>");
3921 #endif
3922   GNUNET_STATISTICS_update (stats,
3923                             gettext_noop ("# PING messages received"),
3924                             1,
3925                             GNUNET_NO);
3926   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3927   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3928   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3929   pong->purpose.size =
3930     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3931            sizeof (uint32_t) +
3932            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3933   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3934   pong->challenge = ping->challenge;
3935   pong->addrlen = htons(sender_address_len);
3936   memcpy(&pong->signer, 
3937          &my_public_key, 
3938          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3939   if (sender_address != NULL)
3940     memcpy (&pong[1], sender_address, sender_address_len);
3941   GNUNET_assert (GNUNET_OK ==
3942                  GNUNET_CRYPTO_rsa_sign (my_private_key,
3943                                          &pong->purpose, &pong->signature));
3944   n = find_neighbour(peer);
3945   GNUNET_assert (n != NULL);
3946   /* first try reliable response transmission */
3947   rl = n->plugins;
3948   while (rl != NULL)
3949     {
3950       fal = rl->addresses;
3951       while (fal != NULL)
3952         {
3953           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3954                                            peer,
3955                                            (const char*) pong,
3956                                            ntohs (pong->header.size),
3957                                            TRANSPORT_PONG_PRIORITY, 
3958                                            HELLO_VERIFICATION_TIMEOUT,
3959                                            fal->session,
3960                                            fal->addr,
3961                                            fal->addrlen,
3962                                            GNUNET_SYSERR,
3963                                            NULL, NULL))
3964             {
3965               /* done! */
3966               GNUNET_STATISTICS_update (stats,
3967                                         gettext_noop ("# PONGs unicast via reliable transport"),
3968                                         1,
3969                                         GNUNET_NO);      
3970               GNUNET_free (pong);
3971               return GNUNET_OK;
3972             }
3973           fal = fal->next;
3974         }
3975       rl = rl->next;
3976     }
3977   /* no reliable method found, do multicast */
3978   GNUNET_STATISTICS_update (stats,
3979                             gettext_noop ("# PONGs multicast to all available addresses"),
3980                             1,
3981                             GNUNET_NO);      
3982   rl = n->plugins;
3983   while (rl != NULL)
3984     {
3985       fal = rl->addresses;
3986       while (fal != NULL)
3987         {
3988           transmit_to_peer(NULL, fal,
3989                            TRANSPORT_PONG_PRIORITY, 
3990                            HELLO_VERIFICATION_TIMEOUT,
3991                            (const char *)pong, 
3992                            ntohs(pong->header.size), 
3993                            GNUNET_YES, 
3994                            n);
3995           fal = fal->next;
3996         }
3997       rl = rl->next;
3998     }
3999   GNUNET_free(pong);
4000   return GNUNET_OK;
4001 }
4002
4003
4004 /**
4005  * Function called by the plugin for each received message.
4006  * Update data volumes, possibly notify plugins about
4007  * reducing the rate at which they read from the socket
4008  * and generally forward to our receive callback.
4009  *
4010  * @param cls the "struct TransportPlugin *" we gave to the plugin
4011  * @param peer (claimed) identity of the other peer
4012  * @param message the message, NULL if we only care about
4013  *                learning about the delay until we should receive again
4014  * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
4015  * @param session identifier used for this session (can be NULL)
4016  * @param sender_address binary address of the sender (if observed)
4017  * @param sender_address_len number of bytes in sender_address
4018  * @return how long the plugin should wait until receiving more data
4019  *         (plugins that do not support this, can ignore the return value)
4020  */
4021 static struct GNUNET_TIME_Relative
4022 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4023                     const struct GNUNET_MessageHeader *message,
4024                     unsigned int distance,
4025                     struct Session *session,
4026                     const char *sender_address,
4027                     size_t sender_address_len)
4028 {
4029   struct TransportPlugin *plugin = cls;
4030   struct ReadyList *service_context;
4031   struct ForeignAddressList *peer_address;
4032   uint16_t msize;
4033   struct NeighbourList *n;
4034   struct GNUNET_TIME_Relative ret;
4035
4036   if (is_blacklisted (peer, plugin))
4037     return GNUNET_TIME_UNIT_FOREVER_REL;
4038
4039   n = find_neighbour (peer);
4040   if (n == NULL)
4041     n = setup_new_neighbour (peer, GNUNET_YES);
4042   service_context = n->plugins;
4043   while ((service_context != NULL) && (plugin != service_context->plugin))
4044     service_context = service_context->next;
4045   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4046   peer_address = NULL;
4047   if (message != NULL)
4048     {
4049       if ( (session != NULL) ||
4050            (sender_address != NULL) )
4051         peer_address = add_peer_address (n, 
4052                                          plugin->short_name,
4053                                          session,
4054                                          sender_address, 
4055                                          sender_address_len);  
4056       if (peer_address != NULL)
4057         {
4058           peer_address->distance = distance;
4059           if (GNUNET_YES == peer_address->validated)
4060             mark_address_connected (peer_address);
4061           peer_address->timeout
4062             =
4063             GNUNET_TIME_relative_to_absolute
4064             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4065           schedule_next_ping (peer_address);
4066         }
4067       /* update traffic received amount ... */
4068       msize = ntohs (message->size);      
4069       GNUNET_STATISTICS_update (stats,
4070                                 gettext_noop ("# bytes received from other peers"),
4071                                 msize,
4072                                 GNUNET_NO);
4073       n->distance = distance;
4074       n->peer_timeout =
4075         GNUNET_TIME_relative_to_absolute
4076         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4077       GNUNET_SCHEDULER_cancel (sched,
4078                                n->timeout_task);
4079       n->timeout_task =
4080         GNUNET_SCHEDULER_add_delayed (sched,
4081                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4082                                       &neighbour_timeout_task, n);
4083       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4084         {
4085           /* dropping message due to frequent inbound volume violations! */
4086           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4087                       GNUNET_ERROR_TYPE_BULK,
4088                       _
4089                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
4090                       n->in_tracker.available_bytes_per_s__,
4091                       n->quota_violation_count);
4092           GNUNET_STATISTICS_update (stats,
4093                                     gettext_noop ("# bandwidth quota violations by other peers"),
4094                                     1,
4095                                     GNUNET_NO);
4096           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4097         }
4098 #if DEBUG_PING_PONG
4099           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4100                       "Received message of type %u from `%4s', sending to all clients.\n",
4101                       ntohs (message->type), GNUNET_i2s (peer));
4102 #endif
4103       switch (ntohs (message->type))
4104         {
4105         case GNUNET_MESSAGE_TYPE_HELLO:
4106           GNUNET_STATISTICS_update (stats,
4107                                     gettext_noop ("# HELLO messages received from other peers"),
4108                                     1,
4109                                     GNUNET_NO);
4110           process_hello (plugin, message);
4111           break;
4112         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4113           handle_ping (plugin, message, peer, sender_address, sender_address_len);
4114           break;
4115         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4116           handle_pong (plugin, message, peer, sender_address, sender_address_len);
4117           break;
4118         default:
4119           handle_payload_message (message, n);
4120           break;
4121         }
4122     }  
4123   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4124   if (ret.value > 0)
4125     {
4126       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4127                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4128                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
4129                   (unsigned int) n->in_tracker.available_bytes_per_s__,
4130                   (unsigned long long) ret.value);
4131       GNUNET_STATISTICS_update (stats,
4132                                 gettext_noop ("# ms throttling suggested"),
4133                                 (int64_t) ret.value,
4134                                 GNUNET_NO);      
4135     }
4136   return ret;
4137 }
4138
4139 /**
4140  * Handle START-message.  This is the first message sent to us
4141  * by any client which causes us to add it to our list.
4142  *
4143  * @param cls closure (always NULL)
4144  * @param client identification of the client
4145  * @param message the actual message
4146  */
4147 static void
4148 handle_start (void *cls,
4149               struct GNUNET_SERVER_Client *client,
4150               const struct GNUNET_MessageHeader *message)
4151 {
4152   struct TransportClient *c;
4153   struct ConnectInfoMessage cim;
4154   struct NeighbourList *n;
4155
4156 #if DEBUG_TRANSPORT
4157   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4158               "Received `%s' request from client\n", "START");
4159 #endif
4160   c = clients;
4161   while (c != NULL)
4162     {
4163       if (c->client == client)
4164         {
4165           /* client already on our list! */
4166           GNUNET_break (0);
4167           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4168           return;
4169         }
4170       c = c->next;
4171     }
4172   c = GNUNET_malloc (sizeof (struct TransportClient));
4173   c->next = clients;
4174   clients = c;
4175   c->client = client;
4176   if (our_hello != NULL)
4177     {
4178 #if DEBUG_TRANSPORT
4179       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4180                   "Sending our own `%s' to new client\n", "HELLO");
4181 #endif
4182       transmit_to_client (c,
4183                           (const struct GNUNET_MessageHeader *) our_hello,
4184                           GNUNET_NO);
4185       /* tell new client about all existing connections */
4186       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
4187       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4188       n = neighbours; 
4189       while (n != NULL)
4190         {
4191           if (GNUNET_YES == n->received_pong)
4192             {
4193               cim.id = n->id;
4194               cim.latency = GNUNET_TIME_relative_hton (n->latency);
4195               cim.distance = htonl (n->distance);
4196               transmit_to_client (c, &cim.header, GNUNET_NO);
4197             }
4198             n = n->next;
4199         }
4200     }
4201   GNUNET_SERVER_receive_done (client, GNUNET_OK);
4202 }
4203
4204
4205 /**
4206  * Handle HELLO-message.
4207  *
4208  * @param cls closure (always NULL)
4209  * @param client identification of the client
4210  * @param message the actual message
4211  */
4212 static void
4213 handle_hello (void *cls,
4214               struct GNUNET_SERVER_Client *client,
4215               const struct GNUNET_MessageHeader *message)
4216 {
4217   int ret;
4218
4219   GNUNET_STATISTICS_update (stats,
4220                             gettext_noop ("# HELLOs received from clients"),
4221                             1,
4222                             GNUNET_NO);      
4223   ret = process_hello (NULL, message);
4224   GNUNET_SERVER_receive_done (client, ret);
4225 }
4226
4227
4228 /**
4229  * Closure for 'transmit_client_message'; followed by
4230  * 'msize' bytes of the actual message.
4231  */
4232 struct TransmitClientMessageContext 
4233 {
4234   /**
4235    * Client on whom's behalf we are sending.
4236    */
4237   struct GNUNET_SERVER_Client *client;
4238
4239   /**
4240    * Timeout for the transmission.
4241    */
4242   struct GNUNET_TIME_Absolute timeout;
4243   
4244   /**
4245    * Message priority.
4246    */
4247   uint32_t priority;
4248
4249   /**
4250    * Size of the message in bytes.
4251    */ 
4252   uint16_t msize;
4253 };
4254
4255
4256 /**
4257  * Schedule transmission of a message we got from a client to a peer.
4258  *
4259  * @param cls the 'struct TransmitClientMessageContext*'
4260  * @param n destination, or NULL on error (in that case, drop the message)
4261  */
4262 static void
4263 transmit_client_message (void *cls,
4264                          struct NeighbourList *n)
4265 {
4266   struct TransmitClientMessageContext *tcmc = cls;
4267   struct TransportClient *tc;
4268
4269   tc = clients;
4270   while ((tc != NULL) && (tc->client != tcmc->client))
4271     tc = tc->next;
4272
4273   if (n != NULL)
4274     {
4275       transmit_to_peer (tc, NULL, tcmc->priority, 
4276                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
4277                         (char *)&tcmc[1],
4278                         tcmc->msize, GNUNET_NO, n);
4279     }
4280   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
4281   GNUNET_SERVER_client_drop (tcmc->client);
4282   GNUNET_free (tcmc);
4283 }
4284
4285
4286 /**
4287  * Handle SEND-message.
4288  *
4289  * @param cls closure (always NULL)
4290  * @param client identification of the client
4291  * @param message the actual message
4292  */
4293 static void
4294 handle_send (void *cls,
4295              struct GNUNET_SERVER_Client *client,
4296              const struct GNUNET_MessageHeader *message)
4297 {
4298   const struct OutboundMessage *obm;
4299   const struct GNUNET_MessageHeader *obmm;
4300   struct TransmitClientMessageContext *tcmc;
4301   uint16_t size;
4302   uint16_t msize;
4303
4304   size = ntohs (message->size);
4305   if (size <
4306       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
4307     {
4308       GNUNET_break (0);
4309       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4310       return;
4311     }
4312   GNUNET_STATISTICS_update (stats,
4313                             gettext_noop ("# payload received for other peers"),
4314                             size,
4315                             GNUNET_NO);      
4316   obm = (const struct OutboundMessage *) message;
4317   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4318   msize = ntohs (obmm->size);
4319 #if DEBUG_TRANSPORT
4320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4321               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
4322               "SEND", GNUNET_i2s (&obm->peer),
4323               ntohs (obmm->type),
4324               msize);
4325 #endif
4326   if (size != msize + sizeof (struct OutboundMessage))
4327     {
4328       GNUNET_break (0);
4329       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4330       return;
4331     }
4332   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
4333   tcmc->client = client;
4334   tcmc->priority = ntohl (obm->priority);
4335   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
4336   tcmc->msize = msize;
4337   memcpy (&tcmc[1], obmm, msize);
4338   GNUNET_SERVER_client_keep (client);
4339   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
4340                               &transmit_client_message,
4341                               tcmc);
4342 }
4343
4344
4345 /**
4346  * Handle SET_QUOTA-message.
4347  *
4348  * @param cls closure (always NULL)
4349  * @param client identification of the client
4350  * @param message the actual message
4351  */
4352 static void
4353 handle_set_quota (void *cls,
4354                   struct GNUNET_SERVER_Client *client,
4355                   const struct GNUNET_MessageHeader *message)
4356 {
4357   const struct QuotaSetMessage *qsm =
4358     (const struct QuotaSetMessage *) message;
4359   struct NeighbourList *n;
4360   
4361   GNUNET_STATISTICS_update (stats,
4362                             gettext_noop ("# SET QUOTA messages received"),
4363                             1,
4364                             GNUNET_NO);      
4365   n = find_neighbour (&qsm->peer);
4366   if (n == NULL)
4367     {
4368       GNUNET_SERVER_receive_done (client, GNUNET_OK);
4369       GNUNET_STATISTICS_update (stats,
4370                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
4371                                 1,
4372                                 GNUNET_NO);      
4373       return;
4374     }
4375 #if DEBUG_TRANSPORT
4376   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4377               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
4378               "SET_QUOTA", 
4379               (unsigned int) ntohl (qsm->quota.value__),
4380               (unsigned int) n->in_tracker.available_bytes_per_s__,
4381               GNUNET_i2s (&qsm->peer));
4382 #endif
4383   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
4384                                          qsm->quota);
4385   if (0 == ntohl (qsm->quota.value__)) 
4386     disconnect_neighbour (n, GNUNET_NO);    
4387   GNUNET_SERVER_receive_done (client, GNUNET_OK);
4388 }
4389
4390
4391 /**
4392  * Take the given address and append it to the set of results send back to
4393  * the client.
4394  * 
4395  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
4396  * @param address the resolved name, NULL to indicate the last response
4397  */
4398 static void
4399 transmit_address_to_client (void *cls, const char *address)
4400 {
4401   struct GNUNET_SERVER_TransmitContext *tc = cls;
4402   size_t slen;
4403
4404   if (NULL == address)
4405     slen = 0;
4406   else
4407     slen = strlen (address) + 1;
4408   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
4409                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4410   if (NULL == address)
4411     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
4412 }
4413
4414
4415 /**
4416  * Handle AddressLookup-message.
4417  *
4418  * @param cls closure (always NULL)
4419  * @param client identification of the client
4420  * @param message the actual message
4421  */
4422 static void
4423 handle_address_lookup (void *cls,
4424                        struct GNUNET_SERVER_Client *client,
4425                        const struct GNUNET_MessageHeader *message)
4426 {
4427   const struct AddressLookupMessage *alum;
4428   struct TransportPlugin *lsPlugin;
4429   const char *nameTransport;
4430   const char *address;
4431   uint16_t size;
4432   struct GNUNET_SERVER_TransmitContext *tc;
4433   struct GNUNET_TIME_Absolute timeout;
4434   struct GNUNET_TIME_Relative rtimeout;
4435   int32_t numeric;
4436
4437   size = ntohs (message->size);
4438   if (size < sizeof (struct AddressLookupMessage))
4439     {
4440       GNUNET_break_op (0);
4441       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4442       return;
4443     }
4444   alum = (const struct AddressLookupMessage *) message;
4445   uint32_t addressLen = ntohl (alum->addrlen);
4446   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
4447     {
4448       GNUNET_break_op (0);
4449       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4450       return;
4451     }
4452   address = (const char *) &alum[1];
4453   nameTransport = (const char *) &address[addressLen];
4454   if (nameTransport
4455       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
4456     {
4457       GNUNET_break_op (0);
4458       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4459       return;
4460     }
4461   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4462   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4463   numeric = ntohl (alum->numeric_only);
4464   lsPlugin = find_transport (nameTransport);
4465   if (NULL == lsPlugin)
4466     {
4467       tc = GNUNET_SERVER_transmit_context_create (client);
4468       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4469                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4470       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4471       return;
4472     }
4473   tc = GNUNET_SERVER_transmit_context_create (client);
4474   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4475                                          nameTransport,
4476                                          address, addressLen, 
4477                                          numeric,
4478                                          rtimeout,
4479                                          &transmit_address_to_client, tc);
4480 }
4481
4482 /**
4483  * List of handlers for the messages understood by this
4484  * service.
4485  */
4486 static struct GNUNET_SERVER_MessageHandler handlers[] = {
4487   {&handle_start, NULL,
4488    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4489   {&handle_hello, NULL,
4490    GNUNET_MESSAGE_TYPE_HELLO, 0},
4491   {&handle_send, NULL,
4492    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4493   {&handle_set_quota, NULL,
4494    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4495   {&handle_address_lookup, NULL,
4496    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4497    0},
4498   {&handle_blacklist_init, NULL,
4499    GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
4500   {&handle_blacklist_reply, NULL,
4501    GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
4502   {NULL, NULL, 0, 0}
4503 };
4504
4505
4506 /**
4507  * Setup the environment for this plugin.
4508  */
4509 static void
4510 create_environment (struct TransportPlugin *plug)
4511 {
4512   plug->env.cfg = cfg;
4513   plug->env.sched = sched;
4514   plug->env.my_identity = &my_identity;
4515   plug->env.cls = plug;
4516   plug->env.receive = &plugin_env_receive;
4517   plug->env.notify_address = &plugin_env_notify_address;
4518   plug->env.session_end = &plugin_env_session_end;
4519   plug->env.max_connections = max_connect_per_transport;
4520   plug->env.stats = stats;
4521 }
4522
4523
4524 /**
4525  * Start the specified transport (load the plugin).
4526  */
4527 static void
4528 start_transport (struct GNUNET_SERVER_Handle *server, 
4529                  const char *name)
4530 {
4531   struct TransportPlugin *plug;
4532   char *libname;
4533
4534   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4535               _("Loading `%s' transport plugin\n"), name);
4536   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4537   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4538   create_environment (plug);
4539   plug->short_name = GNUNET_strdup (name);
4540   plug->lib_name = libname;
4541   plug->next = plugins;
4542   plugins = plug;
4543   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4544   if (plug->api == NULL)
4545     {
4546       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4547                   _("Failed to load transport plugin for `%s'\n"), name);
4548       GNUNET_free (plug->short_name);
4549       plugins = plug->next;
4550       GNUNET_free (libname);
4551       GNUNET_free (plug);
4552     }
4553 }
4554
4555
4556 /**
4557  * Called whenever a client is disconnected.  Frees our
4558  * resources associated with that client.
4559  *
4560  * @param cls closure
4561  * @param client identification of the client
4562  */
4563 static void
4564 client_disconnect_notification (void *cls,
4565                                 struct GNUNET_SERVER_Client *client)
4566 {
4567   struct TransportClient *pos;
4568   struct TransportClient *prev;
4569   struct ClientMessageQueueEntry *mqe;
4570   struct Blacklisters *bl;
4571   struct BlacklistCheck *bc;
4572
4573   if (client == NULL)
4574     return;
4575 #if DEBUG_TRANSPORT
4576   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4577               "Client disconnected, cleaning up.\n");
4578 #endif
4579   /* clean up blacklister */
4580   bl = bl_head;
4581   while (bl != NULL)
4582     {
4583       if (bl->client == client)
4584         {
4585           bc = bc_head;
4586           while (bc != NULL)
4587             {
4588               if (bc->bl_pos == bl)
4589                 {
4590                   bc->bl_pos = bl->next;
4591                   if (bc->th != NULL)
4592                     {
4593                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
4594                       bc->th = NULL;                  
4595                     }
4596                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
4597                     bc->task = GNUNET_SCHEDULER_add_now (sched,
4598                                                          &do_blacklist_check,
4599                                                          bc);
4600                   break;
4601                 }
4602               bc = bc->next;
4603             }
4604           GNUNET_CONTAINER_DLL_remove (bl_head,
4605                                        bl_tail,
4606                                        bl);
4607           GNUNET_SERVER_client_drop (bl->client);
4608           GNUNET_free (bl);
4609           break;
4610         }
4611       bl = bl->next;
4612     }
4613   /* clean up 'normal' clients */
4614   prev = NULL;
4615   pos = clients;
4616   while ((pos != NULL) && (pos->client != client))
4617     {
4618       prev = pos;
4619       pos = pos->next;
4620     }
4621   if (pos == NULL)
4622     return;
4623   while (NULL != (mqe = pos->message_queue_head))
4624     {
4625       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4626                                    pos->message_queue_tail,
4627                                    mqe);
4628       pos->message_count--;
4629       GNUNET_free (mqe);
4630     }
4631   if (prev == NULL)
4632     clients = pos->next;
4633   else
4634     prev->next = pos->next;
4635   if (GNUNET_YES == pos->tcs_pending)
4636     {
4637       pos->client = NULL;
4638       return;
4639     }
4640   if (pos->th != NULL)
4641     {
4642       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4643       pos->th = NULL;
4644     }
4645   GNUNET_break (0 == pos->message_count);
4646   GNUNET_free (pos);
4647 }
4648
4649
4650 /**
4651  * Iterator to free entries in the validation_map.
4652  *
4653  * @param cls closure (unused)
4654  * @param key current key code
4655  * @param value value in the hash map (validation to abort)
4656  * @return GNUNET_YES (always)
4657  */
4658 static int 
4659 abort_validation (void *cls,
4660                   const GNUNET_HashCode * key,
4661                   void *value)
4662 {
4663   struct ValidationEntry *va = value;
4664
4665   GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
4666   GNUNET_free (va->transport_name);
4667   GNUNET_free (va);
4668   return GNUNET_YES;
4669 }
4670
4671
4672 /**
4673  * Function called when the service shuts down.  Unloads our plugins
4674  * and cancels pending validations.
4675  *
4676  * @param cls closure, unused
4677  * @param tc task context (unused)
4678  */
4679 static void
4680 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4681 {
4682   struct TransportPlugin *plug;
4683   struct OwnAddressList *al;
4684   struct CheckHelloValidatedContext *chvc;
4685
4686   while (neighbours != NULL)
4687     disconnect_neighbour (neighbours, GNUNET_NO);
4688 #if DEBUG_TRANSPORT
4689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4690               "Transport service is unloading plugins...\n");
4691 #endif
4692   while (NULL != (plug = plugins))
4693     {
4694       plugins = plug->next;
4695       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4696         {
4697           GNUNET_SCHEDULER_cancel (plug->env.sched, 
4698                                    plug->address_update_task);
4699           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4700         }
4701       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4702       GNUNET_free (plug->lib_name);
4703       GNUNET_free (plug->short_name);
4704       while (NULL != (al = plug->addresses))
4705         {
4706           plug->addresses = al->next;
4707           GNUNET_free (al);
4708         }
4709       GNUNET_free (plug);
4710     }
4711   if (my_private_key != NULL)
4712     GNUNET_CRYPTO_rsa_key_free (my_private_key);
4713   GNUNET_free_non_null (our_hello);
4714
4715   /* free 'chvc' data structure */
4716   while (NULL != (chvc = chvc_head))
4717     {
4718       chvc_head = chvc->next;
4719       GNUNET_PEERINFO_iterate_cancel (chvc->piter);
4720       GNUNET_free (chvc);
4721     }
4722   chvc_tail = NULL;
4723
4724   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4725                                          &abort_validation,
4726                                          NULL);
4727   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4728   validation_map = NULL;
4729   if (stats != NULL)
4730     {
4731       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4732       stats = NULL;
4733     }
4734
4735   /* Can we assume those are gone by now, or do we need to clean up
4736      explicitly!? */
4737   GNUNET_break (bl_head == NULL);
4738   GNUNET_break (bc_head == NULL);
4739 }
4740
4741
4742 /**
4743  * Initiate transport service.
4744  *
4745  * @param cls closure
4746  * @param s scheduler to use
4747  * @param serv the initialized server
4748  * @param c configuration to use
4749  */
4750 static void
4751 run (void *cls,
4752      struct GNUNET_SCHEDULER_Handle *s,
4753      struct GNUNET_SERVER_Handle *serv,
4754      const struct GNUNET_CONFIGURATION_Handle *c)
4755 {
4756   char *plugs;
4757   char *pos;
4758   int no_transports;
4759   unsigned long long tneigh;
4760   char *keyfile;
4761
4762   sched = s;
4763   cfg = c;
4764   stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4765   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4766   /* parse configuration */
4767   if ((GNUNET_OK !=
4768        GNUNET_CONFIGURATION_get_value_number (c,
4769                                               "TRANSPORT",
4770                                               "NEIGHBOUR_LIMIT",
4771                                               &tneigh)) ||
4772       (GNUNET_OK !=
4773        GNUNET_CONFIGURATION_get_value_filename (c,
4774                                                 "GNUNETD",
4775                                                 "HOSTKEY", &keyfile)))
4776     {
4777       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4778                   _
4779                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
4780       GNUNET_SCHEDULER_shutdown (s);
4781       if (stats != NULL)
4782         {
4783           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4784           stats = NULL;
4785         }
4786       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4787       validation_map = NULL;
4788       return;
4789     }
4790   max_connect_per_transport = (uint32_t) tneigh;
4791   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4792   GNUNET_free (keyfile);
4793   if (my_private_key == NULL)
4794     {
4795       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4796                   _
4797                   ("Transport service could not access hostkey.  Exiting.\n"));
4798       GNUNET_SCHEDULER_shutdown (s);
4799       if (stats != NULL)
4800         {
4801           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4802           stats = NULL;
4803         }
4804       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4805       validation_map = NULL;
4806       return;
4807     }
4808   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4809   GNUNET_CRYPTO_hash (&my_public_key,
4810                       sizeof (my_public_key), &my_identity.hashPubKey);
4811   /* setup notification */
4812   server = serv;
4813   GNUNET_SERVER_disconnect_notify (server,
4814                                    &client_disconnect_notification, NULL);
4815   /* load plugins... */
4816   no_transports = 1;
4817   if (GNUNET_OK ==
4818       GNUNET_CONFIGURATION_get_value_string (c,
4819                                              "TRANSPORT", "PLUGINS", &plugs))
4820     {
4821       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4822                   _("Starting transport plugins `%s'\n"), plugs);
4823       pos = strtok (plugs, " ");
4824       while (pos != NULL)
4825         {
4826           start_transport (server, pos);
4827           no_transports = 0;
4828           pos = strtok (NULL, " ");
4829         }
4830       GNUNET_free (plugs);
4831     }
4832   GNUNET_SCHEDULER_add_delayed (sched,
4833                                 GNUNET_TIME_UNIT_FOREVER_REL,
4834                                 &shutdown_task, NULL);
4835   if (no_transports)
4836     refresh_hello ();
4837
4838 #if DEBUG_TRANSPORT
4839   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4840 #endif
4841   /* If we have a blacklist file, read from it */
4842   read_blacklist_file(cfg);
4843   /* process client requests */
4844   GNUNET_SERVER_add_handlers (server, handlers);
4845 }
4846
4847
4848 /**
4849  * The main function for the transport service.
4850  *
4851  * @param argc number of arguments from the command line
4852  * @param argv command line arguments
4853  * @return 0 ok, 1 on error
4854  */
4855 int
4856 main (int argc, char *const *argv)
4857 {
4858   return (GNUNET_OK ==
4859           GNUNET_SERVICE_run (argc,
4860                               argv,
4861                               "transport",
4862                               GNUNET_SERVICE_OPTION_NONE,
4863                               &run, NULL)) ? 0 : 1;
4864 }
4865
4866 /* end of gnunet-service-transport.c */