check if this pos was connected before...
[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 specific 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   GNUNET_STATISTICS_update (stats,
2508                             gettext_noop ("# disconnects due to try_fast_reconnect"),
2509                             1,
2510                             GNUNET_NO);
2511 #if DISCONNECT
2512   disconnect_neighbour (nl, GNUNET_YES);
2513 #endif
2514 }
2515
2516
2517 /**
2518  * Function that will be called whenever the plugin internally
2519  * cleans up a session pointer and hence the service needs to
2520  * discard all of those sessions as well.  Plugins that do not
2521  * use sessions can simply omit calling this function and always
2522  * use NULL wherever a session pointer is needed.
2523  *
2524  * @param cls closure
2525  * @param peer which peer was the session for
2526  * @param session which session is being destoyed
2527  */
2528 static void
2529 plugin_env_session_end  (void *cls,
2530                          const struct GNUNET_PeerIdentity *peer,
2531                          struct Session *session)
2532 {
2533   struct TransportPlugin *p = cls;
2534   struct NeighbourList *nl;
2535   struct ReadyList *rl;
2536   struct ForeignAddressList *pos;
2537   struct ForeignAddressList *prev;
2538
2539 #if DEBUG_TRANSPORT
2540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2541               "Session ended with peer `%4s', %s\n", 
2542               GNUNET_i2s(peer),
2543               "plugin_env_session_end");
2544 #endif
2545   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2546                                          &remove_session_validations,
2547                                          session);
2548   nl = find_neighbour (peer);
2549   if (nl == NULL)
2550     {
2551 #if DEBUG_TRANSPORT
2552       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2553                   "No neighbour record found for peer `%4s'\n", 
2554                   GNUNET_i2s(peer));
2555 #endif
2556       return; /* was never marked as connected */
2557     }
2558   rl = nl->plugins;
2559   while (rl != NULL)
2560     {
2561       if (rl->plugin == p)
2562         break;
2563       rl = rl->next;
2564     }
2565   if (rl == NULL)
2566     {
2567 #if DEBUG_TRANSPORT
2568       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2569                   "Plugin was associated with peer `%4s'\n", 
2570                   GNUNET_i2s(peer));
2571 #endif
2572       GNUNET_STATISTICS_update (stats,
2573                                 gettext_noop ("# disconnects due to session end"),
2574                                 1,
2575                                 GNUNET_NO);
2576       disconnect_neighbour (nl, GNUNET_YES);
2577       return;
2578     }
2579   prev = NULL;
2580   pos = rl->addresses;
2581   while ( (pos != NULL) &&
2582           (pos->session != session) )
2583     {
2584       prev = pos;
2585       pos = pos->next;
2586     }
2587   if (pos == NULL)
2588     {
2589 #if DEBUG_TRANSPORT
2590       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2591                   "Session was never marked as ready for peer `%4s'\n", 
2592                   GNUNET_i2s(peer));
2593 #endif
2594       //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2595       GNUNET_STATISTICS_update (stats,
2596                                 gettext_noop ("# disconnects due to unready session"),
2597                                 1,
2598                                 GNUNET_NO);
2599       disconnect_neighbour (nl, GNUNET_YES);
2600       return; /* was never marked as connected */
2601     }
2602   pos->session = NULL;
2603   if (pos->addrlen != 0)
2604     {
2605       if (nl->received_pong != GNUNET_NO)
2606         {
2607           GNUNET_STATISTICS_update (stats,
2608                                     gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2609                                     1,
2610                                     GNUNET_NO);
2611           if (GNUNET_YES == pos->connected)
2612             try_fast_reconnect (p, nl);
2613         }
2614       else
2615         {
2616           GNUNET_STATISTICS_update (stats,
2617                                     gettext_noop ("# disconnects due to missing pong"),
2618                                     1,
2619                                     GNUNET_NO);
2620           if (GNUNET_YES == pos->connected)
2621             disconnect_neighbour (nl, GNUNET_YES);
2622         }
2623       return;
2624     }
2625   /* was inbound connection, free 'pos' */
2626   if (prev == NULL)
2627     rl->addresses = pos->next;
2628   else
2629     prev->next = pos->next;
2630   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2631     {
2632       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2633       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2634     }
2635   GNUNET_free_non_null(pos->ressources);
2636   GNUNET_free_non_null(pos->quality);
2637   if (GNUNET_YES != pos->connected)
2638     {
2639       /* nothing else to do, connection was never up... */
2640       GNUNET_free (pos);
2641       return; 
2642     }
2643   GNUNET_free (pos);
2644   ats->stat.recreate_problem = GNUNET_YES;
2645   if (nl->received_pong == GNUNET_NO)
2646     {
2647       GNUNET_STATISTICS_update (stats,
2648                                 gettext_noop ("# disconnects due to NO pong"),
2649                                 1,
2650                                 GNUNET_NO);
2651       disconnect_neighbour (nl, GNUNET_YES);
2652       return; /* nothing to do, never connected... */
2653     }
2654   /* check if we have any validated addresses left */
2655   pos = rl->addresses;
2656   while (pos != NULL)
2657     {
2658       if (GNUNET_YES == pos->validated)
2659         {
2660           GNUNET_STATISTICS_update (stats,
2661                                     gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2662                                     1,
2663                                     GNUNET_NO);
2664           try_fast_reconnect (p, nl);
2665           return;
2666         }
2667       pos = pos->next;
2668     }
2669   /* no valid addresses left, signal disconnect! */
2670
2671 #if DEBUG_TRANSPORT
2672   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2673               "Disconnecting peer `%4s', %s\n", 
2674               GNUNET_i2s(peer),
2675               "plugin_env_session_end");
2676 #endif
2677   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2678    * it means there aren't any left for this PLUGIN/PEER combination! So
2679    * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2680    * when it isn't necessary. Using GNUNET_YES at least checks to see
2681    * if there are any addresses that work first, so as not to overdo it.
2682    * --NE
2683    */
2684   GNUNET_STATISTICS_update (stats,
2685                             gettext_noop ("# disconnects due to plugin_env_session_end"),
2686                             1,
2687                             GNUNET_NO);
2688   disconnect_neighbour (nl, GNUNET_YES);
2689 }
2690
2691
2692 /**
2693  * Function that must be called by each plugin to notify the
2694  * transport service about the addresses under which the transport
2695  * provided by the plugin can be reached.
2696  *
2697  * @param cls closure
2698  * @param name name of the transport that generated the address
2699  * @param addr one of the addresses of the host, NULL for the last address
2700  *        the specific address format depends on the transport
2701  * @param addrlen length of the address
2702  * @param expires when should this address automatically expire?
2703  */
2704 static void
2705 plugin_env_notify_address (void *cls,
2706                            const char *name,
2707                            const void *addr,
2708                            uint16_t addrlen,
2709                            struct GNUNET_TIME_Relative expires)
2710 {
2711   struct TransportPlugin *p = cls;
2712   struct OwnAddressList *al;
2713   struct GNUNET_TIME_Absolute abex;
2714
2715   GNUNET_assert (addr != NULL);
2716   abex = GNUNET_TIME_relative_to_absolute (expires);
2717   GNUNET_assert (p == find_transport (name));
2718   al = p->addresses;
2719   while (al != NULL)
2720     {
2721       if ( (addrlen == al->addrlen) &&
2722            (0 == memcmp (addr, &al[1], addrlen)) )
2723         {
2724           al->expires = abex;
2725           update_addresses (p, GNUNET_NO);
2726           return;
2727         }
2728       al = al->next;
2729     }
2730   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2731   al->next = p->addresses;
2732   p->addresses = al;
2733   al->expires = abex;
2734   al->addrlen = addrlen;
2735   memcpy (&al[1], addr, addrlen);
2736   update_addresses (p, GNUNET_YES);
2737 }
2738
2739
2740 /**
2741  * Notify all of our clients about a peer connecting.
2742  */
2743 static void
2744 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2745                         struct GNUNET_TIME_Relative latency,
2746                         uint32_t distance)
2747 {
2748   struct ConnectInfoMessage * cim;
2749   struct TransportClient *cpos;
2750   uint32_t ats_count;
2751   size_t size;
2752
2753   if (0 == memcmp (peer,
2754                    &my_identity,
2755                    sizeof (struct GNUNET_PeerIdentity)))
2756     {
2757       GNUNET_break (0);
2758       return;
2759     }
2760 #if DEBUG_TRANSPORT
2761   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2762               "Notifying clients about connection from `%s'\n",
2763               GNUNET_i2s (peer));
2764 #endif
2765   GNUNET_STATISTICS_update (stats,
2766                             gettext_noop ("# peers connected"),
2767                             1,
2768                             GNUNET_NO);
2769
2770   ats_count = 2;
2771   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2772   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2773     {
2774       GNUNET_break(0);
2775     }
2776   cim = GNUNET_malloc (size);
2777   cim->header.size = htons (size);
2778   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2779   cim->ats_count = htonl(2);
2780   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2781   (&(cim->ats))[0].value = htonl (distance);
2782   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2783   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2784   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2785   (&(cim->ats))[2].value = htonl (0);
2786   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2787
2788   /* notify ats about connecting peer */
2789   if (shutdown_in_progress == GNUNET_NO)
2790         ats_notify_peer_connect (peer, &(cim->ats), 2);
2791
2792   cpos = clients;
2793   while (cpos != NULL)
2794     {
2795       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2796       cpos = cpos->next;
2797     }
2798
2799   GNUNET_free (cim);
2800 }
2801
2802
2803 /**
2804  * Notify all of our clients about a peer disconnecting.
2805  */
2806 static void
2807 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2808 {
2809   struct DisconnectInfoMessage dim;
2810   struct TransportClient *cpos;
2811
2812   if (0 == memcmp (peer,
2813                    &my_identity,
2814                    sizeof (struct GNUNET_PeerIdentity)))
2815     {
2816       GNUNET_break (0);
2817       return;
2818     }
2819 #if DEBUG_TRANSPORT
2820   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2821               "Notifying clients about lost connection to `%s'\n",
2822               GNUNET_i2s (peer));
2823 #endif
2824   GNUNET_STATISTICS_update (stats,
2825                             gettext_noop ("# peers connected"),
2826                             -1,
2827                             GNUNET_NO);
2828   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2829   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2830   dim.reserved = htonl (0);
2831   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2832
2833   /* notify ats about connecting peer */
2834   if (shutdown_in_progress == GNUNET_NO)
2835           ats_notify_peer_disconnect (peer);
2836
2837   cpos = clients;
2838   while (cpos != NULL)
2839     {
2840       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2841       cpos = cpos->next;
2842     }
2843 }
2844
2845
2846 /**
2847  * Find a ForeignAddressList entry for the given neighbour
2848  * that matches the given address and transport.
2849  *
2850  * @param neighbour which peer we care about
2851  * @param tname name of the transport plugin
2852  * @param session session to look for, NULL for 'any'; otherwise
2853  *        can be used for the service to "learn" this session ID
2854  *        if 'addr' matches
2855  * @param addr binary address
2856  * @param addrlen length of addr
2857  * @return NULL if no such entry exists
2858  */
2859 static struct ForeignAddressList *
2860 find_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 *pos;
2868
2869   head = neighbour->plugins;
2870   while (head != NULL)
2871     {
2872       if (0 == strcmp (tname, head->plugin->short_name))
2873         break;
2874       head = head->next;
2875     }
2876   if (head == NULL)
2877     return NULL;
2878   pos = head->addresses;
2879   while ( (pos != NULL) &&
2880           ( (pos->addrlen != addrlen) ||
2881             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2882     {
2883       if ( (session != NULL) &&
2884            (pos->session == session) )
2885         return pos;
2886       pos = pos->next;
2887     }
2888   if ( (session != NULL) && (pos != NULL) )
2889     pos->session = session; /* learn it! */
2890   return pos;
2891 }
2892
2893
2894 /**
2895  * Get the peer address struct for the given neighbour and
2896  * address.  If it doesn't yet exist, create it.
2897  *
2898  * @param neighbour which peer we care about
2899  * @param tname name of the transport plugin
2900  * @param session session of the plugin, or NULL for none
2901  * @param addr binary address
2902  * @param addrlen length of addr
2903  * @return NULL if we do not have a transport plugin for 'tname'
2904  */
2905 static struct ForeignAddressList *
2906 add_peer_address (struct NeighbourList *neighbour,
2907                   const char *tname,
2908                   struct Session *session,
2909                   const char *addr,
2910                   uint16_t addrlen)
2911 {
2912   struct ReadyList *head;
2913   struct ForeignAddressList *ret;
2914   int c;
2915
2916   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2917   if (ret != NULL)
2918     return ret;
2919   head = neighbour->plugins;
2920
2921   while (head != NULL)
2922     {
2923       if (0 == strcmp (tname, head->plugin->short_name))
2924         break;
2925       head = head->next;
2926     }
2927   if (head == NULL)
2928     return NULL;
2929   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2930   ret->session = session;
2931   if ((addrlen > 0) && (addr != NULL))
2932     {
2933       ret->addr = (const char*) &ret[1];
2934       memcpy (&ret[1], addr, addrlen);
2935     }
2936   else
2937     {
2938       ret->addr = NULL;
2939     }
2940
2941   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2942   for (c=0; c<available_ressources; c++)
2943     {
2944       struct ATS_ressource_entry *r = ret->ressources;
2945       r[c].index = c;
2946       r[c].atis_index = ressources[c].atis_index;
2947       if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2948         {
2949           r[c].c = ressources[c].c_unix;
2950         }
2951       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2952         {
2953           r[c].c = ressources[c].c_udp;
2954         }
2955       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2956         {
2957           r[c].c = ressources[c].c_tcp;
2958         }
2959       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2960         {
2961           r[c].c = ressources[c].c_http;
2962         }
2963       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2964         {
2965           r[c].c = ressources[c].c_https;
2966         }
2967       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2968         {
2969           r[c].c = ressources[c].c_wlan;
2970         }
2971       else
2972         {
2973           r[c].c = ressources[c].c_default;
2974           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2975                       "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2976                       GNUNET_i2s(&neighbour->peer), 
2977                       neighbour->plugins->plugin->short_name);
2978         }
2979     }
2980
2981   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2982   ret->addrlen = addrlen;
2983   ret->expires = GNUNET_TIME_relative_to_absolute
2984     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2985   ret->latency = GNUNET_TIME_relative_get_forever();
2986   ret->distance = -1;
2987   ret->timeout = GNUNET_TIME_relative_to_absolute
2988     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2989   ret->ready_list = head;
2990   ret->next = head->addresses;
2991   head->addresses = ret;
2992   return ret;
2993 }
2994
2995
2996 /**
2997  * Closure for 'add_validated_address'.
2998  */
2999 struct AddValidatedAddressContext
3000 {
3001   /**
3002    * Entry that has been validated.
3003    */
3004   const struct ValidationEntry *ve;
3005
3006   /**
3007    * Flag set after we have added the address so
3008    * that we terminate the iteration next time.
3009    */
3010   int done;
3011 };
3012
3013
3014 /**
3015  * Callback function used to fill a buffer of max bytes with a list of
3016  * addresses in the format used by HELLOs.  Should use
3017  * "GNUNET_HELLO_add_address" as a helper function.
3018  *
3019  * @param cls the 'struct AddValidatedAddressContext' with the validated address
3020  * @param max maximum number of bytes that can be written to buf
3021  * @param buf where to write the address information
3022  * @return number of bytes written, 0 to signal the
3023  *         end of the iteration.
3024  */
3025 static size_t
3026 add_validated_address (void *cls,
3027                        size_t max, void *buf)
3028 {
3029   struct AddValidatedAddressContext *avac = cls;
3030   const struct ValidationEntry *ve = avac->ve;
3031
3032   if (GNUNET_YES == avac->done)
3033     return 0;
3034   avac->done = GNUNET_YES;
3035   return GNUNET_HELLO_add_address (ve->transport_name,
3036                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
3037                                    ve->addr,
3038                                    ve->addrlen,
3039                                    buf,
3040                                    max);
3041 }
3042
3043
3044
3045 /**
3046  * Closure for 'check_address_exists'.
3047  */
3048 struct CheckAddressExistsClosure
3049 {
3050   /**
3051    * Address to check for.
3052    */
3053   const void *addr;
3054
3055   /**
3056    * Name of the transport.
3057    */
3058   const char *tname;
3059
3060   /**
3061    * Session, or NULL.
3062    */
3063   struct Session *session;
3064
3065   /**
3066    * Set to GNUNET_YES if the address exists.
3067    */
3068   int exists;
3069
3070   /**
3071    * Length of addr.
3072    */
3073   uint16_t addrlen;
3074
3075 };
3076
3077
3078 /**
3079  * Iterator over hash map entries.  Checks if the given
3080  * validation entry is for the same address as what is given
3081  * in the closure.
3082  *
3083  * @param cls the 'struct CheckAddressExistsClosure*'
3084  * @param key current key code (ignored)
3085  * @param value value in the hash map ('struct ValidationEntry')
3086  * @return GNUNET_YES if we should continue to
3087  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3088  */
3089 static int
3090 check_address_exists (void *cls,
3091                       const GNUNET_HashCode * key,
3092                       void *value)
3093 {
3094   struct CheckAddressExistsClosure *caec = cls;
3095   struct ValidationEntry *ve = value;
3096
3097   if ( (0 == strcmp (caec->tname,
3098                      ve->transport_name)) &&
3099        (caec->addrlen == ve->addrlen) &&
3100        (0 == memcmp (caec->addr,
3101                      ve->addr,
3102                      caec->addrlen)) )
3103     {
3104       caec->exists = GNUNET_YES;
3105       return GNUNET_NO;
3106     }
3107   if ( (ve->session != NULL) &&
3108        (caec->session == ve->session) )
3109     {
3110       caec->exists = GNUNET_YES;
3111       return GNUNET_NO;
3112     }
3113   return GNUNET_YES;
3114 }
3115
3116
3117
3118 /**
3119  * Iterator to free entries in the validation_map.
3120  *
3121  * @param cls closure (unused)
3122  * @param key current key code
3123  * @param value value in the hash map (validation to abort)
3124  * @return GNUNET_YES (always)
3125  */
3126 static int
3127 abort_validation (void *cls,
3128                   const GNUNET_HashCode * key,
3129                   void *value)
3130 {
3131   struct ValidationEntry *va = value;
3132
3133   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
3134     GNUNET_SCHEDULER_cancel (va->timeout_task);
3135   GNUNET_free (va->transport_name);
3136   if (va->chvc != NULL)
3137     {
3138       va->chvc->ve_count--;
3139       if (va->chvc->ve_count == 0)
3140         {
3141           GNUNET_CONTAINER_DLL_remove (chvc_head,
3142                                        chvc_tail,
3143                                        va->chvc);
3144           GNUNET_free (va->chvc);
3145         }
3146       va->chvc = NULL;
3147     }
3148   GNUNET_free (va);
3149   return GNUNET_YES;
3150 }
3151
3152
3153 /**
3154  * HELLO validation cleanup task (validation failed).
3155  *
3156  * @param cls the 'struct ValidationEntry' that failed
3157  * @param tc scheduler context (unused)
3158  */
3159 static void
3160 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3161 {
3162   struct ValidationEntry *va = cls;
3163   struct GNUNET_PeerIdentity pid;
3164
3165   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3166   GNUNET_STATISTICS_update (stats,
3167                             gettext_noop ("# address validation timeouts"),
3168                             1,
3169                             GNUNET_NO);
3170   GNUNET_CRYPTO_hash (&va->publicKey,
3171                       sizeof (struct
3172                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3173                       &pid.hashPubKey);
3174   GNUNET_break (GNUNET_OK ==
3175                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3176                                                       &pid.hashPubKey,
3177                                                       va));
3178   abort_validation (NULL, NULL, va);
3179 }
3180
3181
3182 static void
3183 neighbour_timeout_task (void *cls,
3184                        const struct GNUNET_SCHEDULER_TaskContext *tc)
3185 {
3186   struct NeighbourList *n = cls;
3187
3188 #if DEBUG_TRANSPORT
3189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3190               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3191 #endif
3192   GNUNET_STATISTICS_update (stats,
3193                             gettext_noop ("# disconnects due to timeout"),
3194                             1,
3195                             GNUNET_NO);
3196   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3197   disconnect_neighbour (n, GNUNET_NO);
3198 }
3199
3200
3201 /**
3202  * Schedule the job that will cause us to send a PING to the
3203  * foreign address to evaluate its validity and latency.
3204  *
3205  * @param fal address to PING
3206  */
3207 static void
3208 schedule_next_ping (struct ForeignAddressList *fal);
3209
3210
3211 /**
3212  * Add the given address to the list of foreign addresses
3213  * available for the given peer (check for duplicates).
3214  *
3215  * @param cls the respective 'struct NeighbourList' to update
3216  * @param tname name of the transport
3217  * @param expiration expiration time
3218  * @param addr the address
3219  * @param addrlen length of the address
3220  * @return GNUNET_OK (always)
3221  */
3222 static int
3223 add_to_foreign_address_list (void *cls,
3224                              const char *tname,
3225                              struct GNUNET_TIME_Absolute expiration,
3226                              const void *addr,
3227                              uint16_t addrlen)
3228 {
3229   struct NeighbourList *n = cls;
3230   struct ForeignAddressList *fal;
3231   int try;
3232
3233   GNUNET_STATISTICS_update (stats,
3234                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
3235                             1,
3236                             GNUNET_NO);
3237   try = GNUNET_NO;
3238   fal = find_peer_address (n, tname, NULL, addr, addrlen);
3239   if (fal == NULL)
3240     {
3241 #if DEBUG_TRANSPORT_HELLO
3242       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3243                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3244                   a2s (tname, addr, addrlen),
3245                   tname,
3246                   GNUNET_i2s (&n->id),
3247                   expiration.abs_value);
3248 #endif
3249       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3250       if (fal == NULL)
3251         {
3252           GNUNET_STATISTICS_update (stats,
3253                                     gettext_noop ("# previously validated addresses lacking transport"),
3254                                     1,
3255                                     GNUNET_NO);
3256         }
3257       else
3258         {
3259           fal->expires = GNUNET_TIME_absolute_max (expiration,
3260                                                    fal->expires);
3261           schedule_next_ping (fal);
3262         }
3263       try = GNUNET_YES;
3264     }
3265   else
3266     {
3267       fal->expires = GNUNET_TIME_absolute_max (expiration,
3268                                                fal->expires);
3269     }
3270   if (fal == NULL)
3271     {
3272 #if DEBUG_TRANSPORT
3273       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3274                   "Failed to add new address for `%4s'\n",
3275                   GNUNET_i2s (&n->id));
3276 #endif
3277       return GNUNET_OK;
3278     }
3279   if (fal->validated == GNUNET_NO)
3280     {
3281       fal->validated = GNUNET_YES;
3282       GNUNET_STATISTICS_update (stats,
3283                                 gettext_noop ("# peer addresses considered valid"),
3284                                 1,
3285                                 GNUNET_NO);
3286     }
3287   if (try == GNUNET_YES)
3288     {
3289 #if DEBUG_TRANSPORT
3290       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3291                   "Have new addresses, will try to trigger transmissions.\n");
3292 #endif
3293       try_transmission_to_peer (n);
3294     }
3295   return GNUNET_OK;
3296 }
3297
3298
3299 /**
3300  * Add addresses in validated HELLO "h" to the set of addresses
3301  * we have for this peer.
3302  *
3303  * @param cls closure ('struct NeighbourList*')
3304  * @param peer id of the peer, NULL for last call
3305  * @param h hello message for the peer (can be NULL)
3306  * @param err_msg NULL if successful, otherwise contains error message
3307  */
3308 static void
3309 add_hello_for_peer (void *cls,
3310                     const struct GNUNET_PeerIdentity *peer,
3311                     const struct GNUNET_HELLO_Message *h,
3312                     const char *err_msg)
3313 {
3314   struct NeighbourList *n = cls;
3315
3316   if (err_msg != NULL)
3317     {
3318 #if DEBUG_TRANSPORT
3319       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3320                   _("Error in communication with PEERINFO service: %s\n"),
3321                   err_msg);
3322 #endif
3323       /* return; */
3324     }
3325   if (peer == NULL)
3326     {
3327       GNUNET_STATISTICS_update (stats,
3328                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3329                                 -1,
3330                                 GNUNET_NO);
3331       n->piter = NULL;
3332       return;
3333     }
3334   if (h == NULL)
3335     return; /* no HELLO available */
3336 #if DEBUG_TRANSPORT
3337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3338               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3339               "HELLO",
3340               GNUNET_i2s (peer));
3341 #endif
3342   if (GNUNET_YES != n->public_key_valid)
3343     {
3344       GNUNET_HELLO_get_key (h, &n->publicKey);
3345       n->public_key_valid = GNUNET_YES;
3346     }
3347   GNUNET_HELLO_iterate_addresses (h,
3348                                   GNUNET_NO,
3349                                   &add_to_foreign_address_list,
3350                                   n);
3351 }
3352
3353
3354 /**
3355  * Create a fresh entry in our neighbour list for the given peer.
3356  * Will try to transmit our current HELLO to the new neighbour.
3357  * Do not call this function directly, use 'setup_peer_check_blacklist.
3358  *
3359  * @param peer the peer for which we create the entry
3360  * @param do_hello should we schedule transmitting a HELLO
3361  * @return the new neighbour list entry
3362  */
3363 static struct NeighbourList *
3364 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3365                      int do_hello)
3366 {
3367   struct NeighbourList *n;
3368   struct TransportPlugin *tp;
3369   struct ReadyList *rl;
3370
3371   GNUNET_assert (0 != memcmp (peer,
3372                               &my_identity,
3373                               sizeof (struct GNUNET_PeerIdentity)));
3374 #if DEBUG_TRANSPORT
3375   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3376               "Setting up state for neighbour `%4s'\n",
3377               GNUNET_i2s (peer));
3378 #endif
3379   GNUNET_STATISTICS_update (stats,
3380                             gettext_noop ("# active neighbours"),
3381                             1,
3382                             GNUNET_NO);
3383   n = GNUNET_malloc (sizeof (struct NeighbourList));
3384   n->next = neighbours;
3385   neighbours = n;
3386   n->id = *peer;
3387   n->peer_timeout =
3388     GNUNET_TIME_relative_to_absolute
3389     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3390   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3391                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3392                                  MAX_BANDWIDTH_CARRY_S);
3393   tp = plugins;
3394   while (tp != NULL)
3395     {
3396       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3397         {
3398           rl = GNUNET_malloc (sizeof (struct ReadyList));
3399           rl->neighbour = n;
3400           rl->next = n->plugins;
3401           n->plugins = rl;
3402           rl->plugin = tp;
3403           rl->addresses = NULL;
3404         }
3405       tp = tp->next;
3406     }
3407   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3408   n->distance = -1;
3409   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3410                                                   &neighbour_timeout_task, n);
3411   if (do_hello)
3412     {
3413       GNUNET_STATISTICS_update (stats,
3414                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3415                                 1,
3416                                 GNUNET_NO);
3417       GNUNET_STATISTICS_update (stats,
3418                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3419                                 1,
3420                                 GNUNET_NO);
3421       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3422                                           GNUNET_TIME_UNIT_FOREVER_REL,
3423                                           &add_hello_for_peer, n);
3424
3425       GNUNET_STATISTICS_update (stats,
3426                                 gettext_noop ("# HELLO's sent to new neighbors"),
3427                                 1,
3428                                 GNUNET_NO);
3429       if (NULL != our_hello)
3430         transmit_to_peer (NULL, NULL, 0,
3431                           HELLO_ADDRESS_EXPIRATION,
3432                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3433                           GNUNET_NO, n);
3434     }
3435   return n;
3436 }
3437
3438
3439 /**
3440  * Function called after we have checked if communicating
3441  * with a given peer is acceptable.
3442  *
3443  * @param cls closure
3444  * @param n NULL if communication is not acceptable
3445  */
3446 typedef void (*SetupContinuation)(void *cls,
3447                                   struct NeighbourList *n);
3448
3449
3450 /**
3451  * Information kept for each client registered to perform
3452  * blacklisting.
3453  */
3454 struct Blacklisters
3455 {
3456   /**
3457    * This is a linked list.
3458    */
3459   struct Blacklisters *next;
3460
3461   /**
3462    * This is a linked list.
3463    */
3464   struct Blacklisters *prev;
3465
3466   /**
3467    * Client responsible for this entry.
3468    */
3469   struct GNUNET_SERVER_Client *client;
3470
3471   /**
3472    * Blacklist check that we're currently performing.
3473    */
3474   struct BlacklistCheck *bc;
3475
3476 };
3477
3478
3479 /**
3480  * Head of DLL of blacklisting clients.
3481  */
3482 static struct Blacklisters *bl_head;
3483
3484 /**
3485  * Tail of DLL of blacklisting clients.
3486  */
3487 static struct Blacklisters *bl_tail;
3488
3489
3490 /**
3491  * Context we use when performing a blacklist check.
3492  */
3493 struct BlacklistCheck
3494 {
3495
3496   /**
3497    * This is a linked list.
3498    */
3499   struct BlacklistCheck *next;
3500
3501   /**
3502    * This is a linked list.
3503    */
3504   struct BlacklistCheck *prev;
3505
3506   /**
3507    * Peer being checked.
3508    */
3509   struct GNUNET_PeerIdentity peer;
3510
3511   /**
3512    * Option for setup neighbour afterwards.
3513    */
3514   int do_hello;
3515
3516   /**
3517    * Continuation to call with the result.
3518    */
3519   SetupContinuation cont;
3520
3521   /**
3522    * Closure for cont.
3523    */
3524   void *cont_cls;
3525
3526   /**
3527    * Current transmission request handle for this client, or NULL if no
3528    * request is pending.
3529    */
3530   struct GNUNET_CONNECTION_TransmitHandle *th;
3531
3532   /**
3533    * Our current position in the blacklisters list.
3534    */
3535   struct Blacklisters *bl_pos;
3536
3537   /**
3538    * Current task performing the check.
3539    */
3540   GNUNET_SCHEDULER_TaskIdentifier task;
3541
3542 };
3543
3544 /**
3545  * Head of DLL of active blacklisting queries.
3546  */
3547 static struct BlacklistCheck *bc_head;
3548
3549 /**
3550  * Tail of DLL of active blacklisting queries.
3551  */
3552 static struct BlacklistCheck *bc_tail;
3553
3554
3555 /**
3556  * Perform next action in the blacklist check.
3557  *
3558  * @param cls the 'struct BlacklistCheck*'
3559  * @param tc unused
3560  */
3561 static void
3562 do_blacklist_check (void *cls,
3563                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3564
3565 /**
3566  * Transmit blacklist query to the client.
3567  *
3568  * @param cls the 'struct BlacklistCheck'
3569  * @param size number of bytes allowed
3570  * @param buf where to copy the message
3571  * @return number of bytes copied to buf
3572  */
3573 static size_t
3574 transmit_blacklist_message (void *cls,
3575                             size_t size,
3576                             void *buf)
3577 {
3578   struct BlacklistCheck *bc = cls;
3579   struct Blacklisters *bl;
3580   struct BlacklistMessage bm;
3581
3582   bc->th = NULL;
3583   if (size == 0)
3584     {
3585       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3586       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3587                                            bc);
3588       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3589                   "Failed to send blacklist test for peer `%s' to client\n",
3590                   GNUNET_i2s (&bc->peer));
3591       return 0;
3592     }
3593 #if DEBUG_TRANSPORT
3594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3595               "Sending blacklist test for peer `%s' to client\n",
3596               GNUNET_i2s (&bc->peer));
3597 #endif
3598   bl = bc->bl_pos;
3599   bm.header.size = htons (sizeof (struct BlacklistMessage));
3600   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3601   bm.is_allowed = htonl (0);
3602   bm.peer = bc->peer;
3603   memcpy (buf, &bm, sizeof (bm));
3604   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3605   return sizeof (bm);
3606 }
3607
3608
3609 /**
3610  * Perform next action in the blacklist check.
3611  *
3612  * @param cls the 'struct BlacklistCheck*'
3613  * @param tc unused
3614  */
3615 static void
3616 do_blacklist_check (void *cls,
3617                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3618 {
3619   struct BlacklistCheck *bc = cls;
3620   struct Blacklisters *bl;
3621
3622   bc->task = GNUNET_SCHEDULER_NO_TASK;
3623   bl = bc->bl_pos;
3624   if (bl == NULL)
3625     {
3626 #if DEBUG_TRANSPORT
3627       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3628                   "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3629                   GNUNET_i2s (&bc->peer));
3630 #endif
3631       bc->cont (bc->cont_cls,
3632                 setup_new_neighbour (&bc->peer, bc->do_hello));
3633       GNUNET_free (bc);
3634       return;
3635     }
3636   if (bl->bc == NULL)
3637     {
3638       bl->bc = bc;
3639       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3640                                                     sizeof (struct BlacklistMessage),
3641                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3642                                                     &transmit_blacklist_message,
3643                                                     bc);
3644     }
3645 }
3646
3647
3648 /**
3649  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3650  * does not yet exist, check the blacklist.  If the blacklist says creating
3651  * one is acceptable, create one and call the continuation; otherwise
3652  * call the continuation with NULL.
3653  *
3654  * @param peer peer to setup or look up a struct NeighbourList for
3655  * @param do_hello should we also schedule sending our HELLO to the peer
3656  *        if this is a new record
3657  * @param cont function to call with the 'struct NeigbhbourList*'
3658  * @param cont_cls closure for cont
3659  */
3660 static void
3661 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3662                             int do_hello,
3663                             SetupContinuation cont,
3664                             void *cont_cls)
3665 {
3666   struct NeighbourList *n;
3667   struct BlacklistCheck *bc;
3668
3669   n = find_neighbour(peer);
3670   if (n != NULL)
3671     {
3672 #if DEBUG_TRANSPORT
3673       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
3674                  "Neighbour record exists for peer `%s'\n", 
3675                  GNUNET_i2s(peer));
3676 #endif
3677       if (cont != NULL)
3678         cont (cont_cls, n);
3679       return;
3680     }
3681   if (bl_head == NULL)
3682     {
3683       if (cont != NULL)
3684         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3685       else
3686         setup_new_neighbour(peer, do_hello);
3687       return;
3688     }
3689   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3690   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3691   bc->peer = *peer;
3692   bc->do_hello = do_hello;
3693   bc->cont = cont;
3694   bc->cont_cls = cont_cls;
3695   bc->bl_pos = bl_head;
3696   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3697                                        bc);
3698 }
3699
3700
3701 /**
3702  * Function called with the result of querying a new blacklister about
3703  * it being allowed (or not) to continue to talk to an existing neighbour.
3704  *
3705  * @param cls the original 'struct NeighbourList'
3706  * @param n NULL if we need to disconnect
3707  */
3708 static void
3709 confirm_or_drop_neighbour (void *cls,
3710                            struct NeighbourList *n)
3711 {
3712   struct NeighbourList * orig = cls;
3713
3714   if (n == NULL)
3715     {
3716 #if DEBUG_TRANSPORT
3717       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3718               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3719               "confirm_or_drop_neighboUr");
3720 #endif
3721       GNUNET_STATISTICS_update (stats,
3722                                 gettext_noop ("# disconnects due to blacklist"),
3723                                 1,
3724                                 GNUNET_NO);
3725       disconnect_neighbour (orig, GNUNET_NO);
3726     }
3727 }
3728
3729
3730 /**
3731  * Handle a request to start a blacklist.
3732  *
3733  * @param cls closure (always NULL)
3734  * @param client identification of the client
3735  * @param message the actual message
3736  */
3737 static void
3738 handle_blacklist_init (void *cls,
3739                        struct GNUNET_SERVER_Client *client,
3740                        const struct GNUNET_MessageHeader *message)
3741 {
3742   struct Blacklisters *bl;
3743   struct BlacklistCheck *bc;
3744   struct NeighbourList *n;
3745
3746   bl = bl_head;
3747   while (bl != NULL)
3748     {
3749       if (bl->client == client)
3750         {
3751           GNUNET_break (0);
3752           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3753           return;
3754         }
3755       bl = bl->next;
3756     }
3757   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3758   bl->client = client;
3759   GNUNET_SERVER_client_keep (client);
3760   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3761   /* confirm that all existing connections are OK! */
3762   n = neighbours;
3763   while (NULL != n)
3764     {
3765       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3766       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3767       bc->peer = n->id;
3768       bc->do_hello = GNUNET_NO;
3769       bc->cont = &confirm_or_drop_neighbour;
3770       bc->cont_cls = n;
3771       bc->bl_pos = bl;
3772       if (n == neighbours) /* all would wait for the same client, no need to
3773                               create more than just the first task right now */
3774         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3775                                              bc);
3776       n = n->next;
3777     }
3778 }
3779
3780
3781 /**
3782  * Handle a request to blacklist a peer.
3783  *
3784  * @param cls closure (always NULL)
3785  * @param client identification of the client
3786  * @param message the actual message
3787  */
3788 static void
3789 handle_blacklist_reply (void *cls,
3790                         struct GNUNET_SERVER_Client *client,
3791                         const struct GNUNET_MessageHeader *message)
3792 {
3793   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3794   struct Blacklisters *bl;
3795   struct BlacklistCheck *bc;
3796
3797   bl = bl_head;
3798   while ( (bl != NULL) &&
3799           (bl->client != client) )
3800     bl = bl->next;
3801   if (bl == NULL)
3802     {
3803 #if DEBUG_TRANSPORT
3804       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3805                   "Blacklist client disconnected\n");
3806 #endif
3807       /* FIXME: other error handling here!? */
3808       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3809       return;
3810     }
3811   bc = bl->bc;
3812   bl->bc = NULL;
3813   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3814     {
3815 #if DEBUG_TRANSPORT
3816       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3817                   "Blacklist check failed, peer not allowed\n");
3818 #endif
3819       bc->cont (bc->cont_cls, NULL);
3820       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3821       GNUNET_free (bc);
3822     }
3823   else
3824     {
3825 #if DEBUG_TRANSPORT
3826       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3827                   "Blacklist check succeeded, continuing with checks\n");
3828 #endif
3829       bc->bl_pos = bc->bl_pos->next;
3830       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3831                                            bc);
3832     }
3833   /* check if any other bc's are waiting for this blacklister */
3834   bc = bc_head;
3835   while (bc != NULL)
3836     {
3837       if ( (bc->bl_pos == bl) &&
3838            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3839         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3840                                              bc);
3841       bc = bc->next;
3842     }
3843 }
3844
3845
3846 /**
3847  * Send periodic PING messages to a given foreign address.
3848  *
3849  * @param cls our 'struct PeriodicValidationContext*'
3850  * @param tc task context
3851  */
3852 static void
3853 send_periodic_ping (void *cls,
3854                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3855 {
3856   struct ForeignAddressList *peer_address = cls;
3857   struct TransportPlugin *tp;
3858   struct ValidationEntry *va;
3859   struct NeighbourList *neighbour;
3860   struct TransportPingMessage ping;
3861   struct CheckAddressExistsClosure caec;
3862   char * message_buf;
3863   uint16_t hello_size;
3864   size_t slen;
3865   size_t tsize;
3866
3867   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3868   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3869     return;
3870   tp = peer_address->ready_list->plugin;
3871   neighbour = peer_address->ready_list->neighbour;
3872   if (GNUNET_YES != neighbour->public_key_valid)
3873     {
3874       /* no public key yet, try again later */
3875       schedule_next_ping (peer_address);
3876       return;
3877     }
3878   caec.addr = peer_address->addr;
3879   caec.addrlen = peer_address->addrlen;
3880   caec.tname = tp->short_name;
3881   caec.session = peer_address->session;
3882   caec.exists = GNUNET_NO;
3883   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3884                                          &check_address_exists,
3885                                          &caec);
3886   if (caec.exists == GNUNET_YES)
3887     {
3888       /* During validation attempts we will likely trigger the other
3889          peer trying to validate our address which in turn will cause
3890          it to send us its HELLO, so we expect to hit this case rather
3891          frequently.  Only print something if we are very verbose. */
3892 #if DEBUG_TRANSPORT > 1
3893       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3894                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3895                   (peer_address->addr != NULL)
3896                   ? a2s (tp->short_name,
3897                          peer_address->addr,
3898                          peer_address->addrlen)
3899                   : "<inbound>",
3900                   tp->short_name,
3901                   GNUNET_i2s (&neighbour->id));
3902 #endif
3903       schedule_next_ping (peer_address);
3904       return;
3905     }
3906   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3907   va->transport_name = GNUNET_strdup (tp->short_name);
3908   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3909                                             UINT_MAX);
3910   va->send_time = GNUNET_TIME_absolute_get();
3911   va->session = peer_address->session;
3912   if (peer_address->addr != NULL)
3913     {
3914       va->addr = (const void*) &va[1];
3915       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3916       va->addrlen = peer_address->addrlen;
3917     }
3918   memcpy(&va->publicKey,
3919          &neighbour->publicKey,
3920          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3921
3922   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3923                                                    &timeout_hello_validation,
3924                                                    va);
3925   GNUNET_CONTAINER_multihashmap_put (validation_map,
3926                                      &neighbour->id.hashPubKey,
3927                                      va,
3928                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3929
3930   if (peer_address->validated != GNUNET_YES)
3931     hello_size = GNUNET_HELLO_size(our_hello);
3932   else
3933     hello_size = 0;
3934
3935   tsize = sizeof(struct TransportPingMessage) + hello_size;
3936
3937   if (peer_address->addr != NULL)
3938     {
3939       slen = strlen (tp->short_name) + 1;
3940       tsize += slen + peer_address->addrlen;
3941     }
3942   else
3943     {
3944       slen = 0; /* make gcc happy */
3945     }
3946   message_buf = GNUNET_malloc(tsize);
3947   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3948   ping.challenge = htonl(va->challenge);
3949   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3950   if (peer_address->validated != GNUNET_YES)
3951     {
3952       memcpy(message_buf, our_hello, hello_size);
3953     }
3954
3955   if (peer_address->addr != NULL)
3956     {
3957       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3958                                peer_address->addrlen +
3959                                slen);
3960       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3961              tp->short_name,
3962              slen);
3963       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3964              peer_address->addr,
3965              peer_address->addrlen);
3966     }
3967   else
3968     {
3969       ping.header.size = htons(sizeof(struct TransportPingMessage));
3970     }
3971
3972   memcpy(&message_buf[hello_size],
3973          &ping,
3974          sizeof(struct TransportPingMessage));
3975
3976 #if DEBUG_TRANSPORT_REVALIDATION
3977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3978               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3979               (peer_address->addr != NULL)
3980               ? a2s (peer_address->plugin->short_name,
3981                      peer_address->addr,
3982                      peer_address->addrlen)
3983               : "<inbound>",
3984               tp->short_name,
3985               GNUNET_i2s (&neighbour->id),
3986               "HELLO", hello_size,
3987               "PING");
3988 #endif
3989   if (peer_address->validated != GNUNET_YES)
3990     GNUNET_STATISTICS_update (stats,
3991                               gettext_noop ("# PING with HELLO messages sent"),
3992                               1,
3993                               GNUNET_NO);
3994   else
3995     GNUNET_STATISTICS_update (stats,
3996                               gettext_noop ("# PING without HELLO messages sent"),
3997                               1,
3998                               GNUNET_NO);
3999   GNUNET_STATISTICS_update (stats,
4000                             gettext_noop ("# PING messages sent for re-validation"),
4001                             1,
4002                             GNUNET_NO);
4003   transmit_to_peer (NULL, peer_address,
4004                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4005                     HELLO_VERIFICATION_TIMEOUT,
4006                     message_buf, tsize,
4007                     GNUNET_YES, neighbour);
4008   GNUNET_free(message_buf);
4009   schedule_next_ping (peer_address);
4010 }
4011
4012
4013 /**
4014  * Schedule the job that will cause us to send a PING to the
4015  * foreign address to evaluate its validity and latency.
4016  *
4017  * @param fal address to PING
4018  */
4019 static void
4020 schedule_next_ping (struct ForeignAddressList *fal)
4021 {
4022   struct GNUNET_TIME_Relative delay;
4023
4024   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
4025     return;
4026   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
4027   delay.rel_value /= 2; /* do before expiration */
4028   delay = GNUNET_TIME_relative_min (delay,
4029                                     LATENCY_EVALUATION_MAX_DELAY);
4030   if (GNUNET_YES != fal->estimated)
4031     {
4032       delay = GNUNET_TIME_UNIT_ZERO;
4033       fal->estimated = GNUNET_YES;
4034     }
4035   if (GNUNET_YES == fal->connected)
4036     {
4037       delay = GNUNET_TIME_relative_min (delay,
4038                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
4039     }
4040   /* FIXME: also adjust delay based on how close the last
4041      observed latency is to the latency of the best alternative */
4042   /* bound how fast we can go */
4043   delay = GNUNET_TIME_relative_max (delay,
4044                                     GNUNET_TIME_UNIT_SECONDS);
4045   /* randomize a bit (to avoid doing all at the same time) */
4046   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
4047   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
4048                                                       &send_periodic_ping,
4049                                                       fal);
4050 }
4051
4052
4053
4054
4055 /**
4056  * Function that will be called if we receive some payload
4057  * from another peer.
4058  *
4059  * @param message the payload
4060  * @param n peer who claimed to be the sender
4061  */
4062 static void
4063 handle_payload_message (const struct GNUNET_MessageHeader *message,
4064                         struct NeighbourList *n)
4065 {
4066   struct InboundMessage *im;
4067   struct TransportClient *cpos;
4068   uint16_t msize;
4069
4070   msize = ntohs (message->size);
4071   if (n->received_pong == GNUNET_NO)
4072     {
4073 #if DEBUG_TRANSPORT
4074       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4075                   "Received message of type %u and size %u from `%4s', but no pong yet!\n",
4076                   ntohs (message->type),
4077                   ntohs (message->size),
4078                   GNUNET_i2s (&n->id));
4079 #endif
4080       GNUNET_free_non_null (n->pre_connect_message_buffer);
4081       n->pre_connect_message_buffer = GNUNET_malloc (msize);
4082       memcpy (n->pre_connect_message_buffer, message, msize);
4083       return;
4084     }
4085
4086 #if DEBUG_TRANSPORT
4087   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4088               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4089               ntohs (message->type),
4090               ntohs (message->size),
4091               GNUNET_i2s (&n->id));
4092 #endif
4093   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4094                                                       (ssize_t) msize))
4095     {
4096       n->quota_violation_count++;
4097 #if DEBUG_TRANSPORT
4098       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4099                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
4100                   n->in_tracker.available_bytes_per_s__,
4101                   n->quota_violation_count);
4102 #endif
4103       /* Discount 32k per violation */
4104       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4105                                         - 32 * 1024);
4106     }
4107   else
4108     {
4109       if (n->quota_violation_count > 0)
4110         {
4111           /* try to add 32k back */
4112           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
4113                                             32 * 1024);
4114           n->quota_violation_count--;
4115         }
4116     }
4117   GNUNET_STATISTICS_update (stats,
4118                             gettext_noop ("# payload received from other peers"),
4119                             msize,
4120                             GNUNET_NO);
4121   /* transmit message to all clients */
4122   uint32_t ats_count = 2;
4123   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
4124   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4125           GNUNET_break(0);
4126
4127   im = GNUNET_malloc (size);
4128   im->header.size = htons (size);
4129   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
4130   im->peer = n->id;
4131   im->ats_count = htonl(ats_count);
4132   /* Setting ATS data */
4133   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4134   (&(im->ats))[0].value = htonl (n->distance);
4135   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4136   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4137   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4138   (&(im->ats))[ats_count].value = htonl (0);
4139
4140   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
4141   cpos = clients;
4142   while (cpos != NULL)
4143     {
4144       transmit_to_client (cpos, &im->header, GNUNET_YES);
4145       cpos = cpos->next;
4146     }
4147   GNUNET_free (im);
4148 }
4149
4150
4151 /**
4152  * Iterator over hash map entries.  Checks if the given validation
4153  * entry is for the same challenge as what is given in the PONG.
4154  *
4155  * @param cls the 'struct TransportPongMessage*'
4156  * @param key peer identity
4157  * @param value value in the hash map ('struct ValidationEntry')
4158  * @return GNUNET_YES if we should continue to
4159  *         iterate (mismatch), GNUNET_NO if not (entry matched)
4160  */
4161 static int
4162 check_pending_validation (void *cls,
4163                           const GNUNET_HashCode * key,
4164                           void *value)
4165 {
4166   const struct TransportPongMessage *pong = cls;
4167   struct ValidationEntry *ve = value;
4168   struct AddValidatedAddressContext avac;
4169   unsigned int challenge = ntohl(pong->challenge);
4170   struct GNUNET_HELLO_Message *hello;
4171   struct GNUNET_PeerIdentity target;
4172   struct NeighbourList *n;
4173   struct ForeignAddressList *fal;
4174   struct OwnAddressList *oal;
4175   struct TransportPlugin *tp;
4176   struct GNUNET_MessageHeader *prem;
4177   uint16_t ps;
4178   const char *addr;
4179   size_t slen;
4180   size_t alen;
4181
4182   ps = ntohs (pong->header.size);
4183   if (ps < sizeof (struct TransportPongMessage))
4184     {
4185       GNUNET_break_op (0);
4186       return GNUNET_NO;
4187     }
4188   addr = (const char*) &pong[1];
4189   slen = strlen (ve->transport_name) + 1;
4190   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4191        (ve->challenge != challenge) ||
4192        (addr[slen-1] != '\0') ||
4193        (0 != strcmp (addr, ve->transport_name)) ||
4194        (ntohl (pong->purpose.size)
4195         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4196         sizeof (uint32_t) +
4197         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4198         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4199     {
4200       return GNUNET_YES;
4201     }
4202
4203   alen = ps - sizeof (struct TransportPongMessage) - slen;
4204   switch (ntohl (pong->purpose.purpose))
4205     {
4206     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4207       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4208            (0 != memcmp (&addr[slen],
4209                          ve->addr,
4210                          ve->addrlen)) )
4211         {
4212           return GNUNET_YES; /* different entry, keep trying! */
4213         }
4214       if (0 != memcmp (&pong->pid,
4215                        key,
4216                        sizeof (struct GNUNET_PeerIdentity)))
4217         {
4218           GNUNET_break_op (0);
4219           return GNUNET_NO;
4220         }
4221       if (GNUNET_OK !=
4222           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4223                                     &pong->purpose,
4224                                     &pong->signature,
4225                                     &ve->publicKey))
4226         {
4227           GNUNET_break_op (0);
4228           return GNUNET_NO;
4229         }
4230
4231 #if DEBUG_TRANSPORT
4232       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4233                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4234                   GNUNET_h2s (key),
4235                   a2s (ve->transport_name,
4236                        (const struct sockaddr *) ve->addr,
4237                        ve->addrlen),
4238                   ve->transport_name);
4239 #endif
4240       break;
4241     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4242       if (0 != memcmp (&pong->pid,
4243                          &my_identity,
4244                          sizeof (struct GNUNET_PeerIdentity)))
4245         {
4246       char * peer;
4247           GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4248 #if DEBUG_TRANSPORT
4249           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4250                       "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4251                       GNUNET_i2s (&my_identity), 
4252                       peer );
4253 #endif
4254           GNUNET_free (peer);
4255           return GNUNET_NO;
4256         }
4257       if (ve->addrlen != 0)
4258         {
4259           /* must have been for a different validation entry */
4260           return GNUNET_YES;
4261         }
4262       tp = find_transport (ve->transport_name);
4263       if (tp == NULL)
4264         {
4265           GNUNET_break (0);
4266           return GNUNET_YES;
4267         }
4268       oal = tp->addresses;
4269       while (NULL != oal)
4270         {
4271           if ( (oal->addrlen == alen) &&
4272                (0 == memcmp (&oal[1],
4273                              &addr[slen],
4274                              alen)) )
4275             break;
4276           oal = oal->next;
4277         }
4278       if (oal == NULL)
4279         {
4280           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4281                       _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
4282                       a2s (ve->transport_name,
4283                            &addr[slen],
4284                            alen));
4285           return GNUNET_NO;
4286         }
4287       if (GNUNET_OK !=
4288           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4289                                     &pong->purpose,
4290                                     &pong->signature,
4291                                     &ve->publicKey))
4292         {
4293           GNUNET_break_op (0);
4294           return GNUNET_NO;
4295         }
4296
4297 #if DEBUG_TRANSPORT
4298       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4299                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4300                   GNUNET_h2s (key),
4301                   a2s (ve->transport_name,
4302                        &addr[slen],
4303                        alen),
4304                   ve->transport_name);
4305 #endif
4306       break;
4307     default:
4308       GNUNET_break_op (0);
4309       return GNUNET_NO;
4310     }
4311   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4312     {
4313       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4314                   _("Received expired signature.  Check system time.\n"));
4315       return GNUNET_NO;
4316     }
4317   GNUNET_STATISTICS_update (stats,
4318                             gettext_noop ("# address validation successes"),
4319                             1,
4320                             GNUNET_NO);
4321   /* create the updated HELLO */
4322   GNUNET_CRYPTO_hash (&ve->publicKey,
4323                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4324                       &target.hashPubKey);
4325   if (ve->addr != NULL)
4326     {
4327       avac.done = GNUNET_NO;
4328       avac.ve = ve;
4329       hello = GNUNET_HELLO_create (&ve->publicKey,
4330                                    &add_validated_address,
4331                                    &avac);
4332       GNUNET_PEERINFO_add_peer (peerinfo,
4333                                 hello);
4334       GNUNET_free (hello);
4335     }
4336   n = find_neighbour (&target);
4337   if (n != NULL)
4338     {
4339       n->publicKey = ve->publicKey;
4340       n->public_key_valid = GNUNET_YES;
4341       fal = add_peer_address (n,
4342                               ve->transport_name,
4343                               ve->session,
4344                               ve->addr,
4345                               ve->addrlen);
4346       GNUNET_assert (fal != NULL);
4347       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4348       fal->validated = GNUNET_YES;
4349       mark_address_connected (fal);
4350       GNUNET_STATISTICS_update (stats,
4351                                 gettext_noop ("# peer addresses considered valid"),
4352                                 1,
4353                                 GNUNET_NO);
4354       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4355       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4356
4357       schedule_next_ping (fal);
4358       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4359         n->latency = fal->latency;
4360       else
4361         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4362
4363       n->distance = fal->distance;
4364       if (GNUNET_NO == n->received_pong)
4365         {
4366           n->received_pong = GNUNET_YES;
4367
4368           notify_clients_connect (&target, n->latency, n->distance);
4369           if (NULL != (prem = n->pre_connect_message_buffer))
4370             {
4371               n->pre_connect_message_buffer = NULL;
4372               handle_payload_message (prem, n);
4373               GNUNET_free (prem);
4374             }
4375         }
4376       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4377         {
4378           GNUNET_SCHEDULER_cancel (n->retry_task);
4379           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4380           try_transmission_to_peer (n);
4381         }
4382     }
4383
4384   /* clean up validation entry */
4385   GNUNET_assert (GNUNET_YES ==
4386                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4387                                                        key,
4388                                                        ve));
4389   abort_validation (NULL, NULL, ve);
4390   return GNUNET_NO;
4391 }
4392
4393
4394 /**
4395  * Function that will be called if we receive a validation
4396  * of an address challenge that we transmitted to another
4397  * peer.  Note that the validation should only be considered
4398  * acceptable if the challenge matches AND if the sender
4399  * address is at least a plausible address for this peer
4400  * (otherwise we may be seeing a MiM attack).
4401  *
4402  * @param cls closure
4403  * @param message the pong message
4404  * @param peer who responded to our challenge
4405  * @param sender_address string describing our sender address (as observed
4406  *         by the other peer in binary format)
4407  * @param sender_address_len number of bytes in 'sender_address'
4408  */
4409 static void
4410 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4411              const struct GNUNET_PeerIdentity *peer,
4412              const char *sender_address,
4413              size_t sender_address_len)
4414 {
4415   if (0 == memcmp (peer,
4416                    &my_identity,
4417                    sizeof (struct GNUNET_PeerIdentity)))
4418     {
4419       /* PONG send to self, ignore */
4420       return;
4421     }
4422
4423 #if DEBUG_TRANSPORT > 1
4424   /* we get tons of these that just get discarded, only log
4425      if we are quite verbose */
4426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4427               "Receiving `%s' message from `%4s'.\n", "PONG",
4428               GNUNET_i2s (peer));
4429 #endif
4430   GNUNET_STATISTICS_update (stats,
4431                             gettext_noop ("# PONG messages received"),
4432                             1,
4433                             GNUNET_NO);
4434   if (GNUNET_SYSERR !=
4435       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4436                                                   &peer->hashPubKey,
4437                                                   &check_pending_validation,
4438                                                   (void*) message))
4439     {
4440       /* This is *expected* to happen a lot since we send
4441          PONGs to *all* known addresses of the sender of
4442          the PING, so most likely we get multiple PONGs
4443          per PING, and all but the first PONG will end up
4444          here. So really we should not print anything here
4445          unless we want to be very, very verbose... */
4446 #if DEBUG_TRANSPORT > 2
4447       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4448                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4449                   "PONG",
4450                   GNUNET_i2s (peer),
4451                   "PING");
4452 #endif
4453       return;
4454     }
4455
4456 }
4457
4458
4459 /**
4460  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4461  *
4462  * @param cls the 'struct ValidationEntry*'
4463  * @param neighbour neighbour to validate, NULL if validation failed
4464  */
4465 static void
4466 transmit_hello_and_ping (void *cls,
4467                          struct NeighbourList *neighbour)
4468 {
4469   struct ValidationEntry *va = cls;
4470   struct ForeignAddressList *peer_address;
4471   struct TransportPingMessage ping;
4472   uint16_t hello_size;
4473   size_t tsize;
4474   char * message_buf;
4475   struct GNUNET_PeerIdentity id;
4476   size_t slen;
4477
4478   GNUNET_CRYPTO_hash (&va->publicKey,
4479                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4480                       &id.hashPubKey);
4481   if (neighbour == NULL)
4482     {
4483       /* FIXME: stats... */
4484       GNUNET_break (GNUNET_OK ==
4485                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4486                                                           &id.hashPubKey,
4487                                                           va));
4488       abort_validation (NULL, NULL, va);
4489       return;
4490     }
4491   neighbour->publicKey = va->publicKey;
4492   neighbour->public_key_valid = GNUNET_YES;
4493   peer_address = add_peer_address (neighbour,
4494                                    va->transport_name, NULL,
4495                                    (const void*) &va[1],
4496                                    va->addrlen);
4497   if (peer_address == NULL)
4498     {
4499       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4500                   "Failed to add peer `%4s' for plugin `%s'\n",
4501                   GNUNET_i2s (&neighbour->id),
4502                   va->transport_name);
4503       GNUNET_break (GNUNET_OK ==
4504                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4505                                                           &id.hashPubKey,
4506                                                           va));
4507       abort_validation (NULL, NULL, va);
4508       return;
4509     }
4510   hello_size = GNUNET_HELLO_size(our_hello);
4511   slen = strlen(va->transport_name) + 1;
4512   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4513   message_buf = GNUNET_malloc(tsize);
4514   ping.challenge = htonl(va->challenge);
4515   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4516   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4517   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4518   memcpy(message_buf, our_hello, hello_size);
4519   memcpy(&message_buf[hello_size],
4520          &ping,
4521          sizeof(struct TransportPingMessage));
4522   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4523          va->transport_name,
4524          slen);
4525   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4526          &va[1],
4527          va->addrlen);
4528 #if DEBUG_TRANSPORT
4529   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4530               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4531               (va->addrlen == 0)
4532               ? "<inbound>"
4533               : a2s (va->transport_name,
4534                      (const void*) &va[1], va->addrlen),
4535               va->transport_name,
4536               GNUNET_i2s (&neighbour->id),
4537               "HELLO", hello_size,
4538               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4539 #endif
4540
4541   GNUNET_STATISTICS_update (stats,
4542                             gettext_noop ("# PING messages sent for initial validation"),
4543                             1,
4544                             GNUNET_NO);
4545   transmit_to_peer (NULL, peer_address,
4546                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4547                     HELLO_VERIFICATION_TIMEOUT,
4548                     message_buf, tsize,
4549                     GNUNET_YES, neighbour);
4550   GNUNET_free(message_buf);
4551 }
4552
4553
4554 /**
4555  * Check if the given address is already being validated; if not,
4556  * append the given address to the list of entries that are being be
4557  * validated and initiate validation.
4558  *
4559  * @param cls closure ('struct CheckHelloValidatedContext *')
4560  * @param tname name of the transport
4561  * @param expiration expiration time
4562  * @param addr the address
4563  * @param addrlen length of the address
4564  * @return GNUNET_OK (always)
4565  */
4566 static int
4567 run_validation (void *cls,
4568                 const char *tname,
4569                 struct GNUNET_TIME_Absolute expiration,
4570                 const void *addr,
4571                 uint16_t addrlen)
4572 {
4573   struct CheckHelloValidatedContext *chvc = cls;
4574   struct GNUNET_PeerIdentity id;
4575   struct TransportPlugin *tp;
4576   struct ValidationEntry *va;
4577   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4578   struct CheckAddressExistsClosure caec;
4579   struct OwnAddressList *oal;
4580
4581   GNUNET_assert (addr != NULL);
4582
4583   GNUNET_STATISTICS_update (stats,
4584                             gettext_noop ("# peer addresses scheduled for validation"),
4585                             1,
4586                             GNUNET_NO);
4587   tp = find_transport (tname);
4588   if (tp == NULL)
4589     {
4590       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4591                   GNUNET_ERROR_TYPE_BULK,
4592                   _
4593                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4594                   tname);
4595       GNUNET_STATISTICS_update (stats,
4596                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4597                                 1,
4598                                 GNUNET_NO);
4599       return GNUNET_OK;
4600     }
4601   /* check if this is one of our own addresses */
4602   oal = tp->addresses;
4603   while (NULL != oal)
4604     {
4605       if ( (oal->addrlen == addrlen) &&
4606            (0 == memcmp (&oal[1],
4607                          addr,
4608                          addrlen)) )
4609         {
4610           /* not plausible, this address is equivalent to our own address! */
4611           GNUNET_STATISTICS_update (stats,
4612                                     gettext_noop ("# peer addresses not validated (loopback)"),
4613                                     1,
4614                                     GNUNET_NO);
4615           return GNUNET_OK;
4616         }
4617       oal = oal->next;
4618     }
4619   GNUNET_HELLO_get_key (chvc->hello, &pk);
4620   GNUNET_CRYPTO_hash (&pk,
4621                       sizeof (struct
4622                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4623                       &id.hashPubKey);
4624
4625   if (is_blacklisted(&id, tp))
4626     {
4627 #if DEBUG_TRANSPORT
4628       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4629                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4630                   GNUNET_i2s(&id),
4631                   tname);
4632 #endif
4633       return GNUNET_OK;
4634     }
4635
4636   caec.addr = addr;
4637   caec.addrlen = addrlen;
4638   caec.session = NULL;
4639   caec.tname = tname;
4640   caec.exists = GNUNET_NO;
4641   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4642                                          &check_address_exists,
4643                                          &caec);
4644   if (caec.exists == GNUNET_YES)
4645     {
4646       /* During validation attempts we will likely trigger the other
4647          peer trying to validate our address which in turn will cause
4648          it to send us its HELLO, so we expect to hit this case rather
4649          frequently.  Only print something if we are very verbose. */
4650 #if DEBUG_TRANSPORT > 1
4651       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4652                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4653                   a2s (tname, addr, addrlen),
4654                   tname,
4655                   GNUNET_i2s (&id));
4656 #endif
4657       GNUNET_STATISTICS_update (stats,
4658                                 gettext_noop ("# peer addresses not validated (in progress)"),
4659                                 1,
4660                                 GNUNET_NO);
4661       return GNUNET_OK;
4662     }
4663   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4664   va->chvc = chvc;
4665   chvc->ve_count++;
4666   va->transport_name = GNUNET_strdup (tname);
4667   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4668                                             UINT_MAX);
4669   va->send_time = GNUNET_TIME_absolute_get();
4670   va->addr = (const void*) &va[1];
4671   memcpy (&va[1], addr, addrlen);
4672   va->addrlen = addrlen;
4673   GNUNET_HELLO_get_key (chvc->hello,
4674                         &va->publicKey);
4675   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4676                                                    &timeout_hello_validation,
4677                                                    va);
4678   GNUNET_CONTAINER_multihashmap_put (validation_map,
4679                                      &id.hashPubKey,
4680                                      va,
4681                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4682   setup_peer_check_blacklist (&id, GNUNET_NO,
4683                               &transmit_hello_and_ping,
4684                               va);
4685   return GNUNET_OK;
4686 }
4687
4688
4689 /**
4690  * Check if addresses in validated hello "h" overlap with
4691  * those in "chvc->hello" and validate the rest.
4692  *
4693  * @param cls closure
4694  * @param peer id of the peer, NULL for last call
4695  * @param h hello message for the peer (can be NULL)
4696  * @param err_msg NULL if successful, otherwise contains error message
4697  */
4698 static void
4699 check_hello_validated (void *cls,
4700                        const struct GNUNET_PeerIdentity *peer,
4701                        const struct GNUNET_HELLO_Message *h,
4702                        const char *err_msg)
4703 {
4704   struct CheckHelloValidatedContext *chvc = cls;
4705   struct GNUNET_HELLO_Message *plain_hello;
4706   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4707   struct GNUNET_PeerIdentity target;
4708   struct NeighbourList *n;
4709
4710   if (err_msg != NULL)
4711     {
4712 #if DEBUG_TRANSPORT
4713       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4714                   _("Error in communication with PEERINFO service: %s\n"),
4715                   err_msg);
4716 #endif
4717       /* return; */
4718   }
4719
4720   if (peer == NULL)
4721     {
4722       GNUNET_STATISTICS_update (stats,
4723                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4724                                 -1,
4725                                 GNUNET_NO);
4726       chvc->piter = NULL;
4727       if (GNUNET_NO == chvc->hello_known)
4728         {
4729           /* notify PEERINFO about the peer now, so that we at least
4730              have the public key if some other component needs it */
4731           GNUNET_HELLO_get_key (chvc->hello, &pk);
4732           GNUNET_CRYPTO_hash (&pk,
4733                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4734                               &target.hashPubKey);
4735           plain_hello = GNUNET_HELLO_create (&pk,
4736                                              NULL,
4737                                              NULL);
4738           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4739           GNUNET_free (plain_hello);
4740 #if DEBUG_TRANSPORT_HELLO
4741           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4742                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4743                       "HELLO",
4744                       GNUNET_i2s (&target));
4745 #endif
4746           GNUNET_STATISTICS_update (stats,
4747                                     gettext_noop ("# new HELLOs requiring full validation"),
4748                                     1,
4749                                     GNUNET_NO);
4750           GNUNET_HELLO_iterate_addresses (chvc->hello,
4751                                           GNUNET_NO,
4752                                           &run_validation,
4753                                           chvc);
4754         }
4755       else
4756         {
4757           GNUNET_STATISTICS_update (stats,
4758                                     gettext_noop ("# duplicate HELLO (peer known)"),
4759                                     1,
4760                                     GNUNET_NO);
4761         }
4762       chvc->ve_count--;
4763       if (chvc->ve_count == 0)
4764         {
4765           GNUNET_CONTAINER_DLL_remove (chvc_head,
4766                                        chvc_tail,
4767                                        chvc);
4768           GNUNET_free (chvc);
4769         }
4770       return;
4771     }
4772   if (h == NULL)
4773     return;
4774 #if DEBUG_TRANSPORT_HELLO
4775   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4776               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4777               "HELLO",
4778               GNUNET_i2s (peer));
4779 #endif
4780   chvc->hello_known = GNUNET_YES;
4781   n = find_neighbour (peer);
4782   if (n != NULL)
4783     {
4784 #if DEBUG_TRANSPORT_HELLO
4785       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4786                   "Calling hello_iterate_addresses for %s!\n",
4787                   GNUNET_i2s (peer));
4788 #endif
4789       GNUNET_HELLO_iterate_addresses (h,
4790                                       GNUNET_NO,
4791                                       &add_to_foreign_address_list,
4792                                       n);
4793       try_transmission_to_peer (n);
4794     }
4795   else
4796     {
4797 #if DEBUG_TRANSPORT_HELLO
4798       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4799                   "No existing neighbor record for %s!\n",
4800                   GNUNET_i2s (peer));
4801 #endif
4802       GNUNET_STATISTICS_update (stats,
4803                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4804                                 1,
4805                                 GNUNET_NO);
4806     }
4807   GNUNET_STATISTICS_update (stats,
4808                             gettext_noop ("# HELLO validations (update case)"),
4809                             1,
4810                             GNUNET_NO);
4811   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4812                                       h,
4813                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4814                                       &run_validation,
4815                                       chvc);
4816 }
4817
4818
4819 /**
4820  * Process HELLO-message.
4821  *
4822  * @param plugin transport involved, may be NULL
4823  * @param message the actual message
4824  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4825  */
4826 static int
4827 process_hello (struct TransportPlugin *plugin,
4828                const struct GNUNET_MessageHeader *message)
4829 {
4830   uint16_t hsize;
4831   struct GNUNET_PeerIdentity target;
4832   const struct GNUNET_HELLO_Message *hello;
4833   struct CheckHelloValidatedContext *chvc;
4834   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4835 #if DEBUG_TRANSPORT_HELLO > 2
4836   char *my_id;
4837 #endif
4838   hsize = ntohs (message->size);
4839   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4840       (hsize < sizeof (struct GNUNET_MessageHeader)))
4841     {
4842       GNUNET_break (0);
4843       return GNUNET_SYSERR;
4844     }
4845   GNUNET_STATISTICS_update (stats,
4846                             gettext_noop ("# HELLOs received for validation"),
4847                             1,
4848                             GNUNET_NO);
4849
4850   /* first, check if load is too high */
4851   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4852     {
4853       GNUNET_STATISTICS_update (stats,
4854                                 gettext_noop ("# HELLOs ignored due to high load"),
4855                                 1,
4856                                 GNUNET_NO);
4857 #if DEBUG_TRANSPORT_HELLO
4858       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4859                   "Ignoring `%s' for `%4s', load too high.\n",
4860                   "HELLO",
4861                   GNUNET_i2s (&target));
4862 #endif
4863       return GNUNET_OK;
4864     }
4865   hello = (const struct GNUNET_HELLO_Message *) message;
4866   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4867     {
4868 #if DEBUG_TRANSPORT_HELLO
4869       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4870                   "Unable to get public key from `%s' for `%4s'!\n",
4871                   "HELLO",
4872                   GNUNET_i2s (&target));
4873 #endif
4874       GNUNET_break_op (0);
4875       return GNUNET_SYSERR;
4876     }
4877
4878   GNUNET_CRYPTO_hash (&publicKey,
4879                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4880                       &target.hashPubKey);
4881
4882 #if DEBUG_TRANSPORT_HELLO
4883   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4884               "Received `%s' message for `%4s'\n",
4885               "HELLO",
4886               GNUNET_i2s (&target));
4887 #endif
4888
4889   if (0 == memcmp (&my_identity,
4890                    &target,
4891                    sizeof (struct GNUNET_PeerIdentity)))
4892     {
4893       GNUNET_STATISTICS_update (stats,
4894                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4895                                 1,
4896                                 GNUNET_NO);
4897       return GNUNET_OK;
4898     }
4899   chvc = chvc_head;
4900   while (NULL != chvc)
4901     {
4902       if (GNUNET_HELLO_equals (hello,
4903                                chvc->hello,
4904                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4905         {
4906 #if DEBUG_TRANSPORT_HELLO > 2
4907           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4908                       "Received duplicate `%s' message for `%4s'; ignored\n",
4909                       "HELLO",
4910                       GNUNET_i2s (&target));
4911 #endif
4912           return GNUNET_OK; /* validation already pending */
4913         }
4914       if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4915         GNUNET_break (0 != memcmp (hello, chvc->hello,
4916                                    GNUNET_HELLO_size(hello)));
4917       chvc = chvc->next;
4918     }
4919
4920 #if BREAK_TESTS
4921   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4922   if ((NULL != temp_neighbor))
4923     {
4924       fprintf(stderr, "Already know peer, ignoring hello\n");
4925       return GNUNET_OK;
4926     }
4927 #endif
4928
4929 #if DEBUG_TRANSPORT_HELLO > 2
4930   if (plugin != NULL)
4931     {
4932       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4933 #if DEBUG_TRANSPORT
4934       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4935                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4936                   my_id,
4937                   "HELLO",
4938                   GNUNET_i2s (&target),
4939                   plugin->short_name,
4940                   GNUNET_HELLO_size(hello));
4941 #endif
4942       GNUNET_free(my_id);
4943     }
4944 #endif
4945   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4946   chvc->ve_count = 1;
4947   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4948   memcpy (&chvc[1], hello, hsize);
4949   GNUNET_CONTAINER_DLL_insert (chvc_head,
4950                                chvc_tail,
4951                                chvc);
4952   /* finally, check if HELLO was previously validated
4953      (continuation will then schedule actual validation) */
4954   GNUNET_STATISTICS_update (stats,
4955                             gettext_noop ("# peerinfo process hello iterate requests"),
4956                             1,
4957                             GNUNET_NO);
4958   GNUNET_STATISTICS_update (stats,
4959                             gettext_noop ("# outstanding peerinfo iterate requests"),
4960                             1,
4961                             GNUNET_NO);
4962   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4963                                          &target,
4964                                          HELLO_VERIFICATION_TIMEOUT,
4965                                          &check_hello_validated, chvc);
4966   return GNUNET_OK;
4967 }
4968
4969
4970 /**
4971  * The peer specified by the given neighbour has timed-out or a plugin
4972  * has disconnected.  We may either need to do nothing (other plugins
4973  * still up), or trigger a full disconnect and clean up.  This
4974  * function updates our state and does the necessary notifications.
4975  * Also notifies our clients that the neighbour is now officially
4976  * gone.
4977  *
4978  * @param n the neighbour list entry for the peer
4979  * @param check GNUNET_YES to check if ALL addresses for this peer
4980  *              are gone, GNUNET_NO to force a disconnect of the peer
4981  *              regardless of whether other addresses exist.
4982  */
4983 static void
4984 disconnect_neighbour (struct NeighbourList *n, int check)
4985 {
4986   struct ReadyList *rpos;
4987   struct NeighbourList *npos;
4988   struct NeighbourList *nprev;
4989   struct MessageQueue *mq;
4990   struct ForeignAddressList *peer_addresses;
4991   struct ForeignAddressList *peer_pos;
4992
4993   if (GNUNET_YES == check)
4994     {
4995       rpos = n->plugins;
4996       while (NULL != rpos)
4997         {
4998           peer_addresses = rpos->addresses;
4999           while (peer_addresses != NULL)
5000             {
5001                   // Do not disconnect if: an address is connected or an inbound address exists
5002               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
5003                 {
5004 #if DEBUG_TRANSPORT
5005                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5006                               "NOT Disconnecting from `%4s', still have live addresses!\n",
5007                               GNUNET_i2s (&n->id));
5008 #endif
5009                   return;             /* still connected */
5010                 }
5011               peer_addresses = peer_addresses->next;
5012             }
5013           rpos = rpos->next;
5014         }
5015     }
5016 #if DEBUG_TRANSPORT
5017   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5018               "Disconnecting from `%4s'\n",
5019               GNUNET_i2s (&n->id));
5020 #endif
5021   /* remove n from neighbours list */
5022   nprev = NULL;
5023   npos = neighbours;
5024   while ((npos != NULL) && (npos != n))
5025     {
5026       nprev = npos;
5027       npos = npos->next;
5028     }
5029   GNUNET_assert (npos != NULL);
5030   if (nprev == NULL)
5031     neighbours = n->next;
5032   else
5033     nprev->next = n->next;
5034
5035   /* notify all clients about disconnect */
5036   if (GNUNET_YES == n->received_pong)
5037     notify_clients_disconnect (&n->id);
5038
5039   /* clean up all plugins, cancel connections and pending transmissions */
5040   while (NULL != (rpos = n->plugins))
5041     {
5042       n->plugins = rpos->next;
5043       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
5044       while (rpos->addresses != NULL)
5045         {
5046           peer_pos = rpos->addresses;
5047           rpos->addresses = peer_pos->next;
5048           if (peer_pos->connected == GNUNET_YES)
5049             GNUNET_STATISTICS_update (stats,
5050                                       gettext_noop ("# connected addresses"),
5051                                       -1,
5052                                       GNUNET_NO);
5053           if (GNUNET_YES == peer_pos->validated)
5054             GNUNET_STATISTICS_update (stats,
5055                                       gettext_noop ("# peer addresses considered valid"),
5056                                       -1,
5057                                       GNUNET_NO);
5058           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
5059             {
5060               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
5061               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5062             }
5063           GNUNET_free(peer_pos->ressources);
5064           peer_pos->ressources = NULL;
5065           GNUNET_free(peer_pos->quality);
5066           peer_pos->ressources = NULL;
5067           GNUNET_free(peer_pos);
5068           ats->stat.recreate_problem = GNUNET_YES;
5069         }
5070       GNUNET_free (rpos);
5071     }
5072
5073   /* free all messages on the queue */
5074   while (NULL != (mq = n->messages_head))
5075     {
5076       GNUNET_STATISTICS_update (stats,
5077                                 gettext_noop ("# bytes in message queue for other peers"),
5078                                 - (int64_t) mq->message_buf_size,
5079                                 GNUNET_NO);
5080       GNUNET_STATISTICS_update (stats,
5081                                 gettext_noop ("# bytes discarded due to disconnect"),
5082                                 mq->message_buf_size,
5083                                 GNUNET_NO);
5084       GNUNET_CONTAINER_DLL_remove (n->messages_head,
5085                                    n->messages_tail,
5086                                    mq);
5087       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
5088                                  &n->id,
5089                                  sizeof(struct GNUNET_PeerIdentity)));
5090       GNUNET_free (mq);
5091     }
5092   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
5093     {
5094       GNUNET_SCHEDULER_cancel (n->timeout_task);
5095       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
5096     }
5097   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
5098     {
5099       GNUNET_SCHEDULER_cancel (n->retry_task);
5100       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
5101     }
5102   if (n->piter != NULL)
5103     {
5104       GNUNET_PEERINFO_iterate_cancel (n->piter);
5105       GNUNET_STATISTICS_update (stats,
5106                                 gettext_noop ("# outstanding peerinfo iterate requests"),
5107                                 -1,
5108                                 GNUNET_NO);
5109       n->piter = NULL;
5110     }
5111   /* finally, free n itself */
5112   GNUNET_STATISTICS_update (stats,
5113                             gettext_noop ("# active neighbours"),
5114                             -1,
5115                             GNUNET_NO);
5116   GNUNET_free_non_null (n->pre_connect_message_buffer);
5117   GNUNET_free (n);
5118 }
5119
5120
5121 /**
5122  * We have received a PING message from someone.  Need to send a PONG message
5123  * in response to the peer by any means necessary.
5124  */
5125 static int
5126 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
5127             const struct GNUNET_PeerIdentity *peer,
5128             struct Session *session,
5129             const char *sender_address,
5130             uint16_t sender_address_len)
5131 {
5132   struct TransportPlugin *plugin = cls;
5133   struct SessionHeader *session_header = (struct SessionHeader*) session;
5134   struct TransportPingMessage *ping;
5135   struct TransportPongMessage *pong;
5136   struct NeighbourList *n;
5137   struct ReadyList *rl;
5138   struct ForeignAddressList *fal;
5139   struct OwnAddressList *oal;
5140   const char *addr;
5141   size_t alen;
5142   size_t slen;
5143
5144   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
5145     {
5146       GNUNET_break_op (0);
5147       return GNUNET_SYSERR;
5148     }
5149
5150   ping = (struct TransportPingMessage *) message;
5151   if (0 != memcmp (&ping->target,
5152                    plugin->env.my_identity,
5153                    sizeof (struct GNUNET_PeerIdentity)))
5154     {
5155 #if DEBUG_TRANSPORT
5156       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5157                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
5158                   "PING",
5159                   (sender_address != NULL)
5160                   ? a2s (plugin->short_name,
5161                          (const struct sockaddr *)sender_address,
5162                          sender_address_len)
5163                   : "<inbound>",
5164                   GNUNET_i2s (&ping->target));
5165 #endif
5166       return GNUNET_SYSERR;
5167     }
5168 #if DEBUG_PING_PONG
5169   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5170               "Processing `%s' from `%s'\n",
5171               "PING",
5172               (sender_address != NULL)
5173               ? a2s (plugin->short_name,
5174                      (const struct sockaddr *)sender_address,
5175                      sender_address_len)
5176               : "<inbound>");
5177 #endif
5178   GNUNET_STATISTICS_update (stats,
5179                             gettext_noop ("# PING messages received"),
5180                             1,
5181                             GNUNET_NO);
5182   addr = (const char*) &ping[1];
5183   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5184   slen = strlen (plugin->short_name) + 1;
5185   if (alen == 0)
5186     {
5187       /* peer wants to confirm that we have an outbound connection to him */
5188       if (session == NULL)
5189         {
5190           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5191                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5192                       GNUNET_i2s (peer));
5193           return GNUNET_SYSERR;
5194         }
5195       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5196       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5197       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5198       pong->purpose.size =
5199         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5200                sizeof (uint32_t) +
5201                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5202                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5203       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5204       pong->challenge = ping->challenge;
5205       pong->addrlen = htonl(sender_address_len + slen);
5206       memcpy(&pong->pid,
5207              peer,
5208              sizeof(struct GNUNET_PeerIdentity));
5209       memcpy (&pong[1],
5210               plugin->short_name,
5211               slen);
5212       if ((sender_address!=NULL) && (sender_address_len > 0))
5213                   memcpy (&((char*)&pong[1])[slen],
5214                           sender_address,
5215                           sender_address_len);
5216       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5217         {
5218           /* create / update cached sig */
5219 #if DEBUG_TRANSPORT
5220           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5221                       "Creating PONG signature to indicate active connection.\n");
5222 #endif
5223           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5224           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5225           GNUNET_assert (GNUNET_OK ==
5226                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5227                                                  &pong->purpose,
5228                                                  &session_header->pong_signature));
5229         }
5230       else
5231         {
5232           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5233         }
5234       memcpy (&pong->signature,
5235               &session_header->pong_signature,
5236               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5237
5238
5239     }
5240   else
5241     {
5242       /* peer wants to confirm that this is one of our addresses */
5243       addr += slen;
5244       alen -= slen;
5245       if (GNUNET_OK !=
5246           plugin->api->check_address (plugin->api->cls,
5247                                       addr,
5248                                       alen))
5249         {
5250           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5251                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5252                       a2s (plugin->short_name,
5253                            addr,
5254                            alen));
5255           return GNUNET_NO;
5256         }
5257       oal = plugin->addresses;
5258       while (NULL != oal)
5259         {
5260           if ( (oal->addrlen == alen) &&
5261                (0 == memcmp (addr,
5262                              &oal[1],
5263                              alen)) )
5264             break;
5265           oal = oal->next;
5266         }
5267       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5268       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5269       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5270       pong->purpose.size =
5271         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5272                sizeof (uint32_t) +
5273                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5274                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5275       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5276       pong->challenge = ping->challenge;
5277       pong->addrlen = htonl(alen + slen);
5278       memcpy(&pong->pid,
5279              &my_identity,
5280              sizeof(struct GNUNET_PeerIdentity));
5281       memcpy (&pong[1], plugin->short_name, slen);
5282       memcpy (&((char*)&pong[1])[slen], addr, alen);
5283       if ( (oal != NULL) &&
5284            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5285         {
5286           /* create / update cached sig */
5287 #if DEBUG_TRANSPORT
5288           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5289                       "Creating PONG signature to indicate ownership.\n");
5290 #endif
5291           oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
5292                                                             GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5293           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5294           GNUNET_assert (GNUNET_OK ==
5295                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5296                                                  &pong->purpose,
5297                                                  &oal->pong_signature));
5298           memcpy (&pong->signature,
5299                   &oal->pong_signature,
5300                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5301         }
5302       else if (oal == NULL)
5303         {
5304           /* not using cache (typically DV-only) */
5305           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5306           GNUNET_assert (GNUNET_OK ==
5307                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5308                                                  &pong->purpose,
5309                                                  &pong->signature));
5310         }
5311       else
5312         {
5313           /* can used cached version */
5314           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5315           memcpy (&pong->signature,
5316                   &oal->pong_signature,
5317                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5318         }
5319     }
5320   n = find_neighbour(peer);
5321   GNUNET_assert (n != NULL);
5322   /* first try reliable response transmission */
5323   rl = n->plugins;
5324   while (rl != NULL)
5325     {
5326       fal = rl->addresses;
5327       while (fal != NULL)
5328         {
5329           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5330                                            peer,
5331                                            (const char*) pong,
5332                                            ntohs (pong->header.size),
5333                                            TRANSPORT_PONG_PRIORITY,
5334                                            HELLO_VERIFICATION_TIMEOUT,
5335                                            fal->session,
5336                                            fal->addr,
5337                                            fal->addrlen,
5338                                            GNUNET_SYSERR,
5339                                            NULL, NULL))
5340             {
5341               /* done! */
5342               GNUNET_STATISTICS_update (stats,
5343                                         gettext_noop ("# PONGs unicast via reliable transport"),
5344                                         1,
5345                                         GNUNET_NO);
5346               GNUNET_free (pong);
5347               return GNUNET_OK;
5348             }
5349           fal = fal->next;
5350         }
5351       rl = rl->next;
5352     }
5353   /* no reliable method found, do multicast */
5354   GNUNET_STATISTICS_update (stats,
5355                             gettext_noop ("# PONGs multicast to all available addresses"),
5356                             1,
5357                             GNUNET_NO);
5358   rl = n->plugins;
5359   while (rl != NULL)
5360     {
5361       fal = rl->addresses;
5362       while (fal != NULL)
5363         {
5364           transmit_to_peer(NULL, fal,
5365                            TRANSPORT_PONG_PRIORITY,
5366                            HELLO_VERIFICATION_TIMEOUT,
5367                            (const char *)pong,
5368                            ntohs(pong->header.size),
5369                            GNUNET_YES,
5370                            n);
5371           fal = fal->next;
5372         }
5373       rl = rl->next;
5374     }
5375   GNUNET_free(pong);
5376   return GNUNET_OK;
5377 }
5378
5379
5380 /**
5381  * Function called by the plugin for each received message.  Update
5382  * data volumes, possibly notify plugins about reducing the rate at
5383  * which they read from the socket and generally forward to our
5384  * receive callback.
5385  *
5386  * @param cls the "struct TransportPlugin *" we gave to the plugin
5387  * @param peer (claimed) identity of the other peer
5388  * @param message the message, NULL if we only care about
5389  *                learning about the delay until we should receive again
5390  * @param ats_data information for automatic transport selection
5391  * @param ats_count number of elements in ats not including 0-terminator
5392  * @param session identifier used for this session (can be NULL)
5393  * @param sender_address binary address of the sender (if observed)
5394  * @param sender_address_len number of bytes in sender_address
5395  * @return how long in ms the plugin should wait until receiving more data
5396  *         (plugins that do not support this, can ignore the return value)
5397  */
5398 static struct GNUNET_TIME_Relative
5399 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5400                     const struct GNUNET_MessageHeader *message,
5401                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5402                     uint32_t ats_count,
5403                     struct Session *session,
5404                     const char *sender_address,
5405                     uint16_t sender_address_len)
5406 {
5407   struct TransportPlugin *plugin = cls;
5408   struct ReadyList *service_context;
5409   struct ForeignAddressList *peer_address;
5410   uint16_t msize;
5411   struct NeighbourList *n;
5412   struct GNUNET_TIME_Relative ret;
5413   uint32_t distance;
5414   int c;
5415
5416   if (0 == memcmp (peer,
5417                    &my_identity,
5418                    sizeof (struct GNUNET_PeerIdentity)))
5419     {
5420       /* refuse to receive from myself */
5421       GNUNET_break (0); 
5422       return GNUNET_TIME_UNIT_FOREVER_REL;
5423     }
5424   if (is_blacklisted (peer, plugin))
5425     return GNUNET_TIME_UNIT_FOREVER_REL;
5426   n = find_neighbour (peer);
5427   if (n == NULL)
5428     n = setup_new_neighbour (peer, GNUNET_YES);
5429   service_context = n->plugins;
5430   while ((service_context != NULL) && (plugin != service_context->plugin))
5431     service_context = service_context->next;
5432   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5433   peer_address = NULL;
5434   distance = 1;
5435
5436   for (c=0; c<ats_count; c++)
5437     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5438       distance = ntohl(ats_data[c].value);
5439   
5440   /* notify ATS about incoming data */
5441   //ats_notify_ats_data(peer, ats_data);
5442
5443   if (message != NULL)
5444     {
5445       if ( (session != NULL) ||
5446            (sender_address != NULL) )
5447         peer_address = add_peer_address (n,
5448                                          plugin->short_name,
5449                                          session,
5450                                          sender_address,
5451                                          sender_address_len);
5452       if (peer_address != NULL)
5453         {
5454           update_addr_ats(peer_address, ats_data, ats_count);
5455           update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5456           
5457           peer_address->distance = distance;
5458           if (GNUNET_YES == peer_address->validated)
5459             mark_address_connected (peer_address);
5460           peer_address->timeout
5461             = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5462           schedule_next_ping (peer_address);
5463         }
5464       /* update traffic received amount ... */
5465       msize = ntohs (message->size);
5466
5467       GNUNET_STATISTICS_update (stats,
5468                                 gettext_noop ("# bytes received from other peers"),
5469                                 msize,
5470                                 GNUNET_NO);
5471       n->distance = distance;
5472       n->peer_timeout =
5473         GNUNET_TIME_relative_to_absolute
5474         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5475       GNUNET_SCHEDULER_cancel (n->timeout_task);
5476       n->timeout_task =
5477         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5478                                       &neighbour_timeout_task, n);
5479       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5480         {
5481           /* dropping message due to frequent inbound volume violations! */
5482           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5483                       GNUNET_ERROR_TYPE_BULK,
5484                       _
5485                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5486                       n->in_tracker.available_bytes_per_s__,
5487                       n->quota_violation_count);
5488           GNUNET_STATISTICS_update (stats,
5489                                     gettext_noop ("# bandwidth quota violations by other peers"),
5490                                     1,
5491                                     GNUNET_NO);
5492           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5493         }
5494     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5495         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5496       {
5497         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5498         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5499         /* Force ressource and quality update */
5500         if (value == 4)
5501           {
5502             ats->stat.modified_resources = GNUNET_YES;
5503             ats->stat.modified_quality = GNUNET_YES;
5504           }
5505         /* Force cost update */
5506         if (value == 3)
5507           ats->stat.modified_resources = GNUNET_YES;
5508         /* Force quality update */
5509         if (value == 2)
5510           ats->stat.modified_quality = GNUNET_YES;
5511         /* Force full rebuild */
5512         if (value == 1)
5513           ats->stat.recreate_problem = GNUNET_YES;
5514       }
5515     
5516 #if DEBUG_PING_PONG
5517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5518                 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5519                 ntohs (message->type),
5520                 ntohs (message->size),
5521                 GNUNET_i2s (peer));
5522 #endif
5523       switch (ntohs (message->type))
5524         {
5525         case GNUNET_MESSAGE_TYPE_HELLO:
5526           GNUNET_STATISTICS_update (stats,
5527                                     gettext_noop ("# HELLO messages received from other peers"),
5528                                     1,
5529                                     GNUNET_NO);
5530           process_hello (plugin, message);
5531           break;
5532         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5533           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5534           break;
5535         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5536           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5537           break;
5538         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5539           break;
5540         default:
5541           handle_payload_message (message, n);
5542           break;
5543         }
5544     }
5545   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5546   if (ret.rel_value > 0)
5547     {
5548 #if DEBUG_TRANSPORT 
5549       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5550                   "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5551                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5552                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5553                   (unsigned long long) ret.rel_value);
5554 #endif
5555       GNUNET_STATISTICS_update (stats,
5556                                 gettext_noop ("# ms throttling suggested"),
5557                                 (int64_t) ret.rel_value,
5558                                 GNUNET_NO);
5559     }
5560   return ret;
5561 }
5562
5563 /**
5564  * Handle START-message.  This is the first message sent to us
5565  * by any client which causes us to add it to our list.
5566  *
5567  * @param cls closure (always NULL)
5568  * @param client identification of the client
5569  * @param message the actual message
5570  */
5571 static void
5572 handle_start (void *cls,
5573               struct GNUNET_SERVER_Client *client,
5574               const struct GNUNET_MessageHeader *message)
5575 {
5576   const struct StartMessage *start;
5577   struct TransportClient *c;
5578   struct ConnectInfoMessage * cim;
5579   struct NeighbourList *n;
5580   uint32_t ats_count;
5581   size_t size;
5582
5583   start = (const struct StartMessage*) message;
5584 #if DEBUG_TRANSPORT
5585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5586               "Received `%s' request from client\n", "START");
5587 #endif
5588   c = clients;
5589   while (c != NULL)
5590     {
5591       if (c->client == client)
5592         {
5593           /* client already on our list! */
5594           GNUNET_break (0);
5595           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5596           return;
5597         }
5598       c = c->next;
5599     }
5600   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5601        (0 != memcmp (&start->self,
5602                      &my_identity,
5603                      sizeof (struct GNUNET_PeerIdentity))) )
5604     {
5605       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5606                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5607                   GNUNET_i2s (&start->self));
5608       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5609       return;
5610     }
5611   c = GNUNET_malloc (sizeof (struct TransportClient));
5612   c->next = clients;
5613   clients = c;
5614   c->client = client;
5615   if (our_hello != NULL)
5616   {
5617 #if DEBUG_TRANSPORT
5618       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5619                   "Sending our own `%s' to new client\n", "HELLO");
5620 #endif
5621       transmit_to_client (c,
5622                           (const struct GNUNET_MessageHeader *) our_hello,
5623                           GNUNET_NO);
5624       /* tell new client about all existing connections */
5625       ats_count = 2;
5626       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5627       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5628       {
5629           GNUNET_break(0);
5630       }
5631       cim = GNUNET_malloc (size);
5632       cim->header.size = htons (size);
5633       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5634       cim->ats_count = htonl(ats_count);
5635       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5636       (&(cim->ats))[2].value = htonl (0);
5637       n = neighbours;
5638       while (n != NULL)
5639           {
5640                   if (GNUNET_YES == n->received_pong)
5641                   {
5642                           (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5643                           (&(cim->ats))[0].value = htonl (n->distance);
5644                           (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5645                           (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5646                           cim->id = n->id;
5647                           transmit_to_client (c, &cim->header, GNUNET_NO);
5648                   }
5649             n = n->next;
5650       }
5651       GNUNET_free (cim);
5652   }
5653   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5654 }
5655
5656
5657 /**
5658  * Handle HELLO-message.
5659  *
5660  * @param cls closure (always NULL)
5661  * @param client identification of the client
5662  * @param message the actual message
5663  */
5664 static void
5665 handle_hello (void *cls,
5666               struct GNUNET_SERVER_Client *client,
5667               const struct GNUNET_MessageHeader *message)
5668 {
5669   int ret;
5670
5671   GNUNET_STATISTICS_update (stats,
5672                             gettext_noop ("# HELLOs received from clients"),
5673                             1,
5674                             GNUNET_NO);
5675   ret = process_hello (NULL, message);
5676   GNUNET_SERVER_receive_done (client, ret);
5677 }
5678
5679
5680 /**
5681  * Closure for 'transmit_client_message'; followed by
5682  * 'msize' bytes of the actual message.
5683  */
5684 struct TransmitClientMessageContext
5685 {
5686   /**
5687    * Client on whom's behalf we are sending.
5688    */
5689   struct GNUNET_SERVER_Client *client;
5690
5691   /**
5692    * Timeout for the transmission.
5693    */
5694   struct GNUNET_TIME_Absolute timeout;
5695
5696   /**
5697    * Message priority.
5698    */
5699   uint32_t priority;
5700
5701   /**
5702    * Size of the message in bytes.
5703    */
5704   uint16_t msize;
5705 };
5706
5707
5708 /**
5709  * Schedule transmission of a message we got from a client to a peer.
5710  *
5711  * @param cls the 'struct TransmitClientMessageContext*'
5712  * @param n destination, or NULL on error (in that case, drop the message)
5713  */
5714 static void
5715 transmit_client_message (void *cls,
5716                          struct NeighbourList *n)
5717 {
5718   struct TransmitClientMessageContext *tcmc = cls;
5719   struct TransportClient *tc;
5720
5721   tc = clients;
5722   while ((tc != NULL) && (tc->client != tcmc->client))
5723     tc = tc->next;
5724
5725   if (n != NULL)
5726     {
5727       transmit_to_peer (tc, NULL, tcmc->priority,
5728                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5729                         (char *)&tcmc[1],
5730                         tcmc->msize, GNUNET_NO, n);
5731     }
5732   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5733   GNUNET_SERVER_client_drop (tcmc->client);
5734   GNUNET_free (tcmc);
5735 }
5736
5737
5738 /**
5739  * Handle SEND-message.
5740  *
5741  * @param cls closure (always NULL)
5742  * @param client identification of the client
5743  * @param message the actual message
5744  */
5745 static void
5746 handle_send (void *cls,
5747              struct GNUNET_SERVER_Client *client,
5748              const struct GNUNET_MessageHeader *message)
5749 {
5750   const struct OutboundMessage *obm;
5751   const struct GNUNET_MessageHeader *obmm;
5752   struct TransmitClientMessageContext *tcmc;
5753   uint16_t size;
5754   uint16_t msize;
5755
5756   size = ntohs (message->size);
5757   if (size <
5758       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5759     {
5760       GNUNET_break (0);
5761       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5762       return;
5763     }
5764   GNUNET_STATISTICS_update (stats,
5765                             gettext_noop ("# payload received for other peers"),
5766                             size,
5767                             GNUNET_NO);
5768   obm = (const struct OutboundMessage *) message;
5769   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5770   msize = size - sizeof (struct OutboundMessage);
5771 #if DEBUG_TRANSPORT
5772   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5773               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5774               "SEND", GNUNET_i2s (&obm->peer),
5775               ntohs (obmm->type),
5776               msize);
5777 #endif
5778   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5779   tcmc->client = client;
5780   tcmc->priority = ntohl (obm->priority);
5781   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5782   tcmc->msize = msize;
5783   /* FIXME: this memcpy can be up to 7% of our total runtime */
5784   memcpy (&tcmc[1], obmm, msize);
5785   GNUNET_SERVER_client_keep (client);
5786   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5787                               &transmit_client_message,
5788                               tcmc);
5789 }
5790
5791
5792 /**
5793  * Handle request connect message
5794  *
5795  * @param cls closure (always NULL)
5796  * @param client identification of the client
5797  * @param message the actual message
5798  */
5799 static void
5800 handle_request_connect (void *cls,
5801                         struct GNUNET_SERVER_Client *client,
5802                         const struct GNUNET_MessageHeader *message)
5803 {
5804   const struct TransportRequestConnectMessage *trcm =
5805     (const struct TransportRequestConnectMessage *) message;
5806
5807   GNUNET_STATISTICS_update (stats,
5808                             gettext_noop ("# REQUEST CONNECT messages received"),
5809                             1,
5810                             GNUNET_NO);
5811 #if DEBUG_TRANSPORT
5812   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
5813              "Received a request connect message for peer `%s'\n", 
5814              GNUNET_i2s(&trcm->peer));
5815 #endif
5816   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5817                               NULL, NULL);
5818   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5819 }
5820
5821
5822 /**
5823  * Handle SET_QUOTA-message.
5824  *
5825  * @param cls closure (always NULL)
5826  * @param client identification of the client
5827  * @param message the actual message
5828  */
5829 static void
5830 handle_set_quota (void *cls,
5831                   struct GNUNET_SERVER_Client *client,
5832                   const struct GNUNET_MessageHeader *message)
5833 {
5834   const struct QuotaSetMessage *qsm =
5835     (const struct QuotaSetMessage *) message;
5836   struct NeighbourList *n;
5837
5838   GNUNET_STATISTICS_update (stats,
5839                             gettext_noop ("# SET QUOTA messages received"),
5840                             1,
5841                             GNUNET_NO);
5842   n = find_neighbour (&qsm->peer);
5843   if (n == NULL)
5844     {
5845       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5846       GNUNET_STATISTICS_update (stats,
5847                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5848                                 1,
5849                                 GNUNET_NO);
5850       return;
5851     }
5852 #if DEBUG_TRANSPORT 
5853   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5854               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5855               "SET_QUOTA",
5856               (unsigned int) ntohl (qsm->quota.value__),
5857               (unsigned int) n->in_tracker.available_bytes_per_s__,
5858               GNUNET_i2s (&qsm->peer));
5859 #endif
5860   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5861                                          qsm->quota);
5862   if (0 == ntohl (qsm->quota.value__))
5863     {
5864 #if DEBUG_TRANSPORT
5865       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5866                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5867                 "SET_QUOTA");
5868 #endif
5869       GNUNET_STATISTICS_update (stats,
5870                                 gettext_noop ("# disconnects due to quota of 0"),
5871                                 1,
5872                                 GNUNET_NO);
5873       disconnect_neighbour (n, GNUNET_NO);
5874     }
5875   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5876 }
5877
5878
5879 /**
5880  * Take the given address and append it to the set of results sent back to
5881  * the client.
5882  *
5883  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5884  * @param address the resolved name, NULL to indicate the last response
5885  */
5886 static void
5887 transmit_address_to_client (void *cls, const char *address)
5888 {
5889   struct GNUNET_SERVER_TransmitContext *tc = cls;
5890   size_t slen;
5891
5892   if (NULL != address)
5893     {
5894       slen = strlen (address) + 1;
5895       GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5896                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5897     }
5898   else
5899     {
5900       GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5901     }
5902 }
5903
5904
5905 /**
5906  * Handle AddressLookup-message.
5907  *
5908  * @param cls closure (always NULL)
5909  * @param client identification of the client
5910  * @param message the actual message
5911  */
5912 static void
5913 handle_address_lookup (void *cls,
5914                        struct GNUNET_SERVER_Client *client,
5915                        const struct GNUNET_MessageHeader *message)
5916 {
5917   const struct AddressLookupMessage *alum;
5918   struct TransportPlugin *lsPlugin;
5919   const char *nameTransport;
5920   const char *address;
5921   uint16_t size;
5922   struct GNUNET_SERVER_TransmitContext *tc;
5923   struct GNUNET_TIME_Absolute timeout;
5924   struct GNUNET_TIME_Relative rtimeout;
5925   int32_t numeric;
5926
5927   size = ntohs (message->size);
5928   if (size < sizeof (struct AddressLookupMessage))
5929     {
5930       GNUNET_break_op (0);
5931       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5932       return;
5933     }
5934   alum = (const struct AddressLookupMessage *) message;
5935   uint32_t addressLen = ntohl (alum->addrlen);
5936   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5937     {
5938       GNUNET_break_op (0);
5939       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5940       return;
5941     }
5942   address = (const char *) &alum[1];
5943   nameTransport = (const char *) &address[addressLen];
5944   if (nameTransport
5945       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5946     {
5947       GNUNET_break_op (0);
5948       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5949       return;
5950     }
5951   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5952   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5953   numeric = ntohl (alum->numeric_only);
5954   lsPlugin = find_transport (nameTransport);
5955   if (NULL == lsPlugin)
5956     {
5957       tc = GNUNET_SERVER_transmit_context_create (client);
5958       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5959                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5960       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5961       return;
5962     }
5963   GNUNET_SERVER_disable_receive_done_warning (client);
5964   tc = GNUNET_SERVER_transmit_context_create (client);
5965   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5966                                          nameTransport,
5967                                          address, addressLen,
5968                                          numeric,
5969                                          rtimeout,
5970                                          &transmit_address_to_client, tc);
5971 }
5972
5973
5974 /**
5975  * Setup the environment for this plugin.
5976  */
5977 static void
5978 create_environment (struct TransportPlugin *plug)
5979 {
5980   plug->env.cfg = cfg;
5981   plug->env.my_identity = &my_identity;
5982   plug->env.our_hello = &our_hello;
5983   plug->env.cls = plug;
5984   plug->env.receive = &plugin_env_receive;
5985   plug->env.notify_address = &plugin_env_notify_address;
5986   plug->env.session_end = &plugin_env_session_end;
5987   plug->env.max_connections = max_connect_per_transport;
5988   plug->env.stats = stats;
5989 }
5990
5991
5992 /**
5993  * Start the specified transport (load the plugin).
5994  */
5995 static void
5996 start_transport (struct GNUNET_SERVER_Handle *server,
5997                  const char *name)
5998 {
5999   struct TransportPlugin *plug;
6000   char *libname;
6001
6002   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6003               _("Loading `%s' transport plugin\n"), name);
6004   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
6005   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
6006   create_environment (plug);
6007   plug->short_name = GNUNET_strdup (name);
6008   plug->lib_name = libname;
6009   plug->next = plugins;
6010   plugins = plug;
6011   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
6012   if (plug->api == NULL)
6013     {
6014       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6015                   _("Failed to load transport plugin for `%s'\n"), name);
6016       GNUNET_free (plug->short_name);
6017       plugins = plug->next;
6018       GNUNET_free (libname);
6019       GNUNET_free (plug);
6020     }
6021 }
6022
6023
6024 /**
6025  * Called whenever a client is disconnected.  Frees our
6026  * resources associated with that client.
6027  *
6028  * @param cls closure
6029  * @param client identification of the client
6030  */
6031 static void
6032 client_disconnect_notification (void *cls,
6033                                 struct GNUNET_SERVER_Client *client)
6034 {
6035   struct TransportClient *pos;
6036   struct TransportClient *prev;
6037   struct ClientMessageQueueEntry *mqe;
6038   struct Blacklisters *bl;
6039   struct BlacklistCheck *bc;
6040
6041   if (client == NULL)
6042     return;
6043 #if DEBUG_TRANSPORT
6044   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
6045               "Client disconnected, cleaning up.\n");
6046 #endif
6047   /* clean up blacklister */
6048   bl = bl_head;
6049   while (bl != NULL)
6050     {
6051       if (bl->client == client)
6052         {
6053           bc = bc_head;
6054           while (bc != NULL)
6055             {
6056               if (bc->bl_pos == bl)
6057                 {
6058                   bc->bl_pos = bl->next;
6059                   if (bc->th != NULL)
6060                     {
6061                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6062                       bc->th = NULL;
6063                     }
6064                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6065                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6066                                                          bc);
6067                   break;
6068                 }
6069               bc = bc->next;
6070             }
6071           GNUNET_CONTAINER_DLL_remove (bl_head,
6072                                        bl_tail,
6073                                        bl);
6074           GNUNET_SERVER_client_drop (bl->client);
6075           GNUNET_free (bl);
6076           break;
6077         }
6078       bl = bl->next;
6079     }
6080   /* clean up 'normal' clients */
6081   prev = NULL;
6082   pos = clients;
6083   while ((pos != NULL) && (pos->client != client))
6084     {
6085       prev = pos;
6086       pos = pos->next;
6087     }
6088   if (pos == NULL)
6089     return;
6090   while (NULL != (mqe = pos->message_queue_head))
6091     {
6092       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6093                                    pos->message_queue_tail,
6094                                    mqe);
6095       pos->message_count--;
6096       GNUNET_free (mqe);
6097     }
6098   if (prev == NULL)
6099     clients = pos->next;
6100   else
6101     prev->next = pos->next;
6102   if (GNUNET_YES == pos->tcs_pending)
6103     {
6104       pos->client = NULL;
6105       return;
6106     }
6107   if (pos->th != NULL)
6108     {
6109       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6110       pos->th = NULL;
6111     }
6112   GNUNET_break (0 == pos->message_count);
6113   GNUNET_free (pos);
6114 }
6115
6116
6117 /**
6118  * Function called when the service shuts down.  Unloads our plugins
6119  * and cancels pending validations.
6120  *
6121  * @param cls closure, unused
6122  * @param tc task context (unused)
6123  */
6124 static void
6125 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6126 {
6127   struct TransportPlugin *plug;
6128   struct OwnAddressList *al;
6129   struct CheckHelloValidatedContext *chvc;
6130
6131   shutdown_in_progress = GNUNET_YES;
6132   while (neighbours != NULL)
6133     {
6134 #if DEBUG_TRANSPORT
6135       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6136                   "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6137                   "SHUTDOWN_TASK");
6138 #endif
6139       disconnect_neighbour (neighbours, GNUNET_NO);
6140     }
6141 #if DEBUG_TRANSPORT
6142   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6143               "Transport service is unloading plugins...\n");
6144 #endif
6145   while (NULL != (plug = plugins))
6146     {
6147       plugins = plug->next;
6148       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6149         {
6150           GNUNET_SCHEDULER_cancel (plug->address_update_task);
6151           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6152         }
6153       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6154       GNUNET_free (plug->lib_name);
6155       GNUNET_free (plug->short_name);
6156       while (NULL != (al = plug->addresses))
6157         {
6158           plug->addresses = al->next;
6159           GNUNET_free (al);
6160         }
6161       GNUNET_free (plug);
6162     }
6163   if (my_private_key != NULL)
6164     GNUNET_CRYPTO_rsa_key_free (my_private_key);
6165   GNUNET_free_non_null (our_hello);
6166
6167   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6168                                          &abort_validation,
6169                                          NULL);
6170   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6171   validation_map = NULL;
6172
6173   ats_shutdown(ats);
6174
6175   /* free 'chvc' data structure */
6176   while (NULL != (chvc = chvc_head))
6177     {
6178       chvc_head = chvc->next;
6179       if (chvc->piter != NULL)
6180         {
6181           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6182           GNUNET_STATISTICS_update (stats,
6183                                     gettext_noop ("# outstanding peerinfo iterate requests"),
6184                                     -1,
6185                                     GNUNET_NO);
6186           chvc->ve_count --;
6187         }
6188       else
6189           GNUNET_break (0);
6190       GNUNET_assert (chvc->ve_count == 0);
6191       GNUNET_free (chvc);
6192     }
6193   chvc_tail = NULL;
6194
6195   if (stats != NULL)
6196     {
6197       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6198       stats = NULL;
6199     }
6200   if (peerinfo != NULL)
6201     {
6202       GNUNET_PEERINFO_disconnect (peerinfo);
6203       peerinfo = NULL;
6204     }
6205   /* Can we assume those are gone by now, or do we need to clean up
6206      explicitly!? */
6207   GNUNET_break (bl_head == NULL);
6208   GNUNET_break (bc_head == NULL);
6209 }
6210
6211 #if HAVE_LIBGLPK
6212 static int ats_evaluate_results (int result, int solution, char * problem)
6213 {
6214         int cont = GNUNET_NO;
6215 #if DEBUG_ATS || VERBOSE_ATS
6216         int error_kind = GNUNET_ERROR_TYPE_DEBUG;
6217 #endif
6218 #if VERBOSE_ATS
6219         error_kind = GNUNET_ERROR_TYPE_ERROR;
6220 #endif
6221
6222         switch (result) {
6223         case GNUNET_SYSERR : /* GNUNET problem, not GLPK related */
6224 #if DEBUG_ATS || VERBOSE_ATS
6225                 GNUNET_log (error_kind, "%s , GLPK solving not executed\n", problem);
6226 #endif
6227                 break;
6228         case GLP_ESTOP  :    /* search terminated by application */
6229 #if DEBUG_ATS || VERBOSE_ATS
6230                 GNUNET_log (error_kind, "%s , Search terminated by application\n", problem);
6231 #endif
6232                 break;
6233         case GLP_EITLIM :    /* iteration limit exceeded */
6234 #if DEBUG_ATS || VERBOSE_ATS
6235                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Iteration limit exceeded\n", problem);
6236 #endif
6237                 break;
6238         case GLP_ETMLIM :    /* time limit exceeded */
6239 #if DEBUG_ATS || VERBOSE_ATS
6240                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Time limit exceeded\n", problem);
6241 #endif
6242         break;
6243         case GLP_ENOPFS :    /* no primal feasible solution */
6244         case GLP_ENODFS :    /* no dual feasible solution */
6245 #if DEBUG_ATS || VERBOSE_ATS
6246                 GNUNET_log (error_kind, "%s No feasible solution\n", problem);
6247 #endif
6248         break;
6249
6250         case GLP_EBADB  :    /* invalid basis */
6251         case GLP_ESING  :    /* singular matrix */
6252         case GLP_ECOND  :    /* ill-conditioned matrix */
6253         case GLP_EBOUND :    /* invalid bounds */
6254         case GLP_EFAIL  :    /* solver failed */
6255         case GLP_EOBJLL :    /* objective lower limit reached */
6256         case GLP_EOBJUL :    /* objective upper limit reached */
6257         case GLP_EROOT  :    /* root LP optimum not provided */
6258 #if DEBUG_ATS || VERBOSE_ATS
6259                 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
6260 #endif
6261         break;
6262
6263         case 0:
6264 #if DEBUG_ATS || VERBOSE_ATS
6265                         GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
6266 #endif
6267         break;
6268         }
6269
6270         switch (solution) {
6271                 case GLP_UNDEF:
6272 #if DEBUG_ATS || VERBOSE_ATS
6273                         GNUNET_log (error_kind, "%s solution is undefined\n", problem);
6274 #endif
6275                         break;
6276                 case GLP_OPT:
6277 #if DEBUG_ATS || VERBOSE_ATS
6278                         GNUNET_log (error_kind, "%s solution is optimal\n", problem);
6279 #endif
6280                         cont=GNUNET_YES;
6281                         break;
6282                 case GLP_FEAS:
6283 #if DEBUG_ATS || VERBOSE_ATS
6284                         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"));
6285 #endif
6286                         cont=GNUNET_YES;
6287                         break;
6288                 case GLP_NOFEAS:
6289 #if DEBUG_ATS || VERBOSE_ATS
6290                         GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem,  (0==strcmp(problem,"LP")?"":"integer "));
6291 #endif
6292                         break;
6293                 case GLP_INFEAS:
6294 #if DEBUG_ATS || VERBOSE_ATS
6295                         GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
6296 #endif
6297                         break;
6298                 case GLP_UNBND:
6299 #if DEBUG_ATS || VERBOSE_ATS
6300                         GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
6301 #endif
6302                 default:
6303                         break;
6304         }
6305 return cont;
6306 }
6307
6308 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)
6309 {
6310         int result = GNUNET_SYSERR;
6311         int lp_solution = GNUNET_SYSERR;
6312         int mlp_solution = GNUNET_SYSERR;
6313
6314         // Solving simplex
6315         glp_smcp opt_lp;
6316         glp_init_smcp(&opt_lp);
6317 #if VERBOSE_ATS
6318         opt_lp.msg_lev = GLP_MSG_ALL;
6319 #else
6320         opt_lp.msg_lev = GLP_MSG_OFF;
6321 #endif
6322
6323         // setting iteration limit
6324         opt_lp.it_lim = max_it;
6325         // maximum duration
6326         opt_lp.tm_lim = max_dur;
6327
6328         if (ats->stat.recreate_problem == GNUNET_YES)
6329                 opt_lp.presolve = GLP_ON;
6330         result = glp_simplex(ats->prob, &opt_lp);
6331         lp_solution =  glp_get_status (ats->prob);
6332
6333         if ((result == GLP_ETMLIM) || (result == GLP_EITLIM))
6334         {
6335                 ats->stat.valid = GNUNET_NO;
6336                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS exceeded time or iteration limit!\n");
6337                 return;
6338         }
6339
6340         if (ats_evaluate_results(result, lp_solution, "LP") == GNUNET_YES)
6341         {
6342                         stat->valid = GNUNET_YES;
6343         }
6344         else
6345         {
6346                 ats->stat.simplex_rerun_required = GNUNET_YES;
6347                 opt_lp.presolve = GLP_ON;
6348                 result = glp_simplex(ats->prob, &opt_lp);
6349                 lp_solution =  glp_get_status (ats->prob);
6350
6351                 // TODO: Remove if this does not appear until release
6352                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "EXECUTED SIMPLEX WITH PRESOLVER! %i \n", lp_solution);
6353
6354                 if (ats_evaluate_results(result, lp_solution, "LP") != GNUNET_YES)
6355                 {
6356                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "After execution simplex with presolver: STILL INVALID!\n");
6357                         char * filename;
6358                         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);
6359                         glp_write_lp (ats->prob, NULL, filename);
6360                         GNUNET_free (filename);
6361                         stat->valid = GNUNET_NO;
6362                         ats->stat.recreate_problem = GNUNET_YES;
6363                         return;
6364                 }
6365                 stat->valid = GNUNET_YES;
6366         }
6367
6368         // Solving mlp
6369         glp_iocp opt_mlp;
6370         glp_init_iocp(&opt_mlp);
6371         // maximum duration
6372         opt_mlp.tm_lim = max_dur;
6373         // output level
6374 #if VERBOSE_ATS
6375         opt_mlp.msg_lev = GLP_MSG_ALL;
6376 #else
6377         opt_mlp.msg_lev = GLP_MSG_OFF;
6378 #endif
6379
6380         result = glp_intopt (ats->prob, &opt_mlp);
6381         mlp_solution =  glp_mip_status (ats->prob);
6382         stat->solution = mlp_solution;
6383
6384         if (ats_evaluate_results(result, mlp_solution, "MLP") == GNUNET_YES)
6385         {
6386                 stat->valid = GNUNET_YES;
6387         }
6388         else
6389         {
6390                 // TODO: Remove if this does not appear until release
6391                 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);
6392                 stat->valid = GNUNET_NO;
6393         }
6394
6395 /*
6396         int check;
6397         int error = GNUNET_NO;
6398         double bw;
6399         struct ATS_mechanism *t = NULL;
6400         for (c=1; c<= (c_peers); c++ )
6401         {
6402                 check = GNUNET_NO;
6403                 t = peers[c].m_head;
6404                 while (t!=NULL)
6405                 {
6406                         bw = glp_get_col_prim(prob, t->col_index);
6407                         if (bw > 1.0)
6408                         {
6409 #if VERBOSE_ATS
6410                                 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);
6411 #endif
6412                                 if (check ==GNUNET_YES)
6413                                 {
6414                                         glp_write_sol(prob, "invalid_solution.mlp");
6415                                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6416                                         GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6417                                         error = GNUNET_YES;
6418                                 }
6419                                 if (check ==GNUNET_NO)
6420                                         check = GNUNET_YES;
6421                         }
6422                         t = t->next;
6423                 }
6424         }*/
6425
6426 #if VERBOSE_ATS
6427         if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
6428         {
6429         int c;
6430         for (c=1; c<= available_quality_metrics; c++ )
6431         {
6432                 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));
6433         }
6434         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));
6435         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));
6436         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));
6437         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value:  %f\n", glp_mip_obj_val(ats->prob));
6438         }
6439 #endif
6440 }
6441
6442 static void ats_delete_problem ()
6443 {
6444 #if DEBUG_ATS
6445         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting problem\n");
6446 #endif
6447         int c;
6448
6449         for (c=0; c< (ats->stat).c_mechs; c++)
6450                 GNUNET_free_non_null (ats->mechanisms[c].rc);
6451
6452
6453         if (ats->mechanisms!=NULL)
6454         {
6455                 GNUNET_free(ats->mechanisms);
6456                 ats->mechanisms = NULL;
6457         }
6458
6459         if (ats->peers!=NULL)
6460         {
6461                 GNUNET_free(ats->peers);
6462                 ats->peers = NULL;
6463         }
6464
6465         if (ats->prob != NULL)
6466         {
6467                 glp_delete_prob(ats->prob);
6468                 ats->prob = NULL;
6469         }
6470
6471         ats->stat.begin_cr = GNUNET_SYSERR;
6472         ats->stat.begin_qm = GNUNET_SYSERR;
6473         ats->stat.c_mechs = 0;
6474         ats->stat.c_peers = 0;
6475         ats->stat.end_cr = GNUNET_SYSERR;
6476         ats->stat.end_qm = GNUNET_SYSERR;
6477         ats->stat.solution = GNUNET_SYSERR;
6478         ats->stat.valid = GNUNET_SYSERR;
6479 }
6480
6481
6482 static void ats_update_problem_qm ()
6483 {
6484         int array_index;
6485         int row_index;
6486         int c, c2;
6487         int c_q_metrics = available_quality_metrics;
6488
6489         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6490         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6491 #if DEBUG_ATS
6492                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6493 #endif
6494         row_index = ats->stat.begin_qm;
6495
6496         for (c=1; c <= c_q_metrics; c++)
6497         {
6498                 array_index = 1;
6499                 double value = 1;
6500 #if VERBOSE_ATS
6501                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6502 #endif
6503
6504                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6505                 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6506                 {
6507                         ja[array_index] = c2;
6508
6509                         GNUNET_assert (ats->mechanisms[c2].addr != NULL);
6510                         GNUNET_assert (ats->mechanisms[c2].peer != NULL);
6511
6512                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6513                         {
6514                                 double v0 = 0, v1 = 0, v2 = 0;
6515
6516                                 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6517                                 if (v1 < 1) v0 = 0.1;
6518                                 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6519                                 if (v1 < 1) v0 = 0.1;
6520                                 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6521                                 if (v1 < 1) v0 = 0.1;
6522                                 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6523                                 //value = 1;
6524                         }
6525                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6526                         {
6527                                 double v0 = 0, v1 = 0, v2 = 0;
6528                                 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6529                                 if (v0 < 1) v0 = 1;
6530                                 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6531                                 if (v1 < 1) v1 = 1;
6532                                 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6533                                 if (v2 < 1) v2 = 1;
6534                                 value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
6535                                 if (value >= 1)
6536                                         value =  (double) 10 / value;
6537                                 else
6538                                         value = 10;
6539                         }
6540                         ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6541 #if VERBOSE_ATS
6542                         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]);
6543 #endif
6544                         array_index++;
6545                 }
6546                 ja[array_index] = ats->stat.col_qm + c - 1;
6547                 ar[array_index] = -1;
6548
6549 #if VERBOSE_ATS
6550                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6551 #endif
6552                 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6553
6554                 array_index = 1;
6555                 row_index++;
6556         }
6557
6558         GNUNET_free_non_null (ja);
6559         GNUNET_free_non_null (ar);
6560 }
6561
6562
6563 static void ats_update_problem_cr ()
6564 {
6565
6566         int array_index;
6567         int row_index;
6568         int c, c2;
6569         double ct_max, ct_min;
6570
6571         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6572         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6573
6574         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6575         row_index = ats->stat.begin_cr;
6576         array_index = 1;
6577
6578         for (c=0; c<available_ressources; c++)
6579         {
6580                 ct_max = ressources[c].c_max;
6581                 ct_min = ressources[c].c_min;
6582 #if VERBOSE_ATS
6583                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6584 #endif
6585                 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6586
6587                 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6588                 {
6589                         double value = 0;
6590
6591                         GNUNET_assert (ats->mechanisms[c2].addr != NULL);
6592                         GNUNET_assert (ats->mechanisms[c2].peer != NULL);
6593
6594                         ja[array_index] = c2;
6595                         value = ats->mechanisms[c2].addr->ressources[c].c;
6596                         ar[array_index] = value;
6597 #if VERBOSE_ATS
6598                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6599 #endif
6600                         array_index++;
6601                 }
6602                 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6603
6604                 row_index ++;
6605         }
6606
6607
6608         GNUNET_free_non_null (ja);
6609         GNUNET_free_non_null (ar);
6610 }
6611
6612
6613 #if 0
6614 static void ats_update_problem_qm_TEST ()
6615 {
6616         int row_index;
6617         int c, c2;
6618
6619         int old_ja[ats->stat.c_mechs + 2];
6620         double old_ar[ats->stat.c_mechs + 2];
6621         int c_old;
6622         int changed = 0;
6623
6624         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6625         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6626 #if DEBUG_ATS
6627         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
6628 #endif
6629         if (ats->stat.begin_qm >0)
6630                 row_index = ats->stat.begin_qm;
6631         else
6632                 return;
6633
6634
6635         for (c=0; c<available_quality_metrics; c++)
6636         {
6637
6638                 c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
6639
6640                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6641
6642                 for (c2=1; c2<=c_old; c2++)
6643                 {
6644                         ja[c2] = old_ja[c2];
6645                         if ((changed < 3) && (c2>2) && (old_ar[c2] != -1))
6646                         {
6647                                 ar[c2] = old_ar[c2] + 5 - changed;
6648                                 changed ++;
6649                         }
6650                         else
6651                                 ar[c2] = old_ar[c2];
6652 #if VERBOSE_ATS
6653                         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]);
6654 #endif
6655                 }
6656                 glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
6657
6658                 row_index ++;
6659         }
6660
6661         GNUNET_free_non_null (ja);
6662         GNUNET_free_non_null (ar);
6663 }
6664 #endif //END: HAVE_LIBGLPK
6665
6666 /** solve the bandwidth distribution problem
6667  * @param max_it maximum iterations
6668  * @param max_dur maximum duration in ms
6669  * @param D     weight for diversity
6670  * @param U weight for utility
6671  * @param R weight for relativity
6672  * @param v_b_min minimal bandwidth per peer
6673  * @param v_n_min minimum number of connections
6674  * @param stat result struct
6675  * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6676  */
6677 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
6678 {
6679         ats->prob = glp_create_prob();
6680
6681         int c;
6682         int c_peers = 0;
6683         int c_mechs = 0;
6684
6685         int c_c_ressources = available_ressources;
6686         int c_q_metrics = available_quality_metrics;
6687
6688         double M = VERY_BIG_DOUBLE_VALUE;
6689         double Q[c_q_metrics+1];
6690         for (c=1; c<=c_q_metrics; c++)
6691         {
6692                 Q[c] = 1;
6693         }
6694
6695         struct NeighbourList *next = neighbours;
6696         while (next!=NULL)
6697         {
6698                 int found_addresses = GNUNET_NO;
6699                 struct ReadyList *r_next = next->plugins;
6700                 while (r_next != NULL)
6701                 {
6702                         struct ForeignAddressList * a_next = r_next->addresses;
6703                         while (a_next != NULL)
6704                         {
6705                                 c_mechs++;
6706                                 found_addresses = GNUNET_YES;
6707                                 a_next = a_next->next;
6708                         }
6709                         r_next = r_next->next;
6710                 }
6711                 if (found_addresses) c_peers++;
6712                 next = next->next;
6713         }
6714
6715         if (c_mechs==0)
6716         {
6717 #if DEBUG_ATS
6718                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6719 #endif
6720                 stat->valid = GNUNET_NO;
6721                 stat->c_peers = 0;
6722                 stat->c_mechs = 0;
6723                 return GNUNET_SYSERR;
6724         }
6725
6726         GNUNET_assert (ats->mechanisms == NULL);
6727         ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6728         GNUNET_assert (ats->peers == NULL);
6729         ats->peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6730
6731         struct ATS_mechanism * mechanisms = ats->mechanisms;
6732         struct ATS_peer * peers = ats->peers;
6733
6734         c_mechs = 1;
6735         c_peers = 1;
6736
6737         next = neighbours;
6738         while (next!=NULL)
6739         {
6740                 int found_addresses = GNUNET_NO;
6741                 struct ReadyList *r_next = next->plugins;
6742                 while (r_next != NULL)
6743                 {
6744                         struct ForeignAddressList * a_next = r_next->addresses;
6745                         while (a_next != NULL)
6746                         {
6747                                 if (found_addresses == GNUNET_NO)
6748                                 {
6749                                         peers[c_peers].peer = next->id;
6750                                         peers[c_peers].m_head = NULL;
6751                                         peers[c_peers].m_tail = NULL;
6752                                         peers[c_peers].f = 1.0 / c_mechs;
6753                                 }
6754
6755                                 mechanisms[c_mechs].addr = a_next;
6756                                 mechanisms[c_mechs].col_index = c_mechs;
6757                                 mechanisms[c_mechs].peer = &peers[c_peers];
6758                                 mechanisms[c_mechs].next = NULL;
6759                                 mechanisms[c_mechs].plugin = r_next->plugin;
6760
6761                                 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6762                                 found_addresses = GNUNET_YES;
6763                                 c_mechs++;
6764
6765                                 a_next = a_next->next;
6766                         }
6767                         r_next = r_next->next;
6768                 }
6769                 if (found_addresses == GNUNET_YES)
6770                         c_peers++;
6771                 next = next->next;
6772         }
6773         c_mechs--;
6774         c_peers--;
6775
6776         if (v_n_min > c_peers)
6777                 v_n_min = c_peers;
6778
6779 #if VERBOSE_ATS
6780         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);
6781 #endif
6782
6783         int size =  1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6784         int row_index;
6785         int array_index=1;
6786         int * ia = GNUNET_malloc (size * sizeof (int));
6787         int * ja = GNUNET_malloc (size * sizeof (int));
6788         double * ar = GNUNET_malloc(size* sizeof (double));
6789
6790         glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6791         glp_set_obj_dir(ats->prob, GLP_MAX);
6792
6793         /* adding columns */
6794         char * name;
6795         glp_add_cols(ats->prob, 2 * c_mechs);
6796         /* adding b_t cols */
6797         for (c=1; c <= c_mechs; c++)
6798         {
6799
6800                 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6801                 glp_set_col_name(ats->prob, c, name);
6802                 GNUNET_free (name);
6803                 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6804                 glp_set_col_kind(ats->prob, c, GLP_CV);
6805                 glp_set_obj_coef(ats->prob, c, 0);
6806
6807         }
6808         /* adding n_t cols */
6809         for (c=c_mechs+1; c <= 2*c_mechs; c++)
6810         {
6811                 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6812                 glp_set_col_name(ats->prob, c, name);
6813                 GNUNET_free (name);
6814                 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6815                 glp_set_col_kind(ats->prob, c, GLP_IV);
6816                 glp_set_obj_coef(ats->prob, c, 0);
6817         }
6818
6819         /* feasibility constraints */
6820         /* Constraint 1: one address per peer*/
6821         row_index = 1;
6822         glp_add_rows(ats->prob, c_peers);
6823         for (c=1; c<=c_peers; c++)
6824         {
6825 #if VERBOSE_ATS
6826                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6827 #endif
6828                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6829
6830                 struct ATS_mechanism *m = peers[c].m_head;
6831                 while (m!=NULL)
6832                 {
6833                         ia[array_index] = row_index;
6834                         ja[array_index] = (c_mechs + m->col_index);
6835                         ar[array_index] = 1;
6836 #if VERBOSE_ATS
6837                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6838 #endif
6839                         array_index++;
6840                         m = m->next;
6841                 }
6842                 row_index++;
6843         }
6844
6845         /* Constraint 2: only active mechanism gets bandwidth assigned */
6846         glp_add_rows(ats->prob, c_mechs);
6847         for (c=1; c<=c_mechs; c++)
6848         {
6849                 /* b_t - n_t * M <= 0 */
6850 #if VERBOSE_ATS
6851                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6852 #endif
6853                 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6854
6855                 ia[array_index] = row_index;
6856                 ja[array_index] = mechanisms[c].col_index;
6857                 ar[array_index] = 1;
6858 #if VERBOSE_ATS
6859                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6860 #endif
6861                 array_index++;
6862                 ia[array_index] = row_index;
6863                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6864                 ar[array_index] = -M;
6865 #if VERBOSE_ATS
6866                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6867 #endif
6868                 array_index++;
6869                 row_index ++;
6870         }
6871
6872         /* Constraint 3: minimum bandwidth*/
6873         glp_add_rows(ats->prob, c_mechs);
6874         for (c=1; c<=c_mechs; c++)
6875         {
6876                 /* b_t - n_t * b_min <= 0 */
6877 #if VERBOSE_ATS
6878                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6879 #endif
6880                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6881
6882                 ia[array_index] = row_index;
6883                 ja[array_index] = mechanisms[c].col_index;
6884                 ar[array_index] = 1;
6885 #if VERBOSE_ATS
6886                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6887 #endif
6888                 array_index++;
6889                 ia[array_index] = row_index;
6890                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6891                 ar[array_index] = -v_b_min;
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                 row_index ++;
6897         }
6898         int c2;
6899         /* Constraint 4: max ressource capacity */
6900         /* V cr: bt * ct_r <= cr_max
6901          * */
6902         glp_add_rows(ats->prob, available_ressources);
6903         double ct_max = VERY_BIG_DOUBLE_VALUE;
6904         double ct_min = 0.0;
6905
6906         stat->begin_cr = array_index;
6907
6908         for (c=0; c<available_ressources; c++)
6909         {
6910                 ct_max = ressources[c].c_max;
6911                 ct_min = ressources[c].c_min;
6912 #if VERBOSE_ATS
6913                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6914 #endif
6915                 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6916
6917                 for (c2=1; c2<=c_mechs; c2++)
6918                 {
6919                         double value = 0;
6920                         ia[array_index] = row_index;
6921                         ja[array_index] = c2;
6922                         value = mechanisms[c2].addr->ressources[c].c;
6923                         ar[array_index] = value;
6924 #if VERBOSE_ATS
6925                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6926 #endif
6927                         array_index++;
6928                 }
6929                 row_index ++;
6930         }
6931         stat->end_cr = array_index--;
6932
6933         /* Constraint 5: min number of connections*/
6934         glp_add_rows(ats->prob, 1);
6935         for (c=1; c<=c_mechs; c++)
6936         {
6937                 // b_t - n_t * b_min >= 0
6938 #if VERBOSE_ATS
6939                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6940 #endif
6941                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6942
6943                 ia[array_index] = row_index;
6944                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6945                 ar[array_index] = 1;
6946 #if VERBOSE_ATS
6947                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6948 #endif
6949                 array_index++;
6950         }
6951         row_index ++;
6952
6953         // optimisation constraints
6954
6955         // adding columns
6956
6957         // Constraint 6: optimize for diversity
6958         int col_d;
6959         col_d = glp_add_cols(ats->prob, 1);
6960         stat->col_d = col_d;
6961         //GNUNET_assert (col_d == (2*c_mechs) + 1);
6962         glp_set_col_name(ats->prob, col_d, "d");
6963         glp_set_obj_coef(ats->prob, col_d, D);
6964         glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
6965         glp_add_rows(ats->prob, 1);
6966 #if VERBOSE_ATS
6967         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6968 #endif
6969         glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6970         for (c=1; c<=c_mechs; c++)
6971         {
6972                 ia[array_index] = row_index;
6973                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6974                 ar[array_index] = 1;
6975 #if VERBOSE_ATS
6976                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6977 #endif
6978                 array_index++;
6979         }
6980         ia[array_index] = row_index;
6981         ja[array_index] = col_d;
6982         ar[array_index] = -1;
6983 #if VERBOSE_ATS
6984         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6985 #endif
6986         array_index++;
6987         row_index ++;
6988
6989
6990         // Constraint 7: optimize for quality
6991         int col_qm;
6992         col_qm = glp_add_cols(ats->prob, c_q_metrics);
6993         stat->col_qm = col_qm;
6994         //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
6995         for (c=0; c< c_q_metrics; c++)
6996         {
6997                 GNUNET_asprintf(&name, "Q_%s",qm[c].name);
6998                 glp_set_col_name(ats->prob, col_qm + c, name);
6999                 glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
7000                 GNUNET_free (name);
7001                 glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
7002         }
7003     glp_add_rows(ats->prob, available_quality_metrics);
7004         stat->begin_qm = row_index;
7005         for (c=1; c <= c_q_metrics; c++)
7006         {
7007 #if VERBOSE_ATS
7008                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
7009 #endif
7010                 double value = 1;
7011                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
7012                 for (c2=1; c2<=c_mechs; c2++)
7013                 {
7014
7015                         ia[array_index] = row_index;
7016                         ja[array_index] = c2;
7017                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
7018                         {
7019                                 double v0 = 0, v1 = 0, v2 = 0;
7020                                 v0 = mechanisms[c2].addr->quality[c-1].values[0];
7021                                 if (v1 < 1) v0 = 0.1;
7022                                 v1 = mechanisms[c2].addr->quality[c-1].values[1];
7023                                 if (v1 < 1) v0 = 0.1;
7024                                 v2 = mechanisms[c2].addr->quality[c-1].values[2];
7025                                 if (v1 < 1) v0 = 0.1;
7026                                 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
7027                                 value = 1;
7028                         }
7029                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
7030                         {
7031                                 double v0 = 0, v1 = 0, v2 = 0;
7032                                 v0 = mechanisms[c2].addr->quality[c-1].values[0];
7033                                 if (v0 < 1) v0 = 1;
7034                                 v1 = mechanisms[c2].addr->quality[c-1].values[1];
7035                                 if (v1 < 1) v1 = 1;
7036                                 v2 = mechanisms[c2].addr->quality[c-1].values[2];
7037                                 if (v2 < 1) v2 = 1;
7038                                 value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
7039                                 if (value >= 1)
7040                                         value =  (double) 10 / value;
7041                                 else
7042                                         value = 10;
7043                         }
7044                         ar[array_index] = (mechanisms[c2].peer->f) * value ;
7045 #if VERBOSE_ATS
7046                         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]);
7047 #endif
7048                         array_index++;
7049                 }
7050
7051                 ia[array_index] = row_index;
7052                 ja[array_index] = col_qm + c - 1;
7053                 ar[array_index] = -1;
7054 #if VERBOSE_ATS
7055                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7056 #endif
7057                 array_index++;
7058                 row_index++;
7059         }
7060         stat->end_qm = row_index-1;
7061
7062         // Constraint 8: optimize bandwidth utility
7063         int col_u;
7064         col_u = glp_add_cols(ats->prob, 1);
7065         stat->col_u = col_u;
7066         //GNUNET_assert (col_u == (2*c_mechs) + 2);
7067         glp_set_col_name(ats->prob, col_u, "u");
7068         glp_set_obj_coef(ats->prob, col_u, U);
7069         glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
7070         glp_add_rows(ats->prob, 1);
7071 #if VERBOSE_ATS
7072         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
7073 #endif
7074         glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
7075         for (c=1; c<=c_mechs; c++)
7076         {
7077                 ia[array_index] = row_index;
7078                 ja[array_index] = c;
7079                 ar[array_index] = mechanisms[c].peer->f;
7080 #if VERBOSE_ATS
7081                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7082 #endif
7083                 array_index++;
7084         }
7085         ia[array_index] = row_index;
7086         ja[array_index] = col_u;
7087         ar[array_index] = -1;
7088 #if VERBOSE_ATS
7089         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7090 #endif
7091
7092         array_index++;
7093         row_index ++;
7094
7095         // Constraint 9: optimize relativity
7096         int col_r;
7097         col_r = glp_add_cols(ats->prob, 1);
7098         stat->col_r = col_r;
7099         //GNUNET_assert (col_r == (2*c_mechs) + 3);
7100         glp_set_col_name(ats->prob, col_r, "r");
7101         glp_set_obj_coef(ats->prob, col_r, R);
7102         glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
7103         glp_add_rows(ats->prob, c_peers);
7104         for (c=1; c<=c_peers; c++)
7105         {
7106                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
7107
7108                 struct ATS_mechanism *m = peers[c].m_head;
7109                 while (m!=NULL)
7110                 {
7111                         ia[array_index] = row_index;
7112                         ja[array_index] = m->col_index;
7113                         ar[array_index] = 1 / mechanisms[c].peer->f;
7114 #if VERBOSE_ATS
7115                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7116 #endif
7117                         array_index++;
7118                         m = m->next;
7119                 }
7120                 ia[array_index] = row_index;
7121                 ja[array_index] = col_r;
7122                 ar[array_index] = -1;
7123 #if VERBOSE_ATS
7124                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
7125 #endif
7126                 array_index++;
7127
7128                 row_index++;
7129         }
7130
7131         /* Loading the matrix */
7132         glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
7133
7134         stat->c_mechs = c_mechs;
7135         stat->c_peers = c_peers;
7136         stat->solution = 0;
7137         stat->valid = GNUNET_YES;
7138
7139         /* clean up */
7140
7141         GNUNET_free (ja);
7142         GNUNET_free (ia);
7143         GNUNET_free (ar);
7144
7145         return GNUNET_OK;
7146
7147 }
7148
7149 void ats_notify_ats_data (
7150                 const struct GNUNET_PeerIdentity *peer,
7151                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
7152 {
7153 #if DEBUG_ATS
7154         GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
7155 #endif
7156         if (shutdown_in_progress == GNUNET_NO)
7157                 ats_calculate_bandwidth_distribution();
7158 }
7159 #endif //END: HAVE_LIBGLPK
7160
7161 static void
7162 ats_calculate_bandwidth_distribution ()
7163 {
7164 #if HAVE_LIBGLPK
7165
7166         struct GNUNET_TIME_Absolute start;
7167         struct GNUNET_TIME_Relative creation;
7168         struct GNUNET_TIME_Relative solving;
7169         char *text = "unmodified";
7170
7171         struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (ats->last, GNUNET_TIME_absolute_get());
7172         if (delta.rel_value < ats->min_delta.rel_value)
7173         {
7174 #if DEBUG_ATS
7175                 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
7176 #endif
7177                 return;
7178         }
7179
7180         if (shutdown_in_progress == GNUNET_YES)
7181         {
7182 #if DEBUG_ATS
7183                 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Transport service is shutting down\n");
7184 #endif
7185                 return;
7186         }
7187
7188 #if FIXME_WACHS
7189         int dur;
7190         if (INT_MAX < ats->max_exec_duration.rel_value)
7191                 dur = INT_MAX;
7192         else
7193                 dur = (int) ats->max_exec_duration.rel_value;
7194 #endif
7195
7196         ats->stat.simplex_rerun_required = GNUNET_NO;
7197         start = GNUNET_TIME_absolute_get();
7198         if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL) || (ats->stat.valid == GNUNET_NO))
7199         {
7200                 text = "new";
7201                 ats->stat.recreate_problem = GNUNET_YES;
7202                 ats_delete_problem ();
7203                 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
7204 #if DEBUG_ATS
7205                 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);
7206 #endif
7207         }
7208
7209         else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_resources == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
7210         {
7211                 text = "modified resources";
7212                 ats_update_problem_cr();
7213         }
7214         else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_quality == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
7215         {
7216                 text = "modified quality";
7217                 ats_update_problem_qm();
7218                 //ats_update_problem_qm_TEST ();
7219
7220         }
7221 #if DEBUG_ATS
7222         else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
7223 #endif
7224
7225         creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
7226         start = GNUNET_TIME_absolute_get();
7227
7228         ats->stat.solution = GLP_UNDEF;
7229         if (ats->stat.valid == GNUNET_YES)
7230         {
7231                 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
7232         }
7233         solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
7234
7235         if (ats->stat.valid == GNUNET_YES)
7236         {
7237                 int msg_type = GNUNET_ERROR_TYPE_DEBUG;
7238 #if DEBUG_ATS
7239                 msg_type = GNUNET_ERROR_TYPE_ERROR;
7240 #endif
7241                 GNUNET_log (msg_type, "MLP %s: creation time: %llu, execution time: %llu, %i mechanisms, simplex rerun: %s, solution %s\n",
7242                                 text, creation.rel_value, solving.rel_value,
7243                                 ats->stat.c_mechs,
7244                                 (ats->stat.simplex_rerun_required == GNUNET_NO) ? "NO" : "YES", (ats->stat.solution == 5) ? "OPTIMAL" : "INVALID");
7245                 ats->successful_executions ++;
7246                 GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
7247
7248                 if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL))
7249                         GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
7250                 else if ((ats->stat.modified_resources == GNUNET_YES) &&
7251                                 (ats->stat.modified_quality == GNUNET_NO))
7252                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
7253                 else if ((ats->stat.modified_resources == GNUNET_NO) &&
7254                                 (ats->stat.modified_quality == GNUNET_YES) &&
7255                                 (ats->stat.simplex_rerun_required == GNUNET_NO))
7256                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
7257                 else if ((ats->stat.modified_resources == GNUNET_YES) &&
7258                                 (ats->stat.modified_quality == GNUNET_YES) &&
7259                                 (ats->stat.simplex_rerun_required == GNUNET_NO))
7260                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
7261                 else if (ats->stat.simplex_rerun_required == GNUNET_NO)
7262                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
7263         }
7264         else
7265         {
7266                 if (ats->stat.c_peers != 0)
7267                 {
7268                         ats->invalid_executions ++;
7269                         GNUNET_STATISTICS_set (stats, "# ATS invalid executions", ats->invalid_executions, GNUNET_NO);
7270                 }
7271                 else
7272                 {
7273                         GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
7274                 }
7275         }
7276
7277         GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
7278         GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
7279         GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
7280         GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
7281         GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
7282
7283         if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
7284         {
7285                 char * filename;
7286                 if (ats->dump_overwrite == GNUNET_NO)
7287                 {
7288                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.mlp",
7289                         ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
7290                         glp_write_lp (ats->prob, NULL, filename);
7291                 }
7292                 else
7293                 {
7294                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",
7295                         ats->stat.c_peers, ats->stat.c_mechs );
7296                         glp_write_lp (ats->prob, NULL, filename);
7297                 }
7298                 GNUNET_free (filename);
7299         }
7300         if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
7301         {
7302                 char * filename;
7303                 if (ats->dump_overwrite == GNUNET_NO)
7304                 {
7305                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.sol",
7306                         ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
7307                         glp_print_sol (ats->prob, filename);
7308                 }
7309                 else
7310                 {
7311                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.sol",
7312                         ats->stat.c_peers, ats->stat.c_mechs);
7313                         glp_print_sol (ats->prob, filename);
7314                 }
7315                 GNUNET_free (filename);
7316         }
7317
7318         ats->last = GNUNET_TIME_absolute_get();
7319         ats->stat.recreate_problem = GNUNET_NO;
7320         ats->stat.modified_resources = GNUNET_NO;
7321         ats->stat.modified_quality = GNUNET_NO;
7322 #endif
7323 }
7324
7325 static void
7326 ats_schedule_calculation (void *cls,
7327                           const struct GNUNET_SCHEDULER_TaskContext *tc)
7328 {
7329         struct ATS_info *ats = (struct ATS_info *) cls;
7330         if (ats==NULL) return;
7331
7332         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7333         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
7334             return;
7335
7336         if (shutdown_in_progress == GNUNET_YES)
7337                 return;
7338
7339 #if DEBUG_ATS
7340         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
7341 #endif
7342
7343         ats_calculate_bandwidth_distribution (ats);
7344
7345         ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_interval,
7346                                         &ats_schedule_calculation, ats);
7347 }
7348
7349 void ats_init ()
7350 {
7351         int c = 0;
7352         unsigned long long  value;
7353         char * section;
7354
7355         ats = GNUNET_malloc(sizeof (struct ATS_info));
7356
7357         ats->min_delta = ATS_MIN_INTERVAL;
7358         ats->exec_interval = ATS_EXEC_INTERVAL;
7359         ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
7360         ats->max_iterations = ATS_MAX_ITERATIONS;
7361         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7362
7363 #if !HAVE_LIBGLPK
7364         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS not active\n");
7365         return;
7366 #endif
7367
7368         ats->D = 1.0;
7369         ats->U = 1.0;
7370         ats->R = 1.0;
7371         ats->v_b_min = 64000;
7372         ats->v_n_min = 10;
7373         ats->dump_min_peers = 1;
7374         ats->dump_min_addr = 1;
7375         ats->dump_overwrite = GNUNET_NO;
7376         ats->mechanisms = NULL;
7377         ats->peers = NULL;
7378         ats->successful_executions = 0;
7379         ats->invalid_executions = 0;
7380
7381 #if HAVE_LIBGLPK
7382         ats->prob = NULL;
7383 #endif
7384
7385         /* loading cost ressources */
7386         for (c=0; c<available_ressources; c++)
7387         {
7388                 GNUNET_asprintf(&section,"%s_UP",ressources[c].cfg_param);
7389                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7390                 {
7391                         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7392                         {
7393 #if DEBUG_ATS
7394                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7395 #endif
7396                                 ressources[c].c_max = value;
7397                         }
7398                 }
7399                 GNUNET_free (section);
7400                 GNUNET_asprintf(&section,"%s_DOWN",ressources[c].cfg_param);
7401                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7402                 {
7403                         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7404                         {
7405 #if DEBUG_ATS
7406                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7407 #endif
7408                                 ressources[c].c_min = value;
7409                         }
7410                 }
7411                 GNUNET_free (section);
7412         }
7413
7414         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
7415                 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
7416
7417         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
7418                 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
7419         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7420                 ats->dump_overwrite = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_OVERWRITE");
7421         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
7422         {
7423                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_PEERS", &value);
7424                 ats->dump_min_peers= value;
7425         }
7426         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_ADDRS"))
7427         {
7428                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_ADDRS", &value);
7429                 ats->dump_min_addr= value;
7430         }
7431         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7432         {
7433                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_OVERWRITE", &value);
7434                 ats->min_delta.rel_value = value;
7435         }
7436
7437         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7438         {
7439                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7440                 ats->min_delta.rel_value = value;
7441         }
7442
7443         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_EXEC_INTERVAL"))
7444         {
7445                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_EXEC_INTERVAL", &value);
7446                 ats->exec_interval.rel_value = value;
7447         }
7448         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7449         {
7450                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7451                 ats->min_delta.rel_value = value;
7452         }
7453
7454         ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
7455 }
7456
7457
7458 static void ats_shutdown ()
7459 {
7460 #if DEBUG_ATS
7461         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
7462 #endif
7463         if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
7464                 GNUNET_SCHEDULER_cancel(ats->ats_task);
7465         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7466
7467 #if HAVE_LIBGLPK
7468         ats_delete_problem ();
7469         glp_free_env();
7470 #endif
7471         GNUNET_free (ats);
7472 }
7473
7474
7475 void ats_notify_peer_connect (
7476                 const struct GNUNET_PeerIdentity *peer,
7477                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
7478 {
7479 #if DEBUG_ATS
7480         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
7481 #endif
7482         //update_addr_ats();
7483         ats->stat.recreate_problem = GNUNET_YES;
7484         ats_calculate_bandwidth_distribution(ats);
7485 }
7486
7487 void ats_notify_peer_disconnect (
7488                 const struct GNUNET_PeerIdentity *peer)
7489 {
7490 #if DEBUG_ATS
7491         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
7492 #endif
7493         ats->stat.recreate_problem = GNUNET_YES;
7494         ats_calculate_bandwidth_distribution (ats);
7495 }
7496
7497 struct ForeignAddressList * ats_get_preferred_address (
7498                 struct NeighbourList *n)
7499 {
7500 #if DEBUG_ATS
7501         //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
7502 #endif
7503         struct ReadyList *next = n->plugins;
7504         while (next != NULL)
7505         {
7506 #if DEBUG_ATS
7507                 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
7508 #endif
7509                 next = next->next;
7510         }
7511         return find_ready_address(n);
7512 }
7513
7514 /**
7515  * Initiate transport service.
7516  *
7517  * @param cls closure
7518  * @param server the initialized server
7519  * @param c configuration to use
7520  */
7521 static void
7522 run (void *cls,
7523      struct GNUNET_SERVER_Handle *server,
7524      const struct GNUNET_CONFIGURATION_Handle *c)
7525 {
7526   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
7527     {&handle_start, NULL,
7528      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
7529     {&handle_hello, NULL,
7530      GNUNET_MESSAGE_TYPE_HELLO, 0},
7531     {&handle_send, NULL,
7532      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
7533     {&handle_request_connect, NULL,
7534      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
7535     {&handle_set_quota, NULL,
7536      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
7537     {&handle_address_lookup, NULL,
7538      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
7539      0},
7540     {&handle_blacklist_init, NULL,
7541      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
7542     {&handle_blacklist_reply, NULL,
7543      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
7544     {NULL, NULL, 0, 0}
7545   };
7546   char *plugs;
7547   char *pos;
7548   int no_transports;
7549   unsigned long long tneigh;
7550   char *keyfile;
7551
7552   shutdown_in_progress = GNUNET_NO;
7553   cfg = c;
7554   stats = GNUNET_STATISTICS_create ("transport", cfg);
7555   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
7556   /* parse configuration */
7557   if ((GNUNET_OK !=
7558        GNUNET_CONFIGURATION_get_value_number (c,
7559                                               "TRANSPORT",
7560                                               "NEIGHBOUR_LIMIT",
7561                                               &tneigh)) ||
7562       (GNUNET_OK !=
7563        GNUNET_CONFIGURATION_get_value_filename (c,
7564                                                 "GNUNETD",
7565                                                 "HOSTKEY", &keyfile)))
7566     {
7567       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7568                   _
7569                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
7570       GNUNET_SCHEDULER_shutdown ();
7571       if (stats != NULL)
7572         {
7573           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7574           stats = NULL;
7575         }
7576       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7577       validation_map = NULL;
7578       return;
7579     }
7580
7581   max_connect_per_transport = (uint32_t) tneigh;
7582   peerinfo = GNUNET_PEERINFO_connect (cfg);
7583   if (peerinfo == NULL)
7584     {
7585       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7586                   _("Could not access PEERINFO service.  Exiting.\n"));
7587       GNUNET_SCHEDULER_shutdown ();
7588       if (stats != NULL)
7589         {
7590           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7591           stats = NULL;
7592         }
7593       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7594       validation_map = NULL;
7595       GNUNET_free (keyfile);
7596       return;
7597     }
7598   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
7599   GNUNET_free (keyfile);
7600   if (my_private_key == NULL)
7601     {
7602       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7603                   _
7604                   ("Transport service could not access hostkey.  Exiting.\n"));
7605       GNUNET_SCHEDULER_shutdown ();
7606       if (stats != NULL)
7607         {
7608           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7609           stats = NULL;
7610         }
7611       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7612       validation_map = NULL;
7613       return;
7614     }
7615   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
7616   GNUNET_CRYPTO_hash (&my_public_key,
7617                       sizeof (my_public_key), &my_identity.hashPubKey);
7618   /* setup notification */
7619   GNUNET_SERVER_disconnect_notify (server,
7620                                    &client_disconnect_notification, NULL);
7621   /* load plugins... */
7622   no_transports = 1;
7623   if (GNUNET_OK ==
7624       GNUNET_CONFIGURATION_get_value_string (c,
7625                                              "TRANSPORT", "PLUGINS", &plugs))
7626     {
7627       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7628                   _("Starting transport plugins `%s'\n"), plugs);
7629       pos = strtok (plugs, " ");
7630       while (pos != NULL)
7631         {
7632           start_transport (server, pos);
7633           no_transports = 0;
7634           pos = strtok (NULL, " ");
7635         }
7636       GNUNET_free (plugs);
7637     }
7638   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
7639                                 &shutdown_task, NULL);
7640   if (no_transports)
7641     refresh_hello ();
7642
7643   ats_init();
7644
7645 #if DEBUG_TRANSPORT
7646   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7647 #endif
7648   /* If we have a blacklist file, read from it */
7649   read_blacklist_file(cfg);
7650   /* process client requests */
7651   GNUNET_SERVER_add_handlers (server, handlers);
7652 }
7653
7654
7655 /**
7656  * The main function for the transport service.
7657  *
7658  * @param argc number of arguments from the command line
7659  * @param argv command line arguments
7660  * @return 0 ok, 1 on error
7661  */
7662 int
7663 main (int argc, char *const *argv)
7664 {
7665   a2s (NULL, NULL, 0); /* make compiler happy */
7666   return (GNUNET_OK ==
7667           GNUNET_SERVICE_run (argc,
7668                               argv,
7669                               "transport",
7670                               GNUNET_SERVICE_OPTION_NONE,
7671                               &run, NULL)) ? 0 : 1;
7672 }
7673
7674 /* end of gnunet-service-transport.c */