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