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