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