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