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