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