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