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