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