ats related changes
[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 (GNUNET_YES != pos->connected)
2434     {
2435       /* nothing else to do, connection was never up... */
2436       GNUNET_free (pos);
2437       return; 
2438     }
2439   GNUNET_free (pos);
2440   if (ats != NULL)
2441     ats->stat.recreate_problem = GNUNET_YES;
2442   if (nl->received_pong == GNUNET_NO)
2443     {
2444       GNUNET_STATISTICS_update (stats,
2445                                 gettext_noop ("# disconnects due to NO pong"),
2446                                 1,
2447                                 GNUNET_NO);
2448       disconnect_neighbour (nl, GNUNET_YES);
2449       return; /* nothing to do, never connected... */
2450     }
2451   /* check if we have any validated addresses left */
2452   pos = rl->addresses;
2453   while (pos != NULL)
2454     {
2455       if (GNUNET_YES == pos->validated)
2456         {
2457           GNUNET_STATISTICS_update (stats,
2458                                     gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2459                                     1,
2460                                     GNUNET_NO);
2461           try_fast_reconnect (p, nl);
2462           return;
2463         }
2464       pos = pos->next;
2465     }
2466   /* no valid addresses left, signal disconnect! */
2467
2468 #if DEBUG_TRANSPORT
2469   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2470               "Disconnecting peer `%4s', %s\n", 
2471               GNUNET_i2s(peer),
2472               "plugin_env_session_end");
2473 #endif
2474   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2475    * it means there aren't any left for this PLUGIN/PEER combination! So
2476    * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2477    * when it isn't necessary. Using GNUNET_YES at least checks to see
2478    * if there are any addresses that work first, so as not to overdo it.
2479    * --NE
2480    */
2481   GNUNET_STATISTICS_update (stats,
2482                             gettext_noop ("# disconnects due to plugin_env_session_end"),
2483                             1,
2484                             GNUNET_NO);
2485   disconnect_neighbour (nl, GNUNET_YES);
2486 }
2487
2488
2489 /**
2490  * Function that must be called by each plugin to notify the
2491  * transport service about the addresses under which the transport
2492  * provided by the plugin can be reached.
2493  *
2494  * @param cls closure
2495  * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2496  * @param addr one of the addresses of the host, NULL for the last address
2497  *        the specific address format depends on the transport
2498  * @param addrlen length of the address
2499  */
2500 static void
2501 plugin_env_notify_address (void *cls,
2502                            int add_remove,
2503                            const void *addr,
2504                            size_t addrlen)
2505 {
2506   struct TransportPlugin *p = cls;
2507   struct OwnAddressList *al;
2508   struct OwnAddressList *prev;
2509
2510   GNUNET_assert (p->api != NULL);
2511 #if DEBUG_TRANSPORT
2512   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2513               (add_remove == GNUNET_YES)
2514               ? "Adding `%s':%s to the set of our addresses\n"
2515               : "Removing `%s':%s from the set of our addresses\n",
2516               a2s (p->short_name,
2517                    addr, addrlen),
2518               p->short_name);
2519 #endif
2520   GNUNET_assert (addr != NULL);
2521   if (GNUNET_NO == add_remove)
2522     {
2523       prev = NULL;
2524       al = p->addresses;
2525       while (al != NULL)
2526         {
2527           if ( (addrlen == al->addrlen) &&
2528                (0 == memcmp (addr, &al[1], addrlen)) )
2529             {
2530               if (prev == NULL)
2531                 p->addresses = al->next;
2532               else
2533                 prev->next = al->next;
2534               GNUNET_free (al);
2535               refresh_hello ();
2536               return;
2537             }
2538           prev = al;
2539           al = al->next;
2540         }
2541       GNUNET_break (0);
2542       return;
2543     }
2544   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2545   al->next = p->addresses;
2546   p->addresses = al;
2547   al->addrlen = addrlen;
2548   memcpy (&al[1], addr, addrlen);
2549   refresh_hello ();
2550 }
2551
2552
2553 /**
2554  * Notify all of our clients about a peer connecting.
2555  */
2556 static void
2557 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2558                         struct GNUNET_TIME_Relative latency,
2559                         uint32_t distance)
2560 {
2561   struct ConnectInfoMessage * cim;
2562   struct TransportClient *cpos;
2563   uint32_t ats_count;
2564   size_t size;
2565
2566   if (0 == memcmp (peer,
2567                    &my_identity,
2568                    sizeof (struct GNUNET_PeerIdentity)))
2569     {
2570       GNUNET_break (0);
2571       return;
2572     }
2573 #if DEBUG_TRANSPORT
2574   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2575               "Notifying clients about connection with `%s'\n",
2576               GNUNET_i2s (peer));
2577 #endif
2578   GNUNET_STATISTICS_update (stats,
2579                             gettext_noop ("# peers connected"),
2580                             1,
2581                             GNUNET_NO);
2582
2583   ats_count = 2;
2584   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2585   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2586     {
2587       GNUNET_break(0);
2588     }
2589   cim = GNUNET_malloc (size);
2590   cim->header.size = htons (size);
2591   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2592   cim->ats_count = htonl(2);
2593   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2594   (&(cim->ats))[0].value = htonl (distance);
2595   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2596   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2597   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2598   (&(cim->ats))[2].value = htonl (0);
2599   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2600
2601   /* notify ats about connecting peer */
2602   /* notify ats about connecting peer */
2603   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2604   {
2605     ats->stat.recreate_problem = GNUNET_YES;
2606     ats_calculate_bandwidth_distribution (ats, stats, neighbours);
2607   }
2608
2609
2610   cpos = clients;
2611   while (cpos != NULL)
2612     {
2613       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2614       cpos = cpos->next;
2615     }
2616
2617   GNUNET_free (cim);
2618 }
2619
2620
2621 /**
2622  * Notify all of our clients about a peer disconnecting.
2623  */
2624 static void
2625 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2626 {
2627   struct DisconnectInfoMessage dim;
2628   struct TransportClient *cpos;
2629
2630   if (0 == memcmp (peer,
2631                    &my_identity,
2632                    sizeof (struct GNUNET_PeerIdentity)))
2633     {
2634       GNUNET_break (0);
2635       return;
2636     }
2637 #if DEBUG_TRANSPORT
2638   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2639               "Notifying clients about lost connection to `%s'\n",
2640               GNUNET_i2s (peer));
2641 #endif
2642   GNUNET_STATISTICS_update (stats,
2643                             gettext_noop ("# peers connected"),
2644                             -1,
2645                             GNUNET_NO);
2646   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2647   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2648   dim.reserved = htonl (0);
2649   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2650
2651   /* notify ats about connecting peer */
2652   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2653   {
2654     ats->stat.recreate_problem = GNUNET_YES;
2655     ats_calculate_bandwidth_distribution (ats, stats, neighbours);
2656   }
2657
2658   cpos = clients;
2659   while (cpos != NULL)
2660     {
2661       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2662       cpos = cpos->next;
2663     }
2664 }
2665
2666
2667 /**
2668  * Find a ForeignAddressList entry for the given neighbour
2669  * that matches the given address and transport.
2670  *
2671  * @param neighbour which peer we care about
2672  * @param tname name of the transport plugin
2673  * @param session session to look for, NULL for 'any'; otherwise
2674  *        can be used for the service to "learn" this session ID
2675  *        if 'addr' matches
2676  * @param addr binary address
2677  * @param addrlen length of addr
2678  * @return NULL if no such entry exists
2679  */
2680 static struct ForeignAddressList *
2681 find_peer_address(struct NeighbourList *neighbour,
2682                   const char *tname,
2683                   struct Session *session,
2684                   const char *addr,
2685                   uint16_t addrlen)
2686 {
2687   struct ReadyList *head;
2688   struct ForeignAddressList *pos;
2689
2690   head = neighbour->plugins;
2691   while (head != NULL)
2692     {
2693       if (0 == strcmp (tname, head->plugin->short_name))
2694         break;
2695       head = head->next;
2696     }
2697   if (head == NULL)
2698     return NULL;
2699   pos = head->addresses;
2700   while ( (pos != NULL) &&
2701           ( (pos->addrlen != addrlen) ||
2702             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2703     {
2704       if ( (session != NULL) &&
2705            (pos->session == session) )
2706         return pos;
2707       pos = pos->next;
2708     }
2709   if ( (session != NULL) && (pos != NULL) )
2710     pos->session = session; /* learn it! */
2711   return pos;
2712 }
2713
2714
2715 /**
2716  * Get the peer address struct for the given neighbour and
2717  * address.  If it doesn't yet exist, create it.
2718  *
2719  * @param neighbour which peer we care about
2720  * @param tname name of the transport plugin
2721  * @param session session of the plugin, or NULL for none
2722  * @param addr binary address
2723  * @param addrlen length of addr
2724  * @return NULL if we do not have a transport plugin for 'tname'
2725  */
2726 static struct ForeignAddressList *
2727 add_peer_address (struct NeighbourList *neighbour,
2728                   const char *tname,
2729                   struct Session *session,
2730                   const char *addr,
2731                   uint16_t addrlen)
2732 {
2733   struct ReadyList *head;
2734   struct ForeignAddressList *ret;
2735   int c;
2736
2737   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2738   if (ret != NULL)
2739     return ret;
2740   head = neighbour->plugins;
2741
2742   while (head != NULL)
2743     {
2744       if (0 == strcmp (tname, head->plugin->short_name))
2745         break;
2746       head = head->next;
2747     }
2748   if (head == NULL)
2749     return NULL;
2750   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2751   ret->session = session;
2752   if ((addrlen > 0) && (addr != NULL))
2753     {
2754       ret->addr = (const char*) &ret[1];
2755       memcpy (&ret[1], addr, addrlen);
2756     }
2757   else
2758     {
2759       ret->addr = NULL;
2760     }
2761
2762   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2763   for (c=0; c<available_ressources; c++)
2764     {
2765       struct ATS_ressource_entry *r = ret->ressources;
2766       r[c].index = c;
2767       r[c].atis_index = ressources[c].atis_index;
2768       if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2769         {
2770           r[c].c = ressources[c].c_unix;
2771         }
2772       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2773         {
2774           r[c].c = ressources[c].c_udp;
2775         }
2776       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2777         {
2778           r[c].c = ressources[c].c_tcp;
2779         }
2780       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2781         {
2782           r[c].c = ressources[c].c_http;
2783         }
2784       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2785         {
2786           r[c].c = ressources[c].c_https;
2787         }
2788       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2789         {
2790           r[c].c = ressources[c].c_wlan;
2791         }
2792       else
2793         {
2794           r[c].c = ressources[c].c_default;
2795           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2796                       "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2797                       GNUNET_i2s(&neighbour->peer), 
2798                       neighbour->plugins->plugin->short_name);
2799         }
2800     }
2801
2802   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2803   ret->addrlen = addrlen;
2804   ret->expires = GNUNET_TIME_relative_to_absolute
2805     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2806   ret->latency = GNUNET_TIME_relative_get_forever();
2807   ret->distance = -1;
2808   ret->timeout = GNUNET_TIME_relative_to_absolute
2809     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2810   ret->ready_list = head;
2811   ret->next = head->addresses;
2812   head->addresses = ret;
2813   return ret;
2814 }
2815
2816
2817 /**
2818  * Closure for 'add_validated_address'.
2819  */
2820 struct AddValidatedAddressContext
2821 {
2822   /**
2823    * Entry that has been validated.
2824    */
2825   const struct ValidationEntry *ve;
2826
2827   /**
2828    * Flag set after we have added the address so
2829    * that we terminate the iteration next time.
2830    */
2831   int done;
2832 };
2833
2834
2835 /**
2836  * Callback function used to fill a buffer of max bytes with a list of
2837  * addresses in the format used by HELLOs.  Should use
2838  * "GNUNET_HELLO_add_address" as a helper function.
2839  *
2840  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2841  * @param max maximum number of bytes that can be written to buf
2842  * @param buf where to write the address information
2843  * @return number of bytes written, 0 to signal the
2844  *         end of the iteration.
2845  */
2846 static size_t
2847 add_validated_address (void *cls,
2848                        size_t max, void *buf)
2849 {
2850   struct AddValidatedAddressContext *avac = cls;
2851   const struct ValidationEntry *ve = avac->ve;
2852
2853   if (GNUNET_YES == avac->done)
2854     return 0;
2855   avac->done = GNUNET_YES;
2856   return GNUNET_HELLO_add_address (ve->transport_name,
2857                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2858                                    ve->addr,
2859                                    ve->addrlen,
2860                                    buf,
2861                                    max);
2862 }
2863
2864
2865
2866 /**
2867  * Closure for 'check_address_exists'.
2868  */
2869 struct CheckAddressExistsClosure
2870 {
2871   /**
2872    * Address to check for.
2873    */
2874   const void *addr;
2875
2876   /**
2877    * Name of the transport.
2878    */
2879   const char *tname;
2880
2881   /**
2882    * Session, or NULL.
2883    */
2884   struct Session *session;
2885
2886   /**
2887    * Set to GNUNET_YES if the address exists.
2888    */
2889   int exists;
2890
2891   /**
2892    * Length of addr.
2893    */
2894   uint16_t addrlen;
2895
2896 };
2897
2898
2899 /**
2900  * Iterator over hash map entries.  Checks if the given
2901  * validation entry is for the same address as what is given
2902  * in the closure.
2903  *
2904  * @param cls the 'struct CheckAddressExistsClosure*'
2905  * @param key current key code (ignored)
2906  * @param value value in the hash map ('struct ValidationEntry')
2907  * @return GNUNET_YES if we should continue to
2908  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2909  */
2910 static int
2911 check_address_exists (void *cls,
2912                       const GNUNET_HashCode * key,
2913                       void *value)
2914 {
2915   struct CheckAddressExistsClosure *caec = cls;
2916   struct ValidationEntry *ve = value;
2917
2918   if ( (0 == strcmp (caec->tname,
2919                      ve->transport_name)) &&
2920        (caec->addrlen == ve->addrlen) &&
2921        (0 == memcmp (caec->addr,
2922                      ve->addr,
2923                      caec->addrlen)) )
2924     {
2925       caec->exists = GNUNET_YES;
2926       return GNUNET_NO;
2927     }
2928   if ( (ve->session != NULL) &&
2929        (caec->session == ve->session) )
2930     {
2931       caec->exists = GNUNET_YES;
2932       return GNUNET_NO;
2933     }
2934   return GNUNET_YES;
2935 }
2936
2937
2938 static void
2939 neighbour_timeout_task (void *cls,
2940                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2941 {
2942   struct NeighbourList *n = cls;
2943
2944 #if DEBUG_TRANSPORT
2945   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2946               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2947 #endif
2948   GNUNET_STATISTICS_update (stats,
2949                             gettext_noop ("# disconnects due to timeout"),
2950                             1,
2951                             GNUNET_NO);
2952   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2953   disconnect_neighbour (n, GNUNET_NO);
2954 }
2955
2956
2957 /**
2958  * Schedule the job that will cause us to send a PING to the
2959  * foreign address to evaluate its validity and latency.
2960  *
2961  * @param fal address to PING
2962  */
2963 static void
2964 schedule_next_ping (struct ForeignAddressList *fal);
2965
2966
2967 /**
2968  * Add the given address to the list of foreign addresses
2969  * available for the given peer (check for duplicates).
2970  *
2971  * @param cls the respective 'struct NeighbourList' to update
2972  * @param tname name of the transport
2973  * @param expiration expiration time
2974  * @param addr the address
2975  * @param addrlen length of the address
2976  * @return GNUNET_OK (always)
2977  */
2978 static int
2979 add_to_foreign_address_list (void *cls,
2980                              const char *tname,
2981                              struct GNUNET_TIME_Absolute expiration,
2982                              const void *addr,
2983                              uint16_t addrlen)
2984 {
2985   struct NeighbourList *n = cls;
2986   struct ForeignAddressList *fal;
2987   int try;
2988
2989   GNUNET_STATISTICS_update (stats,
2990                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
2991                             1,
2992                             GNUNET_NO);
2993   try = GNUNET_NO;
2994   fal = find_peer_address (n, tname, NULL, addr, addrlen);
2995   if (fal == NULL)
2996     {
2997 #if DEBUG_TRANSPORT_HELLO
2998       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2999                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3000                   a2s (tname, addr, addrlen),
3001                   tname,
3002                   GNUNET_i2s (&n->id),
3003                   expiration.abs_value);
3004 #endif
3005       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3006       if (fal == NULL)
3007         {
3008           GNUNET_STATISTICS_update (stats,
3009                                     gettext_noop ("# previously validated addresses lacking transport"),
3010                                     1,
3011                                     GNUNET_NO);
3012         }
3013       else
3014         {
3015           fal->expires = GNUNET_TIME_absolute_max (expiration,
3016                                                    fal->expires);
3017           schedule_next_ping (fal);
3018         }
3019       try = GNUNET_YES;
3020     }
3021   else
3022     {
3023       fal->expires = GNUNET_TIME_absolute_max (expiration,
3024                                                fal->expires);
3025     }
3026   if (fal == NULL)
3027     {
3028 #if DEBUG_TRANSPORT
3029       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3030                   "Failed to add new address for `%4s'\n",
3031                   GNUNET_i2s (&n->id));
3032 #endif
3033       return GNUNET_OK;
3034     }
3035   if (fal->validated == GNUNET_NO)
3036     {
3037       fal->validated = GNUNET_YES;
3038       GNUNET_STATISTICS_update (stats,
3039                                 gettext_noop ("# peer addresses considered valid"),
3040                                 1,
3041                                 GNUNET_NO);
3042     }
3043   if (try == GNUNET_YES)
3044     {
3045 #if DEBUG_TRANSPORT
3046       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3047                   "Have new addresses, will try to trigger transmissions.\n");
3048 #endif
3049       try_transmission_to_peer (n);
3050     }
3051   return GNUNET_OK;
3052 }
3053
3054
3055 /**
3056  * Add addresses in validated HELLO "h" to the set of addresses
3057  * we have for this peer.
3058  *
3059  * @param cls closure ('struct NeighbourList*')
3060  * @param peer id of the peer, NULL for last call
3061  * @param h hello message for the peer (can be NULL)
3062  * @param err_msg NULL if successful, otherwise contains error message
3063  */
3064 static void
3065 add_hello_for_peer (void *cls,
3066                     const struct GNUNET_PeerIdentity *peer,
3067                     const struct GNUNET_HELLO_Message *h,
3068                     const char *err_msg)
3069 {
3070   struct NeighbourList *n = cls;
3071
3072   if (err_msg != NULL)
3073     {
3074 #if DEBUG_TRANSPORT
3075       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3076                   _("Error in communication with PEERINFO service: %s\n"),
3077                   err_msg);
3078 #endif
3079       /* return; */
3080     }
3081   if (peer == NULL)
3082     {
3083       GNUNET_STATISTICS_update (stats,
3084                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3085                                 -1,
3086                                 GNUNET_NO);
3087       n->piter = NULL;
3088       return;
3089     }
3090   if (h == NULL)
3091     return; /* no HELLO available */
3092 #if DEBUG_TRANSPORT
3093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3095               "HELLO",
3096               GNUNET_i2s (peer));
3097 #endif
3098   if (GNUNET_YES != n->public_key_valid)
3099     {
3100       GNUNET_HELLO_get_key (h, &n->publicKey);
3101       n->public_key_valid = GNUNET_YES;
3102     }
3103   GNUNET_HELLO_iterate_addresses (h,
3104                                   GNUNET_NO,
3105                                   &add_to_foreign_address_list,
3106                                   n);
3107 }
3108
3109
3110 /**
3111  * Create a fresh entry in our neighbour list for the given peer.
3112  * Will try to transmit our current HELLO to the new neighbour.
3113  * Do not call this function directly, use 'setup_peer_check_blacklist.
3114  *
3115  * @param peer the peer for which we create the entry
3116  * @param do_hello should we schedule transmitting a HELLO
3117  * @return the new neighbour list entry
3118  */
3119 static struct NeighbourList *
3120 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3121                      int do_hello)
3122 {
3123   struct NeighbourList *n;
3124   struct TransportPlugin *tp;
3125   struct ReadyList *rl;
3126
3127   GNUNET_assert (0 != memcmp (peer,
3128                               &my_identity,
3129                               sizeof (struct GNUNET_PeerIdentity)));
3130 #if DEBUG_TRANSPORT
3131   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3132               "Setting up state for neighbour `%4s'\n",
3133               GNUNET_i2s (peer));
3134 #endif
3135   GNUNET_STATISTICS_update (stats,
3136                             gettext_noop ("# active neighbours"),
3137                             1,
3138                             GNUNET_NO);
3139   n = GNUNET_malloc (sizeof (struct NeighbourList));
3140   n->next = neighbours;
3141   neighbours = n;
3142   n->id = *peer;
3143   n->peer_timeout =
3144     GNUNET_TIME_relative_to_absolute
3145     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3146   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3147                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3148                                  MAX_BANDWIDTH_CARRY_S);
3149   tp = plugins;
3150   while (tp != NULL)
3151     {
3152       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3153         {
3154           rl = GNUNET_malloc (sizeof (struct ReadyList));
3155           rl->neighbour = n;
3156           rl->next = n->plugins;
3157           n->plugins = rl;
3158           rl->plugin = tp;
3159           rl->addresses = NULL;
3160         }
3161       tp = tp->next;
3162     }
3163   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3164   n->distance = -1;
3165   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3166                                                   &neighbour_timeout_task, n);
3167   if (do_hello)
3168     {
3169       GNUNET_STATISTICS_update (stats,
3170                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3171                                 1,
3172                                 GNUNET_NO);
3173       GNUNET_STATISTICS_update (stats,
3174                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3175                                 1,
3176                                 GNUNET_NO);
3177       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3178                                           GNUNET_TIME_UNIT_FOREVER_REL,
3179                                           &add_hello_for_peer, n);
3180
3181       GNUNET_STATISTICS_update (stats,
3182                                 gettext_noop ("# HELLO's sent to new neighbors"),
3183                                 1,
3184                                 GNUNET_NO);
3185       if (NULL != our_hello)
3186         transmit_to_peer (NULL, NULL, 0,
3187                           HELLO_ADDRESS_EXPIRATION,
3188                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3189                           GNUNET_NO, n);
3190     }
3191   return n;
3192 }
3193
3194
3195 /**
3196  * Function called after we have checked if communicating
3197  * with a given peer is acceptable.
3198  *
3199  * @param cls closure
3200  * @param n NULL if communication is not acceptable
3201  */
3202 typedef void (*SetupContinuation)(void *cls,
3203                                   struct NeighbourList *n);
3204
3205
3206 /**
3207  * Information kept for each client registered to perform
3208  * blacklisting.
3209  */
3210 struct Blacklisters
3211 {
3212   /**
3213    * This is a linked list.
3214    */
3215   struct Blacklisters *next;
3216
3217   /**
3218    * This is a linked list.
3219    */
3220   struct Blacklisters *prev;
3221
3222   /**
3223    * Client responsible for this entry.
3224    */
3225   struct GNUNET_SERVER_Client *client;
3226
3227   /**
3228    * Blacklist check that we're currently performing.
3229    */
3230   struct BlacklistCheck *bc;
3231
3232 };
3233
3234
3235 /**
3236  * Head of DLL of blacklisting clients.
3237  */
3238 static struct Blacklisters *bl_head;
3239
3240 /**
3241  * Tail of DLL of blacklisting clients.
3242  */
3243 static struct Blacklisters *bl_tail;
3244
3245
3246 /**
3247  * Context we use when performing a blacklist check.
3248  */
3249 struct BlacklistCheck
3250 {
3251
3252   /**
3253    * This is a linked list.
3254    */
3255   struct BlacklistCheck *next;
3256
3257   /**
3258    * This is a linked list.
3259    */
3260   struct BlacklistCheck *prev;
3261
3262   /**
3263    * Peer being checked.
3264    */
3265   struct GNUNET_PeerIdentity peer;
3266
3267   /**
3268    * Option for setup neighbour afterwards.
3269    */
3270   int do_hello;
3271
3272   /**
3273    * Continuation to call with the result.
3274    */
3275   SetupContinuation cont;
3276
3277   /**
3278    * Closure for cont.
3279    */
3280   void *cont_cls;
3281
3282   /**
3283    * Current transmission request handle for this client, or NULL if no
3284    * request is pending.
3285    */
3286   struct GNUNET_CONNECTION_TransmitHandle *th;
3287
3288   /**
3289    * Our current position in the blacklisters list.
3290    */
3291   struct Blacklisters *bl_pos;
3292
3293   /**
3294    * Current task performing the check.
3295    */
3296   GNUNET_SCHEDULER_TaskIdentifier task;
3297
3298 };
3299
3300 /**
3301  * Head of DLL of active blacklisting queries.
3302  */
3303 static struct BlacklistCheck *bc_head;
3304
3305 /**
3306  * Tail of DLL of active blacklisting queries.
3307  */
3308 static struct BlacklistCheck *bc_tail;
3309
3310
3311 /**
3312  * Perform next action in the blacklist check.
3313  *
3314  * @param cls the 'struct BlacklistCheck*'
3315  * @param tc unused
3316  */
3317 static void
3318 do_blacklist_check (void *cls,
3319                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3320
3321 /**
3322  * Transmit blacklist query to the client.
3323  *
3324  * @param cls the 'struct BlacklistCheck'
3325  * @param size number of bytes allowed
3326  * @param buf where to copy the message
3327  * @return number of bytes copied to buf
3328  */
3329 static size_t
3330 transmit_blacklist_message (void *cls,
3331                             size_t size,
3332                             void *buf)
3333 {
3334   struct BlacklistCheck *bc = cls;
3335   struct Blacklisters *bl;
3336   struct BlacklistMessage bm;
3337
3338   bc->th = NULL;
3339   if (size == 0)
3340     {
3341       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3342       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3343                                            bc);
3344       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3345                   "Failed to send blacklist test for peer `%s' to client\n",
3346                   GNUNET_i2s (&bc->peer));
3347       return 0;
3348     }
3349 #if DEBUG_TRANSPORT
3350   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3351               "Sending blacklist test for peer `%s' to client\n",
3352               GNUNET_i2s (&bc->peer));
3353 #endif
3354   bl = bc->bl_pos;
3355   bm.header.size = htons (sizeof (struct BlacklistMessage));
3356   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3357   bm.is_allowed = htonl (0);
3358   bm.peer = bc->peer;
3359   memcpy (buf, &bm, sizeof (bm));
3360   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3361   return sizeof (bm);
3362 }
3363
3364
3365 /**
3366  * Perform next action in the blacklist check.
3367  *
3368  * @param cls the 'struct BlacklistCheck*'
3369  * @param tc unused
3370  */
3371 static void
3372 do_blacklist_check (void *cls,
3373                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3374 {
3375   struct BlacklistCheck *bc = cls;
3376   struct Blacklisters *bl;
3377
3378   bc->task = GNUNET_SCHEDULER_NO_TASK;
3379   bl = bc->bl_pos;
3380   if (bl == NULL)
3381     {
3382 #if DEBUG_TRANSPORT
3383       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3384                   "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3385                   GNUNET_i2s (&bc->peer));
3386 #endif
3387       bc->cont (bc->cont_cls,
3388                 setup_new_neighbour (&bc->peer, bc->do_hello));
3389       GNUNET_free (bc);
3390       return;
3391     }
3392   if (bl->bc == NULL)
3393     {
3394       bl->bc = bc;
3395       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3396                                                     sizeof (struct BlacklistMessage),
3397                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3398                                                     &transmit_blacklist_message,
3399                                                     bc);
3400     }
3401 }
3402
3403
3404 /**
3405  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3406  * does not yet exist, check the blacklist.  If the blacklist says creating
3407  * one is acceptable, create one and call the continuation; otherwise
3408  * call the continuation with NULL.
3409  *
3410  * @param peer peer to setup or look up a struct NeighbourList for
3411  * @param do_hello should we also schedule sending our HELLO to the peer
3412  *        if this is a new record
3413  * @param cont function to call with the 'struct NeigbhbourList*'
3414  * @param cont_cls closure for cont
3415  */
3416 static void
3417 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3418                             int do_hello,
3419                             SetupContinuation cont,
3420                             void *cont_cls)
3421 {
3422   struct NeighbourList *n;
3423   struct BlacklistCheck *bc;
3424
3425   n = find_neighbour(peer);
3426   if (n != NULL)
3427     {
3428 #if DEBUG_TRANSPORT
3429       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
3430                  "Neighbour record exists for peer `%s'\n", 
3431                  GNUNET_i2s(peer));
3432 #endif
3433       if (cont != NULL)
3434         cont (cont_cls, n);
3435       return;
3436     }
3437   if (bl_head == NULL)
3438     {
3439       if (cont != NULL)
3440         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3441       else
3442         setup_new_neighbour(peer, do_hello);
3443       return;
3444     }
3445   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3446   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3447   bc->peer = *peer;
3448   bc->do_hello = do_hello;
3449   bc->cont = cont;
3450   bc->cont_cls = cont_cls;
3451   bc->bl_pos = bl_head;
3452   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3453                                        bc);
3454 }
3455
3456
3457 /**
3458  * Function called with the result of querying a new blacklister about
3459  * it being allowed (or not) to continue to talk to an existing neighbour.
3460  *
3461  * @param cls the original 'struct NeighbourList'
3462  * @param n NULL if we need to disconnect
3463  */
3464 static void
3465 confirm_or_drop_neighbour (void *cls,
3466                            struct NeighbourList *n)
3467 {
3468   struct NeighbourList * orig = cls;
3469
3470   if (n == NULL)
3471     {
3472 #if DEBUG_TRANSPORT
3473       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3474               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3475               "confirm_or_drop_neighboUr");
3476 #endif
3477       GNUNET_STATISTICS_update (stats,
3478                                 gettext_noop ("# disconnects due to blacklist"),
3479                                 1,
3480                                 GNUNET_NO);
3481       disconnect_neighbour (orig, GNUNET_NO);
3482     }
3483 }
3484
3485
3486 /**
3487  * Handle a request to start a blacklist.
3488  *
3489  * @param cls closure (always NULL)
3490  * @param client identification of the client
3491  * @param message the actual message
3492  */
3493 static void
3494 handle_blacklist_init (void *cls,
3495                        struct GNUNET_SERVER_Client *client,
3496                        const struct GNUNET_MessageHeader *message)
3497 {
3498   struct Blacklisters *bl;
3499   struct BlacklistCheck *bc;
3500   struct NeighbourList *n;
3501
3502   bl = bl_head;
3503   while (bl != NULL)
3504     {
3505       if (bl->client == client)
3506         {
3507           GNUNET_break (0);
3508           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3509           return;
3510         }
3511       bl = bl->next;
3512     }
3513   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3514   bl->client = client;
3515   GNUNET_SERVER_client_keep (client);
3516   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3517   /* confirm that all existing connections are OK! */
3518   n = neighbours;
3519   while (NULL != n)
3520     {
3521       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3522       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3523       bc->peer = n->id;
3524       bc->do_hello = GNUNET_NO;
3525       bc->cont = &confirm_or_drop_neighbour;
3526       bc->cont_cls = n;
3527       bc->bl_pos = bl;
3528       if (n == neighbours) /* all would wait for the same client, no need to
3529                               create more than just the first task right now */
3530         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3531                                              bc);
3532       n = n->next;
3533     }
3534 }
3535
3536
3537 /**
3538  * Handle a request to blacklist a peer.
3539  *
3540  * @param cls closure (always NULL)
3541  * @param client identification of the client
3542  * @param message the actual message
3543  */
3544 static void
3545 handle_blacklist_reply (void *cls,
3546                         struct GNUNET_SERVER_Client *client,
3547                         const struct GNUNET_MessageHeader *message)
3548 {
3549   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3550   struct Blacklisters *bl;
3551   struct BlacklistCheck *bc;
3552
3553   bl = bl_head;
3554   while ( (bl != NULL) &&
3555           (bl->client != client) )
3556     bl = bl->next;
3557   if (bl == NULL)
3558     {
3559 #if DEBUG_TRANSPORT
3560       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3561                   "Blacklist client disconnected\n");
3562 #endif
3563       /* FIXME: other error handling here!? */
3564       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3565       return;
3566     }
3567   bc = bl->bc;
3568   bl->bc = NULL;
3569   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3570     {
3571 #if DEBUG_TRANSPORT
3572       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3573                   "Blacklist check failed, peer not allowed\n");
3574 #endif
3575       bc->cont (bc->cont_cls, NULL);
3576       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3577       GNUNET_free (bc);
3578     }
3579   else
3580     {
3581 #if DEBUG_TRANSPORT
3582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3583                   "Blacklist check succeeded, continuing with checks\n");
3584 #endif
3585       bc->bl_pos = bc->bl_pos->next;
3586       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3587                                            bc);
3588     }
3589   /* check if any other bc's are waiting for this blacklister */
3590   bc = bc_head;
3591   while (bc != NULL)
3592     {
3593       if ( (bc->bl_pos == bl) &&
3594            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3595         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3596                                              bc);
3597       bc = bc->next;
3598     }
3599 }
3600
3601
3602 /**
3603  * Send periodic PING messages to a given foreign address.
3604  *
3605  * @param cls our 'struct PeriodicValidationContext*'
3606  * @param tc task context
3607  */
3608 static void
3609 send_periodic_ping (void *cls,
3610                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3611 {
3612   struct ForeignAddressList *peer_address = cls;
3613   struct TransportPlugin *tp;
3614   struct ValidationEntry *va;
3615   struct NeighbourList *neighbour;
3616   struct TransportPingMessage ping;
3617   struct CheckAddressExistsClosure caec;
3618   char * message_buf;
3619   uint16_t hello_size;
3620   size_t slen;
3621   size_t tsize;
3622
3623   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3624   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3625     return;
3626   tp = peer_address->ready_list->plugin;
3627   neighbour = peer_address->ready_list->neighbour;
3628   if (GNUNET_YES != neighbour->public_key_valid)
3629     {
3630       /* no public key yet, try again later */
3631       schedule_next_ping (peer_address);
3632       return;
3633     }
3634   caec.addr = peer_address->addr;
3635   caec.addrlen = peer_address->addrlen;
3636   caec.tname = tp->short_name;
3637   caec.session = peer_address->session;
3638   caec.exists = GNUNET_NO;
3639   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3640                                          &check_address_exists,
3641                                          &caec);
3642   if (caec.exists == GNUNET_YES)
3643     {
3644       /* During validation attempts we will likely trigger the other
3645          peer trying to validate our address which in turn will cause
3646          it to send us its HELLO, so we expect to hit this case rather
3647          frequently.  Only print something if we are very verbose. */
3648 #if DEBUG_TRANSPORT > 1
3649       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3650                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3651                   (peer_address->addr != NULL)
3652                   ? a2s (tp->short_name,
3653                          peer_address->addr,
3654                          peer_address->addrlen)
3655                   : "<inbound>",
3656                   tp->short_name,
3657                   GNUNET_i2s (&neighbour->id));
3658 #endif
3659       schedule_next_ping (peer_address);
3660       return;
3661     }
3662   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3663   va->transport_name = GNUNET_strdup (tp->short_name);
3664   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3665                                             UINT_MAX);
3666   va->send_time = GNUNET_TIME_absolute_get();
3667   va->session = peer_address->session;
3668   if (peer_address->addr != NULL)
3669     {
3670       va->addr = (const void*) &va[1];
3671       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3672       va->addrlen = peer_address->addrlen;
3673     }
3674   memcpy(&va->publicKey,
3675          &neighbour->publicKey,
3676          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3677
3678   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3679                                                    &timeout_hello_validation,
3680                                                    va);
3681   GNUNET_CONTAINER_multihashmap_put (validation_map,
3682                                      &neighbour->id.hashPubKey,
3683                                      va,
3684                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3685
3686   if (peer_address->validated != GNUNET_YES)
3687     hello_size = GNUNET_HELLO_size(our_hello);
3688   else
3689     hello_size = 0;
3690
3691   tsize = sizeof(struct TransportPingMessage) + hello_size;
3692
3693   if (peer_address->addr != NULL)
3694     {
3695       slen = strlen (tp->short_name) + 1;
3696       tsize += slen + peer_address->addrlen;
3697     }
3698   else
3699     {
3700       slen = 0; /* make gcc happy */
3701     }
3702   message_buf = GNUNET_malloc(tsize);
3703   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3704   ping.challenge = htonl(va->challenge);
3705   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3706   if (peer_address->validated != GNUNET_YES)
3707     {
3708       memcpy(message_buf, our_hello, hello_size);
3709     }
3710
3711   if (peer_address->addr != NULL)
3712     {
3713       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3714                                peer_address->addrlen +
3715                                slen);
3716       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3717              tp->short_name,
3718              slen);
3719       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3720              peer_address->addr,
3721              peer_address->addrlen);
3722     }
3723   else
3724     {
3725       ping.header.size = htons(sizeof(struct TransportPingMessage));
3726     }
3727
3728   memcpy(&message_buf[hello_size],
3729          &ping,
3730          sizeof(struct TransportPingMessage));
3731
3732 #if DEBUG_TRANSPORT_REVALIDATION
3733   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3734               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3735               (peer_address->addr != NULL)
3736               ? a2s (peer_address->plugin->short_name,
3737                      peer_address->addr,
3738                      peer_address->addrlen)
3739               : "<inbound>",
3740               tp->short_name,
3741               GNUNET_i2s (&neighbour->id),
3742               "HELLO", hello_size,
3743               "PING");
3744 #endif
3745   if (peer_address->validated != GNUNET_YES)
3746     GNUNET_STATISTICS_update (stats,
3747                               gettext_noop ("# PING with HELLO messages sent"),
3748                               1,
3749                               GNUNET_NO);
3750   else
3751     GNUNET_STATISTICS_update (stats,
3752                               gettext_noop ("# PING without HELLO messages sent"),
3753                               1,
3754                               GNUNET_NO);
3755   GNUNET_STATISTICS_update (stats,
3756                             gettext_noop ("# PING messages sent for re-validation"),
3757                             1,
3758                             GNUNET_NO);
3759   transmit_to_peer (NULL, peer_address,
3760                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3761                     HELLO_VERIFICATION_TIMEOUT,
3762                     message_buf, tsize,
3763                     GNUNET_YES, neighbour);
3764   GNUNET_free(message_buf);
3765   schedule_next_ping (peer_address);
3766 }
3767
3768
3769 /**
3770  * Schedule the job that will cause us to send a PING to the
3771  * foreign address to evaluate its validity and latency.
3772  *
3773  * @param fal address to PING
3774  */
3775 static void
3776 schedule_next_ping (struct ForeignAddressList *fal)
3777 {
3778   struct GNUNET_TIME_Relative delay;
3779
3780   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3781     return;
3782   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3783   delay.rel_value /= 2; /* do before expiration */
3784   delay = GNUNET_TIME_relative_min (delay,
3785                                     LATENCY_EVALUATION_MAX_DELAY);
3786   if (GNUNET_YES != fal->estimated)
3787     {
3788       delay = GNUNET_TIME_UNIT_ZERO;
3789       fal->estimated = GNUNET_YES;
3790     }
3791   if (GNUNET_YES == fal->connected)
3792     {
3793       delay = GNUNET_TIME_relative_min (delay,
3794                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3795     }
3796   /* FIXME: also adjust delay based on how close the last
3797      observed latency is to the latency of the best alternative */
3798   /* bound how fast we can go */
3799   delay = GNUNET_TIME_relative_max (delay,
3800                                     GNUNET_TIME_UNIT_SECONDS);
3801   /* randomize a bit (to avoid doing all at the same time) */
3802   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3803   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3804                                                       &send_periodic_ping,
3805                                                       fal);
3806 }
3807
3808
3809
3810
3811 /**
3812  * Function that will be called if we receive some payload
3813  * from another peer.
3814  *
3815  * @param message the payload
3816  * @param n peer who claimed to be the sender
3817  */
3818 static void
3819 handle_payload_message (const struct GNUNET_MessageHeader *message,
3820                         struct NeighbourList *n)
3821 {
3822   struct InboundMessage *im;
3823   struct TransportClient *cpos;
3824   uint16_t msize;
3825
3826   msize = ntohs (message->size);
3827   if (n->received_pong == GNUNET_NO)
3828     {
3829 #if DEBUG_TRANSPORT
3830       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3831                   "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3832                   ntohs (message->type),
3833                   ntohs (message->size),
3834                   GNUNET_i2s (&n->id));
3835 #endif
3836       GNUNET_free_non_null (n->pre_connect_message_buffer);
3837       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3838       memcpy (n->pre_connect_message_buffer, message, msize);
3839       return;
3840     }
3841
3842 #if DEBUG_TRANSPORT
3843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3844               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3845               ntohs (message->type),
3846               ntohs (message->size),
3847               GNUNET_i2s (&n->id));
3848 #endif
3849   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3850                                                       (ssize_t) msize))
3851     {
3852       n->quota_violation_count++;
3853 #if DEBUG_TRANSPORT
3854       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3855                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3856                   n->in_tracker.available_bytes_per_s__,
3857                   n->quota_violation_count);
3858 #endif
3859       /* Discount 32k per violation */
3860       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3861                                         - 32 * 1024);
3862     }
3863   else
3864     {
3865       if (n->quota_violation_count > 0)
3866         {
3867           /* try to add 32k back */
3868           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3869                                             32 * 1024);
3870           n->quota_violation_count--;
3871         }
3872     }
3873   GNUNET_STATISTICS_update (stats,
3874                             gettext_noop ("# payload received from other peers"),
3875                             msize,
3876                             GNUNET_NO);
3877   /* transmit message to all clients */
3878   uint32_t ats_count = 2;
3879   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3880   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3881           GNUNET_break(0);
3882
3883   im = GNUNET_malloc (size);
3884   im->header.size = htons (size);
3885   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3886   im->peer = n->id;
3887   im->ats_count = htonl(ats_count);
3888   /* Setting ATS data */
3889   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3890   (&(im->ats))[0].value = htonl (n->distance);
3891   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3892   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3893   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3894   (&(im->ats))[ats_count].value = htonl (0);
3895
3896   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3897   cpos = clients;
3898   while (cpos != NULL)
3899     {
3900       transmit_to_client (cpos, &im->header, GNUNET_YES);
3901       cpos = cpos->next;
3902     }
3903   GNUNET_free (im);
3904 }
3905
3906
3907 /**
3908  * Iterator over hash map entries.  Checks if the given validation
3909  * entry is for the same challenge as what is given in the PONG.
3910  *
3911  * @param cls the 'struct TransportPongMessage*'
3912  * @param key peer identity
3913  * @param value value in the hash map ('struct ValidationEntry')
3914  * @return GNUNET_YES if we should continue to
3915  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3916  */
3917 static int
3918 check_pending_validation (void *cls,
3919                           const GNUNET_HashCode * key,
3920                           void *value)
3921 {
3922   const struct TransportPongMessage *pong = cls;
3923   struct ValidationEntry *ve = value;
3924   struct AddValidatedAddressContext avac;
3925   unsigned int challenge = ntohl(pong->challenge);
3926   struct GNUNET_HELLO_Message *hello;
3927   struct GNUNET_PeerIdentity target;
3928   struct NeighbourList *n;
3929   struct ForeignAddressList *fal;
3930   struct OwnAddressList *oal;
3931   struct TransportPlugin *tp;
3932   struct GNUNET_MessageHeader *prem;
3933   uint16_t ps;
3934   const char *addr;
3935   size_t slen;
3936   size_t alen;
3937
3938   ps = ntohs (pong->header.size);
3939   if (ps < sizeof (struct TransportPongMessage))
3940     {
3941       GNUNET_break_op (0);
3942       return GNUNET_NO;
3943     }
3944   addr = (const char*) &pong[1];
3945   slen = strlen (ve->transport_name) + 1;
3946   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3947        (ve->challenge != challenge) ||
3948        (addr[slen-1] != '\0') ||
3949        (0 != strcmp (addr, ve->transport_name)) ||
3950        (ntohl (pong->purpose.size)
3951         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3952         sizeof (uint32_t) +
3953         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3954         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3955     {
3956       return GNUNET_YES;
3957     }
3958
3959   alen = ps - sizeof (struct TransportPongMessage) - slen;
3960   switch (ntohl (pong->purpose.purpose))
3961     {
3962     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3963       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3964            (0 != memcmp (&addr[slen],
3965                          ve->addr,
3966                          ve->addrlen)) )
3967         {
3968           return GNUNET_YES; /* different entry, keep trying! */
3969         }
3970       if (0 != memcmp (&pong->pid,
3971                        key,
3972                        sizeof (struct GNUNET_PeerIdentity)))
3973         {
3974           GNUNET_break_op (0);
3975           return GNUNET_NO;
3976         }
3977       if (GNUNET_OK !=
3978           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3979                                     &pong->purpose,
3980                                     &pong->signature,
3981                                     &ve->publicKey))
3982         {
3983           GNUNET_break_op (0);
3984           return GNUNET_NO;
3985         }
3986
3987 #if DEBUG_TRANSPORT
3988       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3989                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3990                   GNUNET_h2s (key),
3991                   a2s (ve->transport_name,
3992                        (const struct sockaddr *) ve->addr,
3993                        ve->addrlen),
3994                   ve->transport_name);
3995 #endif
3996       break;
3997     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3998       if (0 != memcmp (&pong->pid,
3999                          &my_identity,
4000                          sizeof (struct GNUNET_PeerIdentity)))
4001         {
4002           char * peer;
4003
4004           GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4005 #if DEBUG_TRANSPORT
4006           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4007                       "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4008                       GNUNET_i2s (&my_identity), 
4009                       peer );
4010 #endif
4011           GNUNET_free (peer);
4012           return GNUNET_NO;
4013         }
4014       if (ve->addrlen != 0)
4015         {
4016           /* must have been for a different validation entry */
4017           return GNUNET_YES;
4018         }
4019       tp = find_transport (ve->transport_name);
4020       if (tp == NULL)
4021         {
4022           GNUNET_break (0);
4023           return GNUNET_YES;
4024         }
4025       oal = tp->addresses;
4026       while (NULL != oal)
4027         {
4028           if ( (oal->addrlen == alen) &&
4029                (0 == memcmp (&oal[1],
4030                              &addr[slen],
4031                              alen)) )
4032             break;
4033           oal = oal->next;
4034         }
4035       if (oal == NULL)
4036         {
4037           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4038                       _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4039                       GNUNET_i2s (&pong->pid),
4040                       a2s (ve->transport_name,
4041                            &addr[slen],
4042                            alen));
4043           /* FIXME: since the sender of the PONG currently uses the
4044              wrong address (see FIMXE there!), we cannot run a 
4045              proper check here... */
4046 #if FIXME_URGENT
4047           return GNUNET_NO;
4048 #endif
4049         }
4050       if (GNUNET_OK !=
4051           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4052                                     &pong->purpose,
4053                                     &pong->signature,
4054                                     &ve->publicKey))
4055         {
4056           GNUNET_break_op (0);
4057           return GNUNET_NO;
4058         }
4059
4060 #if DEBUG_TRANSPORT
4061       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4062                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4063                   GNUNET_h2s (key),
4064                   a2s (ve->transport_name,
4065                        &addr[slen],
4066                        alen),
4067                   ve->transport_name);
4068 #endif
4069       break;
4070     default:
4071       GNUNET_break_op (0);
4072       return GNUNET_NO;
4073     }
4074   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4075     {
4076       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4077                   _("Received expired signature.  Check system time.\n"));
4078       return GNUNET_NO;
4079     }
4080   GNUNET_STATISTICS_update (stats,
4081                             gettext_noop ("# address validation successes"),
4082                             1,
4083                             GNUNET_NO);
4084   /* create the updated HELLO */
4085   GNUNET_CRYPTO_hash (&ve->publicKey,
4086                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4087                       &target.hashPubKey);
4088   if (ve->addr != NULL)
4089     {
4090       avac.done = GNUNET_NO;
4091       avac.ve = ve;
4092       hello = GNUNET_HELLO_create (&ve->publicKey,
4093                                    &add_validated_address,
4094                                    &avac);
4095       GNUNET_PEERINFO_add_peer (peerinfo,
4096                                 hello);
4097       GNUNET_free (hello);
4098     }
4099   n = find_neighbour (&target);
4100   if (n != NULL)
4101     {
4102       n->publicKey = ve->publicKey;
4103       n->public_key_valid = GNUNET_YES;
4104       fal = add_peer_address (n,
4105                               ve->transport_name,
4106                               ve->session,
4107                               ve->addr,
4108                               ve->addrlen);
4109       GNUNET_assert (fal != NULL);
4110       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4111       fal->validated = GNUNET_YES;
4112       mark_address_connected (fal);
4113       GNUNET_STATISTICS_update (stats,
4114                                 gettext_noop ("# peer addresses considered valid"),
4115                                 1,
4116                                 GNUNET_NO);
4117       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4118       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4119
4120       schedule_next_ping (fal);
4121       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4122         n->latency = fal->latency;
4123       else
4124         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4125
4126       n->distance = fal->distance;
4127       if (GNUNET_NO == n->received_pong)
4128         {
4129           n->received_pong = GNUNET_YES;
4130           notify_clients_connect (&target, n->latency, n->distance);
4131           if (NULL != (prem = n->pre_connect_message_buffer))
4132             {
4133               n->pre_connect_message_buffer = NULL;
4134               handle_payload_message (prem, n);
4135               GNUNET_free (prem);
4136             }
4137         }
4138       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4139         {
4140           GNUNET_SCHEDULER_cancel (n->retry_task);
4141           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4142           try_transmission_to_peer (n);
4143         }
4144     }
4145
4146   /* clean up validation entry */
4147   GNUNET_assert (GNUNET_YES ==
4148                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4149                                                        key,
4150                                                        ve));
4151   abort_validation (NULL, NULL, ve);
4152   return GNUNET_NO;
4153 }
4154
4155
4156 /**
4157  * Function that will be called if we receive a validation
4158  * of an address challenge that we transmitted to another
4159  * peer.  Note that the validation should only be considered
4160  * acceptable if the challenge matches AND if the sender
4161  * address is at least a plausible address for this peer
4162  * (otherwise we may be seeing a MiM attack).
4163  *
4164  * @param cls closure
4165  * @param message the pong message
4166  * @param peer who responded to our challenge
4167  * @param sender_address string describing our sender address (as observed
4168  *         by the other peer in binary format)
4169  * @param sender_address_len number of bytes in 'sender_address'
4170  */
4171 static void
4172 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4173              const struct GNUNET_PeerIdentity *peer,
4174              const char *sender_address,
4175              size_t sender_address_len)
4176 {
4177   if (0 == memcmp (peer,
4178                    &my_identity,
4179                    sizeof (struct GNUNET_PeerIdentity)))
4180     {
4181       /* PONG send to self, ignore */
4182       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4183                   "Receiving `%s' message from myself\n", 
4184                   "PONG");
4185       return;
4186     }
4187 #if DEBUG_TRANSPORT > 1
4188   /* we get tons of these that just get discarded, only log
4189      if we are quite verbose */
4190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4191               "Receiving `%s' message from `%4s'.\n", "PONG",
4192               GNUNET_i2s (peer));
4193 #endif
4194   GNUNET_STATISTICS_update (stats,
4195                             gettext_noop ("# PONG messages received"),
4196                             1,
4197                             GNUNET_NO);
4198   if (GNUNET_SYSERR !=
4199       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4200                                                   &peer->hashPubKey,
4201                                                   &check_pending_validation,
4202                                                   (void*) message))
4203     {
4204       /* This is *expected* to happen a lot since we send
4205          PONGs to *all* known addresses of the sender of
4206          the PING, so most likely we get multiple PONGs
4207          per PING, and all but the first PONG will end up
4208          here. So really we should not print anything here
4209          unless we want to be very, very verbose... */
4210 #if DEBUG_TRANSPORT > 2
4211       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4212                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4213                   "PONG",
4214                   GNUNET_i2s (peer),
4215                   "PING");
4216 #endif
4217       return;
4218     }
4219
4220 }
4221
4222
4223 /**
4224  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4225  *
4226  * @param cls the 'struct ValidationEntry*'
4227  * @param neighbour neighbour to validate, NULL if validation failed
4228  */
4229 static void
4230 transmit_hello_and_ping (void *cls,
4231                          struct NeighbourList *neighbour)
4232 {
4233   struct ValidationEntry *va = cls;
4234   struct ForeignAddressList *peer_address;
4235   struct TransportPingMessage ping;
4236   uint16_t hello_size;
4237   size_t tsize;
4238   char * message_buf;
4239   struct GNUNET_PeerIdentity id;
4240   size_t slen;
4241
4242   GNUNET_CRYPTO_hash (&va->publicKey,
4243                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4244                       &id.hashPubKey);
4245   if (neighbour == NULL)
4246     {
4247       /* FIXME: stats... */
4248       GNUNET_break (GNUNET_OK ==
4249                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4250                                                           &id.hashPubKey,
4251                                                           va));
4252       abort_validation (NULL, NULL, va);
4253       return;
4254     }
4255   neighbour->publicKey = va->publicKey;
4256   neighbour->public_key_valid = GNUNET_YES;
4257   peer_address = add_peer_address (neighbour,
4258                                    va->transport_name, NULL,
4259                                    (const void*) &va[1],
4260                                    va->addrlen);
4261   if (peer_address == NULL)
4262     {
4263       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4264                   "Failed to add peer `%4s' for plugin `%s'\n",
4265                   GNUNET_i2s (&neighbour->id),
4266                   va->transport_name);
4267       GNUNET_break (GNUNET_OK ==
4268                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4269                                                           &id.hashPubKey,
4270                                                           va));
4271       abort_validation (NULL, NULL, va);
4272       return;
4273     }
4274   if (NULL == our_hello)
4275     refresh_hello_task (NULL, NULL);
4276   hello_size = GNUNET_HELLO_size(our_hello);
4277   slen = strlen(va->transport_name) + 1;
4278   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4279   message_buf = GNUNET_malloc(tsize);
4280   ping.challenge = htonl(va->challenge);
4281   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4282   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4283   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4284   memcpy(message_buf, our_hello, hello_size);
4285   memcpy(&message_buf[hello_size],
4286          &ping,
4287          sizeof(struct TransportPingMessage));
4288   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4289          va->transport_name,
4290          slen);
4291   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4292          &va[1],
4293          va->addrlen);
4294 #if DEBUG_TRANSPORT
4295   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4296               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4297               (va->addrlen == 0)
4298               ? "<inbound>"
4299               : a2s (va->transport_name,
4300                      (const void*) &va[1], va->addrlen),
4301               va->transport_name,
4302               GNUNET_i2s (&neighbour->id),
4303               "HELLO", hello_size,
4304               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4305 #endif
4306
4307   GNUNET_STATISTICS_update (stats,
4308                             gettext_noop ("# PING messages sent for initial validation"),
4309                             1,
4310                             GNUNET_NO);
4311   transmit_to_peer (NULL, peer_address,
4312                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4313                     HELLO_VERIFICATION_TIMEOUT,
4314                     message_buf, tsize,
4315                     GNUNET_YES, neighbour);
4316   GNUNET_free(message_buf);
4317 }
4318
4319
4320 /**
4321  * Check if the given address is already being validated; if not,
4322  * append the given address to the list of entries that are being be
4323  * validated and initiate validation.
4324  *
4325  * @param cls closure ('struct CheckHelloValidatedContext *')
4326  * @param tname name of the transport
4327  * @param expiration expiration time
4328  * @param addr the address
4329  * @param addrlen length of the address
4330  * @return GNUNET_OK (always)
4331  */
4332 static int
4333 run_validation (void *cls,
4334                 const char *tname,
4335                 struct GNUNET_TIME_Absolute expiration,
4336                 const void *addr,
4337                 uint16_t addrlen)
4338 {
4339   struct CheckHelloValidatedContext *chvc = cls;
4340   struct GNUNET_PeerIdentity id;
4341   struct TransportPlugin *tp;
4342   struct ValidationEntry *va;
4343   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4344   struct CheckAddressExistsClosure caec;
4345   struct OwnAddressList *oal;
4346
4347   GNUNET_assert (addr != NULL);
4348
4349   GNUNET_STATISTICS_update (stats,
4350                             gettext_noop ("# peer addresses scheduled for validation"),
4351                             1,
4352                             GNUNET_NO);
4353   tp = find_transport (tname);
4354   if (tp == NULL)
4355     {
4356       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4357                   GNUNET_ERROR_TYPE_BULK,
4358                   _
4359                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4360                   tname);
4361       GNUNET_STATISTICS_update (stats,
4362                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4363                                 1,
4364                                 GNUNET_NO);
4365       return GNUNET_OK;
4366     }
4367   /* check if this is one of our own addresses */
4368   oal = tp->addresses;
4369   while (NULL != oal)
4370     {
4371       if ( (oal->addrlen == addrlen) &&
4372            (0 == memcmp (&oal[1],
4373                          addr,
4374                          addrlen)) )
4375         {
4376           /* not plausible, this address is equivalent to our own address! */
4377           GNUNET_STATISTICS_update (stats,
4378                                     gettext_noop ("# peer addresses not validated (loopback)"),
4379                                     1,
4380                                     GNUNET_NO);
4381           return GNUNET_OK;
4382         }
4383       oal = oal->next;
4384     }
4385   GNUNET_HELLO_get_key (chvc->hello, &pk);
4386   GNUNET_CRYPTO_hash (&pk,
4387                       sizeof (struct
4388                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4389                       &id.hashPubKey);
4390
4391   if (is_blacklisted(&id, tp))
4392     {
4393 #if DEBUG_TRANSPORT
4394       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4395                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4396                   GNUNET_i2s(&id),
4397                   tname);
4398 #endif
4399       return GNUNET_OK;
4400     }
4401
4402   caec.addr = addr;
4403   caec.addrlen = addrlen;
4404   caec.session = NULL;
4405   caec.tname = tname;
4406   caec.exists = GNUNET_NO;
4407   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4408                                          &check_address_exists,
4409                                          &caec);
4410   if (caec.exists == GNUNET_YES)
4411     {
4412       /* During validation attempts we will likely trigger the other
4413          peer trying to validate our address which in turn will cause
4414          it to send us its HELLO, so we expect to hit this case rather
4415          frequently.  Only print something if we are very verbose. */
4416 #if DEBUG_TRANSPORT > 1
4417       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4418                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4419                   a2s (tname, addr, addrlen),
4420                   tname,
4421                   GNUNET_i2s (&id));
4422 #endif
4423       GNUNET_STATISTICS_update (stats,
4424                                 gettext_noop ("# peer addresses not validated (in progress)"),
4425                                 1,
4426                                 GNUNET_NO);
4427       return GNUNET_OK;
4428     }
4429   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4430   va->chvc = chvc;
4431   chvc->ve_count++;
4432   va->transport_name = GNUNET_strdup (tname);
4433   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4434                                             UINT_MAX);
4435   va->send_time = GNUNET_TIME_absolute_get();
4436   va->addr = (const void*) &va[1];
4437   memcpy (&va[1], addr, addrlen);
4438   va->addrlen = addrlen;
4439   GNUNET_HELLO_get_key (chvc->hello,
4440                         &va->publicKey);
4441   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4442                                                    &timeout_hello_validation,
4443                                                    va);
4444   GNUNET_CONTAINER_multihashmap_put (validation_map,
4445                                      &id.hashPubKey,
4446                                      va,
4447                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4448   setup_peer_check_blacklist (&id, GNUNET_NO,
4449                               &transmit_hello_and_ping,
4450                               va);
4451   return GNUNET_OK;
4452 }
4453
4454
4455 /**
4456  * Check if addresses in validated hello "h" overlap with
4457  * those in "chvc->hello" and validate the rest.
4458  *
4459  * @param cls closure
4460  * @param peer id of the peer, NULL for last call
4461  * @param h hello message for the peer (can be NULL)
4462  * @param err_msg NULL if successful, otherwise contains error message
4463  */
4464 static void
4465 check_hello_validated (void *cls,
4466                        const struct GNUNET_PeerIdentity *peer,
4467                        const struct GNUNET_HELLO_Message *h,
4468                        const char *err_msg)
4469 {
4470   struct CheckHelloValidatedContext *chvc = cls;
4471   struct GNUNET_HELLO_Message *plain_hello;
4472   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4473   struct GNUNET_PeerIdentity target;
4474   struct NeighbourList *n;
4475
4476   if (err_msg != NULL)
4477     {
4478 #if DEBUG_TRANSPORT
4479       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4480                   _("Error in communication with PEERINFO service: %s\n"),
4481                   err_msg);
4482 #endif
4483       /* return; */
4484   }
4485
4486   if (peer == NULL)
4487     {
4488       GNUNET_STATISTICS_update (stats,
4489                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4490                                 -1,
4491                                 GNUNET_NO);
4492       chvc->piter = NULL;
4493       if (GNUNET_NO == chvc->hello_known)
4494         {
4495           /* notify PEERINFO about the peer now, so that we at least
4496              have the public key if some other component needs it */
4497           GNUNET_HELLO_get_key (chvc->hello, &pk);
4498           GNUNET_CRYPTO_hash (&pk,
4499                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4500                               &target.hashPubKey);
4501           plain_hello = GNUNET_HELLO_create (&pk,
4502                                              NULL,
4503                                              NULL);
4504           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4505           GNUNET_free (plain_hello);
4506 #if DEBUG_TRANSPORT_HELLO
4507           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4508                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4509                       "HELLO",
4510                       GNUNET_i2s (&target));
4511 #endif
4512           GNUNET_STATISTICS_update (stats,
4513                                     gettext_noop ("# new HELLOs requiring full validation"),
4514                                     1,
4515                                     GNUNET_NO);
4516           GNUNET_HELLO_iterate_addresses (chvc->hello,
4517                                           GNUNET_NO,
4518                                           &run_validation,
4519                                           chvc);
4520         }
4521       else
4522         {
4523           GNUNET_STATISTICS_update (stats,
4524                                     gettext_noop ("# duplicate HELLO (peer known)"),
4525                                     1,
4526                                     GNUNET_NO);
4527         }
4528       chvc->ve_count--;
4529       if (chvc->ve_count == 0)
4530         {
4531           GNUNET_CONTAINER_DLL_remove (chvc_head,
4532                                        chvc_tail,
4533                                        chvc);
4534           GNUNET_free (chvc);
4535         }
4536       return;
4537     }
4538   if (h == NULL)
4539     return;
4540 #if DEBUG_TRANSPORT_HELLO
4541   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4542               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4543               "HELLO",
4544               GNUNET_i2s (peer));
4545 #endif
4546   chvc->hello_known = GNUNET_YES;
4547   n = find_neighbour (peer);
4548   if (n != NULL)
4549     {
4550 #if DEBUG_TRANSPORT_HELLO
4551       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4552                   "Calling hello_iterate_addresses for %s!\n",
4553                   GNUNET_i2s (peer));
4554 #endif
4555       GNUNET_HELLO_iterate_addresses (h,
4556                                       GNUNET_NO,
4557                                       &add_to_foreign_address_list,
4558                                       n);
4559       try_transmission_to_peer (n);
4560     }
4561   else
4562     {
4563 #if DEBUG_TRANSPORT_HELLO
4564       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4565                   "No existing neighbor record for %s!\n",
4566                   GNUNET_i2s (peer));
4567 #endif
4568       GNUNET_STATISTICS_update (stats,
4569                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4570                                 1,
4571                                 GNUNET_NO);
4572     }
4573   GNUNET_STATISTICS_update (stats,
4574                             gettext_noop ("# HELLO validations (update case)"),
4575                             1,
4576                             GNUNET_NO);
4577   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4578                                       h,
4579                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4580                                       &run_validation,
4581                                       chvc);
4582 }
4583
4584
4585 /**
4586  * Process HELLO-message.
4587  *
4588  * @param plugin transport involved, may be NULL
4589  * @param message the actual message
4590  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4591  */
4592 static int
4593 process_hello (struct TransportPlugin *plugin,
4594                const struct GNUNET_MessageHeader *message)
4595 {
4596   uint16_t hsize;
4597   struct GNUNET_PeerIdentity target;
4598   const struct GNUNET_HELLO_Message *hello;
4599   struct CheckHelloValidatedContext *chvc;
4600   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4601   struct NeighbourList *n;
4602 #if DEBUG_TRANSPORT_HELLO > 2
4603   char *my_id;
4604 #endif
4605
4606   hsize = ntohs (message->size);
4607   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4608       (hsize < sizeof (struct GNUNET_MessageHeader)))
4609     {
4610       GNUNET_break (0);
4611       return GNUNET_SYSERR;
4612     }
4613   GNUNET_STATISTICS_update (stats,
4614                             gettext_noop ("# HELLOs received for validation"),
4615                             1,
4616                             GNUNET_NO);
4617
4618   hello = (const struct GNUNET_HELLO_Message *) message;
4619   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4620     {
4621 #if DEBUG_TRANSPORT_HELLO
4622       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4623                   "Unable to get public key from `%s' for `%4s'!\n",
4624                   "HELLO",
4625                   GNUNET_i2s (&target));
4626 #endif
4627       GNUNET_break_op (0);
4628       return GNUNET_SYSERR;
4629     }
4630   GNUNET_CRYPTO_hash (&publicKey,
4631                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4632                       &target.hashPubKey);
4633
4634 #if DEBUG_TRANSPORT_HELLO
4635   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4636               "Received `%s' message for `%4s'\n",
4637               "HELLO",
4638               GNUNET_i2s (&target));
4639 #endif
4640   if (0 == memcmp (&my_identity,
4641                    &target,
4642                    sizeof (struct GNUNET_PeerIdentity)))
4643     {
4644       GNUNET_STATISTICS_update (stats,
4645                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4646                                 1,
4647                                 GNUNET_NO);
4648       return GNUNET_OK;
4649     }
4650   n = find_neighbour (&target);
4651   if ( (NULL != n) &&
4652        (! n->public_key_valid) )
4653     {
4654       GNUNET_HELLO_get_key (hello, &n->publicKey);
4655       n->public_key_valid = GNUNET_YES;
4656     }
4657
4658   /* check if load is too high before doing expensive stuff */
4659   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4660     {
4661       GNUNET_STATISTICS_update (stats,
4662                                 gettext_noop ("# HELLOs ignored due to high load"),
4663                                 1,
4664                                 GNUNET_NO);
4665 #if DEBUG_TRANSPORT_HELLO
4666       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4667                   "Ignoring `%s' for `%4s', load too high.\n",
4668                   "HELLO",
4669                   GNUNET_i2s (&target));
4670 #endif
4671       return GNUNET_OK;
4672     }
4673
4674
4675   chvc = chvc_head;
4676   while (NULL != chvc)
4677     {
4678       if (GNUNET_HELLO_equals (hello,
4679                                chvc->hello,
4680                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4681         {
4682 #if DEBUG_TRANSPORT_HELLO > 2
4683           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4684                       "Received duplicate `%s' message for `%4s'; ignored\n",
4685                       "HELLO",
4686                       GNUNET_i2s (&target));
4687 #endif
4688           return GNUNET_OK; /* validation already pending */
4689         }
4690       if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4691         GNUNET_break (0 != memcmp (hello, chvc->hello,
4692                                    GNUNET_HELLO_size(hello)));
4693       chvc = chvc->next;
4694     }
4695
4696 #if BREAK_TESTS
4697   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4698   if ((NULL != temp_neighbor))
4699     {
4700       fprintf(stderr, "Already know peer, ignoring hello\n");
4701       return GNUNET_OK;
4702     }
4703 #endif
4704
4705 #if DEBUG_TRANSPORT_HELLO > 2
4706   if (plugin != NULL)
4707     {
4708       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4709 #if DEBUG_TRANSPORT
4710       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4711                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4712                   my_id,
4713                   "HELLO",
4714                   GNUNET_i2s (&target),
4715                   plugin->short_name,
4716                   GNUNET_HELLO_size(hello));
4717 #endif
4718       GNUNET_free(my_id);
4719     }
4720 #endif
4721   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4722   chvc->ve_count = 1;
4723   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4724   memcpy (&chvc[1], hello, hsize);
4725   GNUNET_CONTAINER_DLL_insert (chvc_head,
4726                                chvc_tail,
4727                                chvc);
4728   /* finally, check if HELLO was previously validated
4729      (continuation will then schedule actual validation) */
4730   GNUNET_STATISTICS_update (stats,
4731                             gettext_noop ("# peerinfo process hello iterate requests"),
4732                             1,
4733                             GNUNET_NO);
4734   GNUNET_STATISTICS_update (stats,
4735                             gettext_noop ("# outstanding peerinfo iterate requests"),
4736                             1,
4737                             GNUNET_NO);
4738   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4739                                          &target,
4740                                          HELLO_VERIFICATION_TIMEOUT,
4741                                          &check_hello_validated, chvc);
4742   return GNUNET_OK;
4743 }
4744
4745
4746 /**
4747  * The peer specified by the given neighbour has timed-out or a plugin
4748  * has disconnected.  We may either need to do nothing (other plugins
4749  * still up), or trigger a full disconnect and clean up.  This
4750  * function updates our state and does the necessary notifications.
4751  * Also notifies our clients that the neighbour is now officially
4752  * gone.
4753  *
4754  * @param n the neighbour list entry for the peer
4755  * @param check GNUNET_YES to check if ALL addresses for this peer
4756  *              are gone, GNUNET_NO to force a disconnect of the peer
4757  *              regardless of whether other addresses exist.
4758  */
4759 static void
4760 disconnect_neighbour (struct NeighbourList *n, int check)
4761 {
4762   struct ReadyList *rpos;
4763   struct NeighbourList *npos;
4764   struct NeighbourList *nprev;
4765   struct MessageQueue *mq;
4766   struct ForeignAddressList *peer_addresses;
4767   struct ForeignAddressList *peer_pos;
4768
4769   if (GNUNET_YES == check)
4770     {
4771       rpos = n->plugins;
4772       while (NULL != rpos)
4773         {
4774           peer_addresses = rpos->addresses;
4775           while (peer_addresses != NULL)
4776             {
4777                   // Do not disconnect if: an address is connected or an inbound address exists
4778               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4779                 {
4780 #if DEBUG_TRANSPORT
4781                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4782                               "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4783                               GNUNET_i2s (&n->id),
4784                               a2s (peer_addresses->ready_list->plugin->short_name,
4785                                    peer_addresses->addr,
4786                                    peer_addresses->addrlen));
4787 #endif
4788                   return;             /* still connected */
4789                 }
4790               peer_addresses = peer_addresses->next;
4791             }
4792           rpos = rpos->next;
4793         }
4794     }
4795 #if DEBUG_TRANSPORT
4796   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4797               "Disconnecting from `%4s'\n",
4798               GNUNET_i2s (&n->id));
4799 #endif
4800
4801   /* remove n from neighbours list */
4802   nprev = NULL;
4803   npos = neighbours;
4804   while ((npos != NULL) && (npos != n))
4805     {
4806       nprev = npos;
4807       npos = npos->next;
4808     }
4809   GNUNET_assert (npos != NULL);
4810   if (nprev == NULL)
4811     neighbours = n->next;
4812   else
4813     nprev->next = n->next;
4814
4815   /* notify all clients about disconnect */
4816   if (GNUNET_YES == n->received_pong)
4817     notify_clients_disconnect (&n->id);
4818
4819   /* clean up all plugins, cancel connections and pending transmissions */
4820   while (NULL != (rpos = n->plugins))
4821     {
4822       n->plugins = rpos->next;
4823       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4824       while (rpos->addresses != NULL)
4825         {
4826           peer_pos = rpos->addresses;
4827           rpos->addresses = peer_pos->next;
4828           if (peer_pos->connected == GNUNET_YES)
4829             GNUNET_STATISTICS_update (stats,
4830                                       gettext_noop ("# connected addresses"),
4831                                       -1,
4832                                       GNUNET_NO);
4833           if (GNUNET_YES == peer_pos->validated)
4834             GNUNET_STATISTICS_update (stats,
4835                                       gettext_noop ("# peer addresses considered valid"),
4836                                       -1,
4837                                       GNUNET_NO);
4838           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4839             {
4840               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4841               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4842             }
4843           GNUNET_free(peer_pos->ressources);
4844           peer_pos->ressources = NULL;
4845           GNUNET_free(peer_pos->quality);
4846           peer_pos->ressources = NULL;
4847           GNUNET_free(peer_pos);
4848           if (ats != NULL)
4849             ats->stat.recreate_problem = GNUNET_YES;
4850         }
4851       GNUNET_free (rpos);
4852     }
4853
4854   /* free all messages on the queue */
4855   while (NULL != (mq = n->messages_head))
4856     {
4857       GNUNET_STATISTICS_update (stats,
4858                                 gettext_noop ("# bytes in message queue for other peers"),
4859                                 - (int64_t) mq->message_buf_size,
4860                                 GNUNET_NO);
4861       GNUNET_STATISTICS_update (stats,
4862                                 gettext_noop ("# bytes discarded due to disconnect"),
4863                                 mq->message_buf_size,
4864                                 GNUNET_NO);
4865       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4866                                    n->messages_tail,
4867                                    mq);
4868       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4869                                  &n->id,
4870                                  sizeof(struct GNUNET_PeerIdentity)));
4871       GNUNET_free (mq);
4872     }
4873
4874   while (NULL != (mq = n->cont_head))
4875     {
4876
4877       GNUNET_CONTAINER_DLL_remove (n->cont_head,
4878                                    n->cont_tail,
4879                                    mq);
4880       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4881                                  &n->id,
4882                                  sizeof(struct GNUNET_PeerIdentity)));
4883       GNUNET_free (mq);
4884     }
4885
4886   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4887     {
4888       GNUNET_SCHEDULER_cancel (n->timeout_task);
4889       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4890     }
4891   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4892     {
4893       GNUNET_SCHEDULER_cancel (n->retry_task);
4894       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4895     }
4896   if (n->piter != NULL)
4897     {
4898       GNUNET_PEERINFO_iterate_cancel (n->piter);
4899       GNUNET_STATISTICS_update (stats,
4900                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4901                                 -1,
4902                                 GNUNET_NO);
4903       n->piter = NULL;
4904     }
4905   /* finally, free n itself */
4906   GNUNET_STATISTICS_update (stats,
4907                             gettext_noop ("# active neighbours"),
4908                             -1,
4909                             GNUNET_NO);
4910   GNUNET_free_non_null (n->pre_connect_message_buffer);
4911   GNUNET_free (n);
4912 }
4913
4914
4915 /**
4916  * We have received a PING message from someone.  Need to send a PONG message
4917  * in response to the peer by any means necessary.
4918  */
4919 static int
4920 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4921              const struct GNUNET_PeerIdentity *peer,
4922              struct Session *session,
4923              const char *sender_address,
4924              uint16_t sender_address_len)
4925 {
4926   struct TransportPlugin *plugin = cls;
4927   struct SessionHeader *session_header = (struct SessionHeader*) session;
4928   struct TransportPingMessage *ping;
4929   struct TransportPongMessage *pong;
4930   struct NeighbourList *n;
4931   struct ReadyList *rl;
4932   struct ForeignAddressList *fal;
4933   struct OwnAddressList *oal;
4934   const char *addr;
4935   size_t alen;
4936   size_t slen;
4937   int did_pong;
4938
4939   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4940     {
4941       GNUNET_break_op (0);
4942       return GNUNET_SYSERR;
4943     }
4944
4945   ping = (struct TransportPingMessage *) message;
4946   if (0 != memcmp (&ping->target,
4947                    plugin->env.my_identity,
4948                    sizeof (struct GNUNET_PeerIdentity)))
4949     {
4950 #if DEBUG_TRANSPORT
4951       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4952                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4953                   "PING",
4954                   (sender_address != NULL)
4955                   ? a2s (plugin->short_name,
4956                          (const struct sockaddr *)sender_address,
4957                          sender_address_len)
4958                   : "<inbound>",
4959                   GNUNET_i2s (&ping->target));
4960 #endif
4961       return GNUNET_SYSERR;
4962     }
4963 #if DEBUG_PING_PONG
4964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4965               "Processing `%s' from `%s'\n",
4966               "PING",
4967               (sender_address != NULL)
4968               ? a2s (plugin->short_name,
4969                      (const struct sockaddr *)sender_address,
4970                      sender_address_len)
4971               : "<inbound>");
4972 #endif
4973   GNUNET_STATISTICS_update (stats,
4974                             gettext_noop ("# PING messages received"),
4975                             1,
4976                             GNUNET_NO);
4977   addr = (const char*) &ping[1];
4978   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4979   slen = strlen (plugin->short_name) + 1;
4980   if (alen == 0)
4981     {
4982       /* peer wants to confirm that we have an outbound connection to him */
4983       if (session == NULL)
4984         {
4985           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4986                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4987                       GNUNET_i2s (peer));
4988           return GNUNET_SYSERR;
4989         }
4990       /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4991         1) it is NULL when we need to have a real value
4992         2) it is documented to be the address of the sender (source-IP), where
4993         what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4994         have...
4995       */
4996       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4997                   "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4998                   a2s (plugin->short_name,
4999                        sender_address,
5000                        sender_address_len),                    
5001                   GNUNET_i2s (peer));
5002
5003       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5004       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5005       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5006       pong->purpose.size =
5007         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5008                sizeof (uint32_t) +
5009                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5010                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5011       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5012       pong->challenge = ping->challenge;
5013       pong->addrlen = htonl(sender_address_len + slen);
5014       memcpy(&pong->pid,
5015              peer,
5016              sizeof(struct GNUNET_PeerIdentity));
5017       memcpy (&pong[1],
5018               plugin->short_name,
5019               slen);
5020       if ((sender_address!=NULL) && (sender_address_len > 0))
5021                   memcpy (&((char*)&pong[1])[slen],
5022                           sender_address,
5023                           sender_address_len);
5024       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5025         {
5026           /* create / update cached sig */
5027 #if DEBUG_TRANSPORT
5028           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5029                       "Creating PONG signature to indicate active connection.\n");
5030 #endif
5031           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5032           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5033           GNUNET_assert (GNUNET_OK ==
5034                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5035                                                  &pong->purpose,
5036                                                  &session_header->pong_signature));
5037         }
5038       else
5039         {
5040           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5041         }
5042       memcpy (&pong->signature,
5043               &session_header->pong_signature,
5044               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5045
5046
5047     }
5048   else
5049     {
5050       /* peer wants to confirm that this is one of our addresses */
5051       addr += slen;
5052       alen -= slen;
5053       if (GNUNET_OK !=
5054           plugin->api->check_address (plugin->api->cls,
5055                                       addr,
5056                                       alen))
5057         {
5058           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5059                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5060                       a2s (plugin->short_name,
5061                            addr,
5062                            alen));
5063           return GNUNET_NO;
5064         }
5065       oal = plugin->addresses;
5066       while (NULL != oal)
5067         {
5068           if ( (oal->addrlen == alen) &&
5069                (0 == memcmp (addr,
5070                              &oal[1],
5071                              alen)) )
5072             break;
5073           oal = oal->next;
5074         }
5075       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5076       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5077       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5078       pong->purpose.size =
5079         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5080                sizeof (uint32_t) +
5081                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5082                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5083       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5084       pong->challenge = ping->challenge;
5085       pong->addrlen = htonl(alen + slen);
5086       memcpy(&pong->pid,
5087              &my_identity,
5088              sizeof(struct GNUNET_PeerIdentity));
5089       memcpy (&pong[1], plugin->short_name, slen);
5090       memcpy (&((char*)&pong[1])[slen], addr, alen);
5091       if ( (oal != NULL) &&
5092            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5093         {
5094           /* create / update cached sig */
5095 #if DEBUG_TRANSPORT
5096           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5097                       "Creating PONG signature to indicate ownership.\n");
5098 #endif
5099           oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5100           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5101           GNUNET_assert (GNUNET_OK ==
5102                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5103                                                  &pong->purpose,
5104                                                  &oal->pong_signature));
5105           memcpy (&pong->signature,
5106                   &oal->pong_signature,
5107                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5108         }
5109       else if (oal == NULL)
5110         {
5111           /* not using cache (typically DV-only) */
5112           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5113           GNUNET_assert (GNUNET_OK ==
5114                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5115                                                  &pong->purpose,
5116                                                  &pong->signature));
5117         }
5118       else
5119         {
5120           /* can used cached version */
5121           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5122           memcpy (&pong->signature,
5123                   &oal->pong_signature,
5124                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5125         }
5126     }
5127   n = find_neighbour(peer);
5128   GNUNET_assert (n != NULL);
5129   did_pong = GNUNET_NO;
5130   /* first try reliable response transmission */
5131   rl = n->plugins;
5132   while (rl != NULL)
5133     {
5134       fal = rl->addresses;
5135       while (fal != NULL)
5136         {
5137           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5138                                            peer,
5139                                            (const char*) pong,
5140                                            ntohs (pong->header.size),
5141                                            TRANSPORT_PONG_PRIORITY,
5142                                            HELLO_VERIFICATION_TIMEOUT,
5143                                            fal->session,
5144                                            fal->addr,
5145                                            fal->addrlen,
5146                                            GNUNET_SYSERR,
5147                                            NULL, NULL))
5148             {
5149               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5150                           "Transmitted PONG to `%s' via reliable mechanism\n",
5151                           GNUNET_i2s (peer));
5152               /* done! */
5153               GNUNET_STATISTICS_update (stats,
5154                                         gettext_noop ("# PONGs unicast via reliable transport"),
5155                                         1,
5156                                         GNUNET_NO);
5157               GNUNET_free (pong);
5158               return GNUNET_OK;
5159             }
5160           did_pong = GNUNET_YES;
5161           fal = fal->next;
5162         }
5163       rl = rl->next;
5164     }
5165   /* no reliable method found, do multicast */
5166   GNUNET_STATISTICS_update (stats,
5167                             gettext_noop ("# PONGs multicast to all available addresses"),
5168                             1,
5169                             GNUNET_NO);
5170   rl = n->plugins;
5171   while (rl != NULL)
5172     {
5173       fal = rl->addresses;
5174       while (fal != NULL)
5175         {
5176           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5177                       "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5178                       GNUNET_i2s (peer),
5179                       a2s (rl->plugin->short_name,
5180                            fal->addr,
5181                            fal->addrlen),
5182                       rl->plugin->short_name);
5183           transmit_to_peer(NULL, fal,
5184                            TRANSPORT_PONG_PRIORITY,
5185                            HELLO_VERIFICATION_TIMEOUT,
5186                            (const char *)pong,
5187                            ntohs(pong->header.size),
5188                            GNUNET_YES,
5189                            n);
5190           did_pong = GNUNET_YES;
5191           fal = fal->next;
5192         }
5193       rl = rl->next;
5194     }
5195   GNUNET_free(pong);
5196   if (GNUNET_YES != did_pong)
5197     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5198                 _("Could not send PONG to `%s': no address available\n"),
5199                 GNUNET_i2s (peer));
5200   return GNUNET_OK;
5201 }
5202
5203
5204 /**
5205  * Function called by the plugin for each received message.  Update
5206  * data volumes, possibly notify plugins about reducing the rate at
5207  * which they read from the socket and generally forward to our
5208  * receive callback.
5209  *
5210  * @param cls the "struct TransportPlugin *" we gave to the plugin
5211  * @param peer (claimed) identity of the other peer
5212  * @param message the message, NULL if we only care about
5213  *                learning about the delay until we should receive again
5214  * @param ats_data information for automatic transport selection
5215  * @param ats_count number of elements in ats not including 0-terminator
5216  * @param session identifier used for this session (can be NULL)
5217  * @param sender_address binary address of the sender (if observed)
5218  * @param sender_address_len number of bytes in sender_address
5219  * @return how long in ms the plugin should wait until receiving more data
5220  *         (plugins that do not support this, can ignore the return value)
5221  */
5222 static struct GNUNET_TIME_Relative
5223 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5224                     const struct GNUNET_MessageHeader *message,
5225                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5226                     uint32_t ats_count,
5227                     struct Session *session,
5228                     const char *sender_address,
5229                     uint16_t sender_address_len)
5230 {
5231   struct TransportPlugin *plugin = cls;
5232   struct ReadyList *service_context;
5233   struct ForeignAddressList *peer_address;
5234   uint16_t msize;
5235   struct NeighbourList *n;
5236   struct GNUNET_TIME_Relative ret;
5237   uint32_t distance;
5238   int c;
5239
5240   if (0 == memcmp (peer,
5241                    &my_identity,
5242                    sizeof (struct GNUNET_PeerIdentity)))
5243     {
5244       /* refuse to receive from myself */
5245       GNUNET_break (0); 
5246       return GNUNET_TIME_UNIT_FOREVER_REL;
5247     }
5248   if (is_blacklisted (peer, plugin))
5249     return GNUNET_TIME_UNIT_FOREVER_REL;
5250   n = find_neighbour (peer);
5251   if (n == NULL)
5252     n = setup_new_neighbour (peer, GNUNET_YES);
5253   service_context = n->plugins;
5254   while ((service_context != NULL) && (plugin != service_context->plugin))
5255     service_context = service_context->next;
5256   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5257   peer_address = NULL;
5258   distance = 1;
5259
5260   for (c=0; c<ats_count; c++)
5261     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5262       distance = ntohl(ats_data[c].value);
5263
5264
5265   if (message != NULL)
5266     {
5267       if ( (session != NULL) ||
5268            (sender_address != NULL) )
5269         peer_address = add_peer_address (n,
5270                                          plugin->short_name,
5271                                          session,
5272                                          sender_address,
5273                                          sender_address_len);
5274       if (peer_address != NULL)
5275         {
5276           update_addr_ats(peer_address, ats_data, ats_count);
5277           update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5278           
5279           peer_address->distance = distance;
5280           if (GNUNET_YES == peer_address->validated)
5281             mark_address_connected (peer_address);
5282           peer_address->timeout
5283             = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5284           schedule_next_ping (peer_address);
5285         }
5286       /* update traffic received amount ... */
5287       msize = ntohs (message->size);
5288
5289       GNUNET_STATISTICS_update (stats,
5290                                 gettext_noop ("# bytes received from other peers"),
5291                                 msize,
5292                                 GNUNET_NO);
5293       n->distance = distance;
5294       n->peer_timeout =
5295         GNUNET_TIME_relative_to_absolute
5296         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5297       GNUNET_SCHEDULER_cancel (n->timeout_task);
5298       n->timeout_task =
5299         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5300                                       &neighbour_timeout_task, n);
5301       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5302         {
5303           /* dropping message due to frequent inbound volume violations! */
5304           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5305                       GNUNET_ERROR_TYPE_BULK,
5306                       _
5307                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5308                       n->in_tracker.available_bytes_per_s__,
5309                       n->quota_violation_count);
5310           GNUNET_STATISTICS_update (stats,
5311                                     gettext_noop ("# bandwidth quota violations by other peers"),
5312                                     1,
5313                                     GNUNET_NO);
5314           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5315         }
5316     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5317         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5318       {
5319         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5320         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5321         /* Force ressource and quality update */
5322         if ((value == 4) && (ats != NULL))
5323           {
5324             ats->stat.modified_resources = GNUNET_YES;
5325             ats->stat.modified_quality = GNUNET_YES;
5326           }
5327         /* Force cost update */
5328         if ((value == 3) && (ats != NULL))
5329           ats->stat.modified_resources = GNUNET_YES;
5330         /* Force quality update */
5331         if ((value == 2) && (ats != NULL))
5332           ats->stat.modified_quality = GNUNET_YES;
5333         /* Force full rebuild */
5334         if ((value == 1) && (ats != NULL))
5335           ats->stat.recreate_problem = GNUNET_YES;
5336       }
5337     
5338 #if DEBUG_PING_PONG
5339     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5340                 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5341                 ntohs (message->type),
5342                 ntohs (message->size),
5343                 GNUNET_i2s (peer));
5344 #endif
5345       switch (ntohs (message->type))
5346         {
5347         case GNUNET_MESSAGE_TYPE_HELLO:
5348           GNUNET_STATISTICS_update (stats,
5349                                     gettext_noop ("# HELLO messages received from other peers"),
5350                                     1,
5351                                     GNUNET_NO);
5352           process_hello (plugin, message);
5353           break;
5354         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5355           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5356           if (! n->received_pong)
5357             transmit_plain_ping (n);
5358           break;
5359         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5360           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5361           break;
5362         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5363           break;
5364         default:
5365           handle_payload_message (message, n);
5366           break;
5367         }
5368     }
5369   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5370   if (ret.rel_value > 0)
5371     {
5372 #if DEBUG_TRANSPORT 
5373       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5374                   "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5375                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5376                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5377                   (unsigned long long) ret.rel_value);
5378 #endif
5379       GNUNET_STATISTICS_update (stats,
5380                                 gettext_noop ("# ms throttling suggested"),
5381                                 (int64_t) ret.rel_value,
5382                                 GNUNET_NO);
5383     }
5384   return ret;
5385 }
5386
5387 /**
5388  * Handle START-message.  This is the first message sent to us
5389  * by any client which causes us to add it to our list.
5390  *
5391  * @param cls closure (always NULL)
5392  * @param client identification of the client
5393  * @param message the actual message
5394  */
5395 static void
5396 handle_start (void *cls,
5397               struct GNUNET_SERVER_Client *client,
5398               const struct GNUNET_MessageHeader *message)
5399 {
5400   const struct StartMessage *start;
5401   struct TransportClient *c;
5402   struct ConnectInfoMessage * cim;
5403   struct NeighbourList *n;
5404   uint32_t ats_count;
5405   size_t size;
5406
5407   start = (const struct StartMessage*) message;
5408 #if DEBUG_TRANSPORT
5409   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5410               "Received `%s' request from client\n", "START");
5411 #endif
5412   c = clients;
5413   while (c != NULL)
5414     {
5415       if (c->client == client)
5416         {
5417           /* client already on our list! */
5418           GNUNET_break (0);
5419           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5420           return;
5421         }
5422       c = c->next;
5423     }
5424   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5425        (0 != memcmp (&start->self,
5426                      &my_identity,
5427                      sizeof (struct GNUNET_PeerIdentity))) )
5428     {
5429       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5430                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5431                   GNUNET_i2s (&start->self));
5432       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5433       return;
5434     }
5435   c = GNUNET_malloc (sizeof (struct TransportClient));
5436   c->next = clients;
5437   clients = c;
5438   c->client = client;
5439   if (our_hello != NULL)
5440     {
5441 #if DEBUG_TRANSPORT
5442       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5443                   "Sending our own `%s' to new client\n", "HELLO");
5444 #endif
5445       transmit_to_client (c,
5446                           (const struct GNUNET_MessageHeader *) our_hello,
5447                           GNUNET_NO);
5448       /* tell new client about all existing connections */
5449       ats_count = 2;
5450       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5451       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5452         {
5453           GNUNET_break(0);
5454         }
5455       cim = GNUNET_malloc (size);
5456       cim->header.size = htons (size);
5457       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5458       cim->ats_count = htonl(ats_count);
5459       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5460       (&(cim->ats))[2].value = htonl (0);
5461       n = neighbours;
5462       while (n != NULL)
5463         {
5464           if (GNUNET_YES == n->received_pong)
5465             {
5466               (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5467               (&(cim->ats))[0].value = htonl (n->distance);
5468               (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5469               (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5470               cim->id = n->id;
5471               transmit_to_client (c, &cim->header, GNUNET_NO);
5472             }
5473           n = n->next;
5474         }
5475       GNUNET_free (cim);
5476     }
5477   else
5478     {
5479 #if DEBUG_TRANSPORT_HELLO
5480       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5481                   "No HELLO created yet, will transmit HELLO to client later!\n");
5482 #endif
5483       refresh_hello ();
5484     }
5485   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5486 }
5487
5488
5489 /**
5490  * Handle HELLO-message.
5491  *
5492  * @param cls closure (always NULL)
5493  * @param client identification of the client
5494  * @param message the actual message
5495  */
5496 static void
5497 handle_hello (void *cls,
5498               struct GNUNET_SERVER_Client *client,
5499               const struct GNUNET_MessageHeader *message)
5500 {
5501   int ret;
5502
5503   GNUNET_STATISTICS_update (stats,
5504                             gettext_noop ("# HELLOs received from clients"),
5505                             1,
5506                             GNUNET_NO);
5507   ret = process_hello (NULL, message);
5508   GNUNET_SERVER_receive_done (client, ret);
5509 }
5510
5511
5512 /**
5513  * Closure for 'transmit_client_message'; followed by
5514  * 'msize' bytes of the actual message.
5515  */
5516 struct TransmitClientMessageContext
5517 {
5518   /**
5519    * Client on whom's behalf we are sending.
5520    */
5521   struct GNUNET_SERVER_Client *client;
5522
5523   /**
5524    * Timeout for the transmission.
5525    */
5526   struct GNUNET_TIME_Absolute timeout;
5527
5528   /**
5529    * Message priority.
5530    */
5531   uint32_t priority;
5532
5533   /**
5534    * Size of the message in bytes.
5535    */
5536   uint16_t msize;
5537 };
5538
5539
5540 /**
5541  * Schedule transmission of a message we got from a client to a peer.
5542  *
5543  * @param cls the 'struct TransmitClientMessageContext*'
5544  * @param n destination, or NULL on error (in that case, drop the message)
5545  */
5546 static void
5547 transmit_client_message (void *cls,
5548                          struct NeighbourList *n)
5549 {
5550   struct TransmitClientMessageContext *tcmc = cls;
5551   struct TransportClient *tc;
5552
5553   tc = clients;
5554   while ((tc != NULL) && (tc->client != tcmc->client))
5555     tc = tc->next;
5556
5557   if (n != NULL)
5558     {
5559       transmit_to_peer (tc, NULL, tcmc->priority,
5560                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5561                         (char *)&tcmc[1],
5562                         tcmc->msize, GNUNET_NO, n);
5563     }
5564   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5565   GNUNET_SERVER_client_drop (tcmc->client);
5566   GNUNET_free (tcmc);
5567 }
5568
5569
5570 /**
5571  * Handle SEND-message.
5572  *
5573  * @param cls closure (always NULL)
5574  * @param client identification of the client
5575  * @param message the actual message
5576  */
5577 static void
5578 handle_send (void *cls,
5579              struct GNUNET_SERVER_Client *client,
5580              const struct GNUNET_MessageHeader *message)
5581 {
5582   const struct OutboundMessage *obm;
5583   const struct GNUNET_MessageHeader *obmm;
5584   struct TransmitClientMessageContext *tcmc;
5585   uint16_t size;
5586   uint16_t msize;
5587
5588   size = ntohs (message->size);
5589   if (size <
5590       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5591     {
5592       GNUNET_break (0);
5593       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5594       return;
5595     }
5596   GNUNET_STATISTICS_update (stats,
5597                             gettext_noop ("# payload received for other peers"),
5598                             size,
5599                             GNUNET_NO);
5600   obm = (const struct OutboundMessage *) message;
5601   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5602   msize = size - sizeof (struct OutboundMessage);
5603 #if DEBUG_TRANSPORT
5604   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5605               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5606               "SEND", GNUNET_i2s (&obm->peer),
5607               ntohs (obmm->type),
5608               msize);
5609 #endif
5610   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5611   tcmc->client = client;
5612   tcmc->priority = ntohl (obm->priority);
5613   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5614   tcmc->msize = msize;
5615   /* FIXME: this memcpy can be up to 7% of our total runtime */
5616   memcpy (&tcmc[1], obmm, msize);
5617   GNUNET_SERVER_client_keep (client);
5618   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5619                               &transmit_client_message,
5620                               tcmc);
5621 }
5622
5623
5624 /**
5625  * Handle request connect message
5626  *
5627  * @param cls closure (always NULL)
5628  * @param client identification of the client
5629  * @param message the actual message
5630  */
5631 static void
5632 handle_request_connect (void *cls,
5633                         struct GNUNET_SERVER_Client *client,
5634                         const struct GNUNET_MessageHeader *message)
5635 {
5636   const struct TransportRequestConnectMessage *trcm =
5637     (const struct TransportRequestConnectMessage *) message;
5638
5639   GNUNET_STATISTICS_update (stats,
5640                             gettext_noop ("# REQUEST CONNECT messages received"),
5641                             1,
5642                             GNUNET_NO);
5643 #if DEBUG_TRANSPORT
5644   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
5645              "Received a request connect message for peer `%s'\n", 
5646              GNUNET_i2s(&trcm->peer));
5647 #endif
5648   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5649                               NULL, NULL);
5650   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5651 }
5652
5653
5654 /**
5655  * Handle SET_QUOTA-message.
5656  *
5657  * @param cls closure (always NULL)
5658  * @param client identification of the client
5659  * @param message the actual message
5660  */
5661 static void
5662 handle_set_quota (void *cls,
5663                   struct GNUNET_SERVER_Client *client,
5664                   const struct GNUNET_MessageHeader *message)
5665 {
5666   const struct QuotaSetMessage *qsm =
5667     (const struct QuotaSetMessage *) message;
5668   struct NeighbourList *n;
5669
5670   GNUNET_STATISTICS_update (stats,
5671                             gettext_noop ("# SET QUOTA messages received"),
5672                             1,
5673                             GNUNET_NO);
5674   n = find_neighbour (&qsm->peer);
5675   if (n == NULL)
5676     {
5677       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5678       GNUNET_STATISTICS_update (stats,
5679                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5680                                 1,
5681                                 GNUNET_NO);
5682       return;
5683     }
5684 #if DEBUG_TRANSPORT 
5685   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5686               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5687               "SET_QUOTA",
5688               (unsigned int) ntohl (qsm->quota.value__),
5689               (unsigned int) n->in_tracker.available_bytes_per_s__,
5690               GNUNET_i2s (&qsm->peer));
5691 #endif
5692   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5693                                          qsm->quota);
5694   if (0 == ntohl (qsm->quota.value__))
5695     {
5696 #if DEBUG_TRANSPORT
5697       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5698                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5699                 "SET_QUOTA");
5700 #endif
5701       GNUNET_STATISTICS_update (stats,
5702                                 gettext_noop ("# disconnects due to quota of 0"),
5703                                 1,
5704                                 GNUNET_NO);
5705       disconnect_neighbour (n, GNUNET_NO);
5706     }
5707   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5708 }
5709
5710
5711 /**
5712  * Take the given address and append it to the set of results sent back to
5713  * the client.
5714  *
5715  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5716  * @param address the resolved name, NULL to indicate the last response
5717  */
5718 static void
5719 transmit_address_to_client (void *cls, const char *address)
5720 {
5721   struct GNUNET_SERVER_TransmitContext *tc = cls;
5722   size_t slen;
5723
5724   if (NULL != address)
5725     {
5726       slen = strlen (address) + 1;
5727       GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5728                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5729     }
5730   else
5731     {
5732       GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5733     }
5734 }
5735
5736
5737 /**
5738  * Handle AddressLookup-message.
5739  *
5740  * @param cls closure (always NULL)
5741  * @param client identification of the client
5742  * @param message the actual message
5743  */
5744 static void
5745 handle_address_lookup (void *cls,
5746                        struct GNUNET_SERVER_Client *client,
5747                        const struct GNUNET_MessageHeader *message)
5748 {
5749   const struct AddressLookupMessage *alum;
5750   struct TransportPlugin *lsPlugin;
5751   const char *nameTransport;
5752   const char *address;
5753   uint16_t size;
5754   struct GNUNET_SERVER_TransmitContext *tc;
5755   struct GNUNET_TIME_Absolute timeout;
5756   struct GNUNET_TIME_Relative rtimeout;
5757   int32_t numeric;
5758
5759   size = ntohs (message->size);
5760   if (size < sizeof (struct AddressLookupMessage))
5761     {
5762       GNUNET_break_op (0);
5763       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5764       return;
5765     }
5766   alum = (const struct AddressLookupMessage *) message;
5767   uint32_t addressLen = ntohl (alum->addrlen);
5768   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5769     {
5770       GNUNET_break_op (0);
5771       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5772       return;
5773     }
5774   address = (const char *) &alum[1];
5775   nameTransport = (const char *) &address[addressLen];
5776   if (nameTransport
5777       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5778     {
5779       GNUNET_break_op (0);
5780       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5781       return;
5782     }
5783   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5784   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5785   numeric = ntohl (alum->numeric_only);
5786   lsPlugin = find_transport (nameTransport);
5787   if (NULL == lsPlugin)
5788     {
5789       tc = GNUNET_SERVER_transmit_context_create (client);
5790       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5791                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5792       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5793       return;
5794     }
5795   GNUNET_SERVER_disable_receive_done_warning (client);
5796   tc = GNUNET_SERVER_transmit_context_create (client);
5797   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5798                                          nameTransport,
5799                                          address, addressLen,
5800                                          numeric,
5801                                          rtimeout,
5802                                          &transmit_address_to_client, tc);
5803 }
5804
5805
5806 /**
5807  * Setup the environment for this plugin.
5808  */
5809 static void
5810 create_environment (struct TransportPlugin *plug)
5811 {
5812   plug->env.cfg = cfg;
5813   plug->env.my_identity = &my_identity;
5814   plug->env.our_hello = &our_hello;
5815   plug->env.cls = plug;
5816   plug->env.receive = &plugin_env_receive;
5817   plug->env.notify_address = &plugin_env_notify_address;
5818   plug->env.session_end = &plugin_env_session_end;
5819   plug->env.max_connections = max_connect_per_transport;
5820   plug->env.stats = stats;
5821 }
5822
5823
5824 /**
5825  * Start the specified transport (load the plugin).
5826  */
5827 static void
5828 start_transport (struct GNUNET_SERVER_Handle *server,
5829                  const char *name)
5830 {
5831   struct TransportPlugin *plug;
5832   char *libname;
5833
5834   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5835               _("Loading `%s' transport plugin\n"), name);
5836   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5837   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5838   create_environment (plug);
5839   plug->short_name = GNUNET_strdup (name);
5840   plug->lib_name = libname;
5841   plug->next = plugins;
5842   plugins = plug;
5843   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5844   if (plug->api == NULL)
5845     {
5846       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5847                   _("Failed to load transport plugin for `%s'\n"), name);
5848       GNUNET_free (plug->short_name);
5849       plugins = plug->next;
5850       GNUNET_free (libname);
5851       GNUNET_free (plug);
5852     }
5853 }
5854
5855
5856 /**
5857  * Called whenever a client is disconnected.  Frees our
5858  * resources associated with that client.
5859  *
5860  * @param cls closure
5861  * @param client identification of the client
5862  */
5863 static void
5864 client_disconnect_notification (void *cls,
5865                                 struct GNUNET_SERVER_Client *client)
5866 {
5867   struct TransportClient *pos;
5868   struct TransportClient *prev;
5869   struct ClientMessageQueueEntry *mqe;
5870   struct Blacklisters *bl;
5871   struct BlacklistCheck *bc;
5872
5873   if (client == NULL)
5874     return;
5875 #if DEBUG_TRANSPORT
5876   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5877               "Client disconnected, cleaning up.\n");
5878 #endif
5879   /* clean up blacklister */
5880   bl = bl_head;
5881   while (bl != NULL)
5882     {
5883       if (bl->client == client)
5884         {
5885           bc = bc_head;
5886           while (bc != NULL)
5887             {
5888               if (bc->bl_pos == bl)
5889                 {
5890                   bc->bl_pos = bl->next;
5891                   if (bc->th != NULL)
5892                     {
5893                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5894                       bc->th = NULL;
5895                     }
5896                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5897                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5898                                                          bc);
5899                   break;
5900                 }
5901               bc = bc->next;
5902             }
5903           GNUNET_CONTAINER_DLL_remove (bl_head,
5904                                        bl_tail,
5905                                        bl);
5906           GNUNET_SERVER_client_drop (bl->client);
5907           GNUNET_free (bl);
5908           break;
5909         }
5910       bl = bl->next;
5911     }
5912   /* clean up 'normal' clients */
5913   prev = NULL;
5914   pos = clients;
5915   while ((pos != NULL) && (pos->client != client))
5916     {
5917       prev = pos;
5918       pos = pos->next;
5919     }
5920   if (pos == NULL)
5921     return;
5922   while (NULL != (mqe = pos->message_queue_head))
5923     {
5924       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5925                                    pos->message_queue_tail,
5926                                    mqe);
5927       pos->message_count--;
5928       GNUNET_free (mqe);
5929     }
5930   if (prev == NULL)
5931     clients = pos->next;
5932   else
5933     prev->next = pos->next;
5934   if (GNUNET_YES == pos->tcs_pending)
5935     {
5936       pos->client = NULL;
5937       return;
5938     }
5939   if (pos->th != NULL)
5940     {
5941       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5942       pos->th = NULL;
5943     }
5944   GNUNET_break (0 == pos->message_count);
5945   GNUNET_free (pos);
5946 }
5947
5948
5949 /**
5950  * Function called when the service shuts down.  Unloads our plugins
5951  * and cancels pending validations.
5952  *
5953  * @param cls closure, unused
5954  * @param tc task context (unused)
5955  */
5956 static void
5957 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5958 {
5959   struct TransportPlugin *plug;
5960   struct TransportPlugin *tmp;
5961   struct OwnAddressList *al;
5962   struct CheckHelloValidatedContext *chvc;
5963
5964   shutdown_in_progress = GNUNET_YES;
5965   while (neighbours != NULL)
5966     {
5967 #if DEBUG_TRANSPORT
5968       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5969                   "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5970                   "SHUTDOWN_TASK");
5971 #endif
5972       disconnect_neighbour (neighbours, GNUNET_NO);
5973     }
5974 #if DEBUG_TRANSPORT
5975   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5976               "Transport service is unloading plugins...\n");
5977 #endif
5978   plug = plugins;
5979   while (plug != NULL)
5980     {
5981       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5982         {
5983           GNUNET_SCHEDULER_cancel (plug->address_update_task);
5984           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5985         }
5986       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5987       GNUNET_free (plug->lib_name);
5988       GNUNET_free (plug->short_name);
5989       while (NULL != (al = plug->addresses))
5990         {
5991           plug->addresses = al->next;
5992           GNUNET_free (al);
5993         }
5994       tmp = plug->next;
5995       GNUNET_free (plug);
5996       plug = tmp;
5997     }
5998   if (my_private_key != NULL)
5999     GNUNET_CRYPTO_rsa_key_free (my_private_key);
6000   GNUNET_free_non_null (our_hello);
6001
6002   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6003                                          &abort_validation,
6004                                          NULL);
6005   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6006   validation_map = NULL;
6007
6008   if (ats != NULL)
6009     ats_shutdown (ats);
6010
6011   /* free 'chvc' data structure */
6012   while (NULL != (chvc = chvc_head))
6013     {
6014       chvc_head = chvc->next;
6015       if (chvc->piter != NULL)
6016         {
6017           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6018           GNUNET_STATISTICS_update (stats,
6019                                     gettext_noop ("# outstanding peerinfo iterate requests"),
6020                                     -1,
6021                                     GNUNET_NO);
6022           chvc->ve_count --;
6023         }
6024       else
6025           GNUNET_break (0);
6026       GNUNET_assert (chvc->ve_count == 0);
6027       GNUNET_free (chvc);
6028     }
6029   chvc_tail = NULL;
6030
6031   if (stats != NULL)
6032     {
6033       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6034       stats = NULL;
6035     }
6036   if (peerinfo != NULL)
6037     {
6038       GNUNET_PEERINFO_disconnect (peerinfo);
6039       peerinfo = NULL;
6040     }
6041   if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6042     {
6043       GNUNET_SCHEDULER_cancel (hello_task);
6044       hello_task = GNUNET_SCHEDULER_NO_TASK;
6045     }
6046   /* Can we assume those are gone by now, or do we need to clean up
6047      explicitly!? */
6048   GNUNET_break (bl_head == NULL);
6049   GNUNET_break (bc_head == NULL);
6050 }
6051
6052
6053 static void
6054 schedule_ats (void *cls,
6055                           const struct GNUNET_SCHEDULER_TaskContext *tc)
6056 {
6057   struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6058   if (ats==NULL)
6059     return;
6060
6061   ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6062   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6063       return;
6064   if (shutdown_in_progress == GNUNET_YES)
6065           return;
6066 #if DEBUG_ATS
6067         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6068 #endif
6069   ats_calculate_bandwidth_distribution (ats, stats, neighbours);
6070   ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_interval,
6071                                   &schedule_ats, ats);
6072 }
6073
6074 struct ForeignAddressList * get_preferred_ats_address (
6075                 struct NeighbourList *n)
6076 {
6077   // TODO get ATS prefered address
6078   return find_ready_address(n);
6079 }
6080
6081 /**
6082  * Initiate transport service.
6083  *
6084  * @param cls closure
6085  * @param server the initialized server
6086  * @param c configuration to use
6087  */
6088 static void
6089 run (void *cls,
6090      struct GNUNET_SERVER_Handle *server,
6091      const struct GNUNET_CONFIGURATION_Handle *c)
6092 {
6093   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6094     {&handle_start, NULL,
6095      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6096     {&handle_hello, NULL,
6097      GNUNET_MESSAGE_TYPE_HELLO, 0},
6098     {&handle_send, NULL,
6099      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6100     {&handle_request_connect, NULL,
6101      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6102     {&handle_set_quota, NULL,
6103      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6104     {&handle_address_lookup, NULL,
6105      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6106      0},
6107     {&handle_blacklist_init, NULL,
6108      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6109     {&handle_blacklist_reply, NULL,
6110      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6111     {NULL, NULL, 0, 0}
6112   };
6113   char *plugs;
6114   char *pos;
6115   int no_transports;
6116   unsigned long long tneigh;
6117   char *keyfile;
6118
6119   shutdown_in_progress = GNUNET_NO;
6120   cfg = c;
6121   stats = GNUNET_STATISTICS_create ("transport", cfg);
6122   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6123   /* parse configuration */
6124   if ((GNUNET_OK !=
6125        GNUNET_CONFIGURATION_get_value_number (c,
6126                                               "TRANSPORT",
6127                                               "NEIGHBOUR_LIMIT",
6128                                               &tneigh)) ||
6129       (GNUNET_OK !=
6130        GNUNET_CONFIGURATION_get_value_filename (c,
6131                                                 "GNUNETD",
6132                                                 "HOSTKEY", &keyfile)))
6133     {
6134       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6135                   _
6136                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
6137       GNUNET_SCHEDULER_shutdown ();
6138       if (stats != NULL)
6139         {
6140           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6141           stats = NULL;
6142         }
6143       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6144       validation_map = NULL;
6145       return;
6146     }
6147
6148   max_connect_per_transport = (uint32_t) tneigh;
6149   peerinfo = GNUNET_PEERINFO_connect (cfg);
6150   if (peerinfo == NULL)
6151     {
6152       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6153                   _("Could not access PEERINFO service.  Exiting.\n"));
6154       GNUNET_SCHEDULER_shutdown ();
6155       if (stats != NULL)
6156         {
6157           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6158           stats = NULL;
6159         }
6160       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6161       validation_map = NULL;
6162       GNUNET_free (keyfile);
6163       return;
6164     }
6165   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6166   GNUNET_free (keyfile);
6167   if (my_private_key == NULL)
6168     {
6169       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6170                   _
6171                   ("Transport service could not access hostkey.  Exiting.\n"));
6172       GNUNET_SCHEDULER_shutdown ();
6173       if (stats != NULL)
6174         {
6175           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6176           stats = NULL;
6177         }
6178       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6179       validation_map = NULL;
6180       return;
6181     }
6182   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6183   GNUNET_CRYPTO_hash (&my_public_key,
6184                       sizeof (my_public_key), &my_identity.hashPubKey);
6185   /* setup notification */
6186   GNUNET_SERVER_disconnect_notify (server,
6187                                    &client_disconnect_notification, NULL);
6188   /* load plugins... */
6189   no_transports = 1;
6190   if (GNUNET_OK ==
6191       GNUNET_CONFIGURATION_get_value_string (c,
6192                                              "TRANSPORT", "PLUGINS", &plugs))
6193     {
6194       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6195                   _("Starting transport plugins `%s'\n"), plugs);
6196       pos = strtok (plugs, " ");
6197       while (pos != NULL)
6198         {
6199           start_transport (server, pos);
6200           no_transports = 0;
6201           pos = strtok (NULL, " ");
6202         }
6203       GNUNET_free (plugs);
6204     }
6205   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6206                                 &shutdown_task, NULL);
6207   if (no_transports)
6208     refresh_hello ();
6209
6210   ats = ats_init (cfg);
6211   if (ats != NULL)
6212     ats->ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6213
6214
6215 #if DEBUG_TRANSPORT
6216   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
6217               _("Transport service ready.\n"));
6218 #endif
6219   /* If we have a blacklist file, read from it */
6220   read_blacklist_file(cfg);
6221   /* process client requests */
6222   GNUNET_SERVER_add_handlers (server, handlers);
6223 }
6224
6225
6226 /**
6227  * The main function for the transport service.
6228  *
6229  * @param argc number of arguments from the command line
6230  * @param argv command line arguments
6231  * @return 0 ok, 1 on error
6232  */
6233 int
6234 main (int argc, char *const *argv)
6235 {
6236   a2s (NULL, NULL, 0); /* make compiler happy */
6237   return (GNUNET_OK ==
6238           GNUNET_SERVICE_run (argc,
6239                               argv,
6240                               "transport",
6241                               GNUNET_SERVICE_OPTION_NONE,
6242                               &run, NULL)) ? 0 : 1;
6243 }
6244
6245 /* end of gnunet-service-transport.c */