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