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