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