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