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