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