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