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