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