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