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