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