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