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