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